Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

time: date conversion does not work when cross compiling for Linux #19123

Closed
skaggmannen opened this issue Feb 16, 2017 · 7 comments
Closed

time: date conversion does not work when cross compiling for Linux #19123

skaggmannen opened this issue Feb 16, 2017 · 7 comments

Comments

@skaggmannen
Copy link

skaggmannen commented Feb 16, 2017

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.7.3 windows/amd64

What operating system and processor architecture are you using (go env)?

set GOARCH=amd64
set GOBIN=
set GOEXE=.exe
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=D:\Projects\go
set GORACE=
set GOROOT=C:\Go
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set CC=gcc
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
set CXX=g++
set CGO_ENABLED=1

What did you do?

Conversion to UTC does not seem to work as expected on different platforms. The following program does not give the expected output when compiled for Linux:

package main

import (
	"fmt"
	"time"
)

func main() {
	if now, err := time.Parse(time.RFC850, "Thursday, 16-Feb-17 14:48:58 CET"); err != nil {
		fmt.Print(err)
	} else {
		fmt.Println("now: ", now)
		fmt.Println("now (utc): ", now.UTC())
	}
}

The output when building for Windows (GOOS=windows) is this:

now:  2017-02-16 14:48:58 +0100 CET
now (utc):  2017-02-16 13:48:58 +0000 UTC

But when compiling for Linux (GOOS=linux) I get this output instead:

now:  2017-02-16 14:48:58 +0000 CET
now (utc):  2017-02-16 14:48:58 +0000 UTC

I tested the Linux binary in Ubuntu Bash for Windows, and on a Raspberry PI (built with GOARCH=arm). The result is the same on both platforms.

I've also tested it in the Golang Playground and it seems to be wrong there as well:

https://play.golang.org/p/kFvAJEx7dw

What did you expect to see?

now:  2017-02-16 14:48:58 +0100 CET
now (utc):  2017-02-16 13:48:58 +0000 UTC

What did you see instead?

now:  2017-02-16 14:48:58 +0000 CET
now (utc):  2017-02-16 14:48:58 +0000 UTC
@ianlancetaylor ianlancetaylor changed the title Date conversion does not work when cross compiling for Linux time: date conversion does not work when cross compiling for Linux Feb 16, 2017
@ianlancetaylor
Copy link
Contributor

The meaning of timezone abbreviations like "CET" are system dependent. The timezone database on your Windows system is giving it one meaning. The timezone database on your GNU/Linux system is giving it a different meaning or, rather, no meaning at all.

This is documented in the time.Parse docs.

Closing because I don't think there is anything to do here.

@skaggmannen
Copy link
Author

skaggmannen commented Feb 17, 2017

I tried with the zoneinfo.zip file distributed with Go ($GOROOT/lib/time/zoneinfo.zip), and I still get the same result.

I've modified the code a bit to check if CET can be loaded as a Location, and that seems to work. The conversion to UTC for the date still doesn't however.

New test:

package main

import (
	"fmt"
	"log"
	"syscall"
	"time"
)

func main() {
	zoneinfo, _ := syscall.Getenv("ZONEINFO")
	log.Println("zoneinfo: ", zoneinfo)

	if _, err := time.LoadLocation("CET"); err != nil {
		log.Println("failed to load 'CET': ", err)
	} else {
		log.Println("loaded 'CET' successfully!")
	}

	if now, err := time.Parse(time.RFC850, "Thursday, 16-Feb-17 14:48:58 MST"); err != nil {
		fmt.Print(err)
	} else {
		fmt.Println("now: ", now)
		fmt.Println("now (utc): ", now.UTC())
	}
}

The program gives the following output:

rs485gw-0f00b9:~$ ZONEINFO=`pwd`/zoneinfo.zip ./time-test
2017/02/17 06:04:29 zoneinfo:  /home/freall/zoneinfo.zip
2017/02/17 06:04:29 loaded 'CET' successfully!
now:  2017-02-16 14:48:58 +0000 CET
now (utc):  2017-02-16 14:48:58 +0000 UTC

@skaggmannen
Copy link
Author

If I use time.ParseInLocation instead of parse it seems to work fine:

Code:

package main

import (
	"fmt"
	"log"
	"syscall"
	"time"
)

func main() {
	zoneinfo, _ := syscall.Getenv("ZONEINFO")
	log.Println("zoneinfo: ", zoneinfo)

	local, err := time.LoadLocation("CET")
	if err != nil {
		log.Println("failed to load 'CET': ", err)
	} else {
		log.Println("loaded 'CET' successfully: ", local)
	}

	if now, err := time.ParseInLocation(time.RFC850, "Thursday, 16-Feb-17 14:48:58 CET", local); err != nil {
		fmt.Print(err)
	} else {
		fmt.Println("now: ", now)
		fmt.Println("now (utc): ", now.UTC())
	}
}

Output:

rs485gw-0f00b9:~$ ZONEINFO=`pwd`/zoneinfo.zip ./time-test
2017/02/17 06:11:53 zoneinfo:  /home/freall/zoneinfo.zip
2017/02/17 06:11:53 loaded 'CET' successfully:  CET
now:  2017-02-16 14:48:58 +0100 CET
now (utc):  2017-02-16 13:48:58 +0000 UTC

But that would mean I would have to manually get the timezone name from the time string, which is pretty much what you expect time.Parse to do for you.

@skaggmannen
Copy link
Author

Ok, this makes time.Parse seem totally broken to me when it comes to time zones. This is what I have to do to work around this issue:

package main

import (
	"fmt"
	"log"
	"syscall"
	"time"
)

func main() {
	zoneinfo, _ := syscall.Getenv("ZONEINFO")
	log.Println("zoneinfo: ", zoneinfo)

	timeString := "Thursday, 16-Feb-17 14:48:58 EST"

	if now, err := time.Parse(time.RFC850, timeString); err != nil {
		fmt.Print(err)
	} else if local, err := time.LoadLocation(now.Location().String()); err != nil {
		fmt.Print(err)
	} else if nowFixed, err := time.ParseInLocation(time.RFC850, timeString, local); err != nil {
		fmt.Print(err)
	} else {
		fmt.Println("now location: ", now.Location())
		fmt.Println("now:          ", now)
		fmt.Println("now (utc):    ", now.UTC())
		fmt.Println("now (fixed):  ", nowFixed.UTC())
	}
}

This finally gives the correct output:

rs485gw-0f00b9:~$ ZONEINFO=`pwd`/zoneinfo.zip ./time-test
2017/02/17 06:33:57 zoneinfo:  /home/freall/zoneinfo.zip
now location:  EST
now:           2017-02-16 14:48:58 +0000 EST
now (utc):     2017-02-16 14:48:58 +0000 UTC
now (fixed):   2017-02-16 19:48:58 +0000 UTC

@ianlancetaylor
Copy link
Contributor

Timezone abbreviations are basically broken by design. For example, you just used "EST", but "EST" means Eastern Standard Time in both the U.S. and Australia, although the two timezones are very different. There's really not a lot we can do to fix it. The only real solution is to avoid using timezone abbreviations. Stick to time.ParseInLocation or unambiguous numbers like -0500.

@skaggmannen
Copy link
Author

skaggmannen commented Feb 19, 2017 via email

@ianlancetaylor
Copy link
Contributor

I don't think there is a simple solution. If we try to look up the time zone in Parse, what should we do if the lookup fails? Returning an error would make it harder to do simple things like parsing the time string in e-mail messages, since e-mail messages put all kinds of junk in the timezone in practice. But not returning an error means that after parsing you can't tell whether you have the correct timezone or not.

@golang golang locked and limited conversation to collaborators Feb 20, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants