Why running Golang's time.Now() at OpenWRT always get UTC time? - go

I wrote a Golang program that runs on OpenWRT.
package main
import (
"fmt"
"time"
)
func main(){
fmt.Println(time.Now())
}
When I run this program on my Macbook, I always get the correct local time.
However, when running this program on OpenWRT, I always get UTC time.
I have set the time zone and time of OpenWRT. When I execute uci show system, I can see the right time zone. When I execute date the right local time can be display correctly.
So my question is, how do I get the correct local time using Golang's time.Now() on OpenWRT?

The root of my problem is that my OpenWRT lacks the zoneinfo package. So I run opkg update && opkg install zoneinfo-xxx first.
This is part of go/src/time/zoneinfo_unix.go:
func initLocal() {
// consult $TZ to find the time zone to use.
// no $TZ means use the system default /etc/localtime.
// $TZ="" means use UTC.
// $TZ="foo" means use /usr/share/zoneinfo/foo.
...
}
According to this file, if there is no "TZ" variable, Golang will use the time zone pointed to by /etc/localtime when calling time.Now().
Then I set time zone at /etc/config/system (option zonename 'xxxxxx') and run /etc/init.d/system restart. Finally, I can get the correct time.Now().

OpenWRT stores the time zone inside a file named /etc/TZ. If this file is missing or empty, OpenWRT assumes the local time equals UTC time. Source
how do I get the correct local time using Golang's time.Now() on
OpenWRT?
Specifying the Time Zone with TZ
The is the value you must add to or substract from the local time to get the UTC time. This offset will be positive if the local time zone is west of the Prime Meridian and negative if it is east.

Related

Understanding tz offset discrepancy on different systems

Hoping someone can see what I'm doing wrong, or misunderstanding.
I was using the time pkg in the Go Sandbox, to become familiar with how to use the timezone specific functions correctly.
Even though I already knew some of the offsets, I used the following site to double check myself : https://documentation.mersive.com/content/topics/api-timezones.htm.
In this case, when I ask for the offset for "America/New_York", I expect -14400.
However, when I ran the following on the Go Sandbox, I get -18000 instead:
https://play.golang.org/p/aU0JFHzueU1
americatz, err := time.LoadLocation("America/New_York")
if err != nil {
fmt.Println(err)
return
}
t := time.Now().In(americatz)
zone, offset := t.Zone()
fmt.Printf("%v :: %v\n", zone, offset)
I noticed that when I brought the same code over to a linux machine, it did exactly what I expected. I'm nervous, because I don't have a firm understanding why the two output's for a very common tz would be different.
I know enough that LoadLocation looks for a zipfile from the ZONEINFO env var. Otherwise it'll look in other system places like the $GOROOT/lib/time/zoneinfo.zip.
Is it really just plain and simple that the Go Server the code runs on vs the linux server have different zone info files? And if I want the exact same behavior across all systems... does this mean I need to always load in and set my own ZONEINFO variable? I feel like most people would expect -14400...
Thanks.
In the playground the time is set to "2009-11-10 23:00:00 UTC" because "This makes it easier to cache programs by giving them deterministic output." (from the 'About' box).
This can have an impact on the timezone offset due to daylight savings. The following will give the answer you are expecting:
today := time.Date(2020,10,16,0,0,0,0,americatz)
zone, offset = today.Zone()
fmt.Printf("%v :: %v\n", zone, offset)
Playground
Further detail:
Due to daylight savings the offset changes depending upon the time; for example:
time.Date(2020,10,16,0,0,0,0,americatz).Zone() will return an offest of -14400 whereas time.Date(2020,1,16,0,0,0,0,americatz).Zone() would return -18000.
It just so happens that the time that now() returns in the playground (2009-11-10) is EST (daylight savings ended Sunday, 1 November 2009, 2:00 a.m.) rather than EDT. If you run your test again in a month you will not see this difference because both times will be in EST.

Get complete UTC offset format

I need to get the UTC offset for a location. I am getting trouble with the inconsistency of the results from different values. All I need to get are values in the format +HHMM (e.g., +0100 for "Europe/Rome").
func main() {
loc, _:= time.LoadLocation("Asia/Kathmandu")
offset, others:= time.Now().In(loc).Zone()
fmt.Println(offset, others)
}
Playground
What I get:
"Asia/Kathmandu": +0545 (suitable)
"Asia/Ho_Chi_Minh": +07 (should be +0700)
"America/Phoenix": MST (should be -0700)
"Europe/Rome": CET (should be +0100)
Reference Timezone country names
The Zone() method you're using is working exactly as advertized.
Zone computes the time zone in effect at time t, returning the abbreviated name of the zone (such as "CET") and its offset in seconds east of UTC.
A better approach for you would be to use the Format method. Something like:
zone := time.Now().In(loc).Format("-0700")
Of course, be aware: Even this won't be 100% consistent, due to daylight savings time.

How to detect if the current Go process is running in a headless (non-GUI) environment?

I have a Go program which wants to install a trayicon. In case the process is headless, that is, it will not be able to create a graphical user interface, the Go program still makes sense and shall run, but obviously it shall not install the trayicon.
What is the way in Go how to detect whether the current Go process is headless?
Currently, I use the following code:
func isHeadless() bool {
_, display := os.LookupEnv("DISPLAY")
return !(runtime.GOOS == "windows" || display)
}
This code works just fine on a "normal" Windows, Linux, or Mac OS X, and I bet it will also run just fine on FreeBSD, NetBSD, Dragonfly and many others.
Still, that code obviously has a lot of problems:
It assumes that Windows is never headless (wrong, what if the process was started without a user logged in, and also, there's Windows 10 IoT Core which can be configured to headless https://learn.microsoft.com/en-us/windows/iot-core/learn-about-hardware/headlessmode)
It doesn't support Android (of which there also is a headless version for IoT).
It assumes that everything non-Windows has an X-Server and thus a DISPLAY environment variable (wrong, for example, Android)
So, what is the correct way in Go to detect whether the current process is headless / running in a headless environment?
I'm not looking for workarounds, like adding a --headless command line switch to my program. Because, I already have that anyway for users who have heads but want the program to behave as if it were headless.
In some other programming environments, such capabilities exist. For example, Java has java.awt.GraphicsEnvironment.isHeadless(), and I'm looking for a similar capability in Go.
Some people have suggested to simply try creating the UI, and catch the error. This does not work, at least not with the library that I use. I use github.com/getlantern/systray. When systray.Run() cannot create the UI, the process dies. My code to setup the system tray looks like this:
func setupSystray() { // called from main()
go func() {
systray.Run(onReady, nil)
}()
}
func onReady() {
systray.SetTitle("foo")
// ...
}
When I run this code on Linux with DISPLAY unset, the output is as following:
$ ./myapp-linux-amd64
Unable to init server: Could not connect: Connection refused
(myapp-linux-amd64:5783): Gtk-WARNING **: 19:42:37.914: cannot open display:
$ echo $?
1
It could be argued that this is a flaw in the library (and I have created a ticket on the library https://github.com/getlantern/systray/issues/71), but nonetheless some other APIs and environments provide a function isHeadless(), and I'm looking for an equivalent in Golang.
I think you might be attacking this problem from a wrong angle.
Detecting reliably that your program really sees a headless machine is, IMO, rather futile for a number of reasons.
Hence I think I'd adopt an approach usually sported in, say, working with filesystems:
Try to perform an operation.
If it fails, collect the error.
Analyze the error and act accordingly.
That is, just try to explicitly initialize the client (yours) side of whatever works with the GUI stack in your code, trap any possible error and analyze it. If it says it failed to initialize the subsystem, then just raise a relevant flag and proceed.
In the perceived absence of a library/solution for this, I've created one myself. https://github.com/christianhujer/isheadless
Example Usage:
package main
import (
. "fmt"
. "github.com/christianhujer/isheadless"
. "os"
)
func main() {
headless := IsHeadless()
Fprintf(Stderr, "%s: info: headless: %v\n", Args[0], headless)
Exit(map[bool]int{true: 0, false: 1}[headless])
}
Example runs:
$ ./isheadless ; echo $?
./isheadless: info: headless: false
1
$ DISPLAY= ./isheadless ; echo $?
./isheadless: info: headless: true
0
Well, the answer to the question precisely as it was stated
is to just look at what Java does in its isHeadless().
Here is what OpenJDK 10 does.
I cannot copy the code as it would supposedly breach its license,
but in essense, the breakdown is as follows:
Get system property "java.awt.headless"; use it, if found.
Get system property "javaplugin.version"; if it exists,
the session is not headless. Use this value.
Get system property "os.name". If it literally contains
the substring "OS X" and the system property "awt.toolkit"
equals the string "sun.awt.HToolkit", the session is not headless.
Use this value.
Check whether the system property "os.name"
equals one of "Linux", "SunOS", "FreeBSD", "NetBSD", "OpenBSD"
or "AIX", and if so, try to find an environment variable "DISPLAY";
if it's absent, the session is headless.
As you can see, in reality the check is pretty lame
and I fail to see any special treatment of Windows.
Still, this answers your question precisely.

How to convert between timezones in Go? [duplicate]

This question already has answers here:
Convert UTC to "local" time in Go
(3 answers)
Closed 7 years ago.
For example time.Now() has a timezone of UTC.
utcNow := time.Now()
fmt.Println(utcNow)
Outputs
2009-11-10 23:00:00 +0000 UTC
How do I convert this time to Japan Standard time?
It looks like you're running that in the Go playground, which is why the time is automatically set to UTC (it's also always set to November 2009 when a program is launched).
If you run time.Now() on your own machine, it should pick up the local region. Alternatively, if you want to force the time to be in a specific timezone, you can use a time.Location object along with the time.Time.In function.
l, err := time.LoadLocation("Asia/Tokyo") // Look up a location by it's IANA name.
if err != nil {
panic(err) // You can handle this gracefully.
}
fmt.Println(utcNow.In(l))
Note that it's still showing the same moment in time, but now with JST's offset.
For more information, look at the go documentation for the time package. http://golang.org/pkg/time

a simple real-time-clock driver program not getting output

I wrote a driver program which will interact with RTC and gives the time.
program is:
outb(GET_HR, CMD_REG);
hrs = inb(STAT_REG);
outb(GET_MIN, CMD_REG);
min = inb(STAT_REG);
pr_info("time: hrs:min\n", hrs, min);
Its working, but giving in format of GMT. I want my local time(GMT+5.30). I explicitly added 5:30 in the program. some times its not giving correct time. Is there any implicit function to get local time?
it is not task of the kernel to do time conversions. You should always work with UTC times in kernel and translate them in userspace to localtime.

Resources