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: Parse with 0 UTC offset different on darwin vs linux #30114

Open
briancharous opened this Issue Feb 6, 2019 · 3 comments

Comments

Projects
None yet
3 participants
@briancharous
Copy link

commented Feb 6, 2019

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

$ go version
go version go1.11.5 darwin/amd64

Does this issue reproduce with the latest release?

Yes

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

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/Cellar/go/1.11.5/libexec"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.11.5/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/7r/c69ybb_15ns25x8p292lb4wr0000gp/T/go-build884654085=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Parsing RFC3339 timestamps with 0 UTC offset specified as +00:00 or -00:00 (for example 2019-02-06T14:00:00+00:00) produces a different time.Time on Darwin vs Linux. On Darwin, the time gets parsed into a time.Time with a custom zone with offset of 0 and no name, on Linux the timestamp parses (correctly in my opinion) into a time.Time with time.UTC zone info.

The behavior is correct on Darwin if the timestamp is specified with Z instead of an offset, for example: 2019-02-06T14:00:00Z parses into a time.Time with time.UTC zone info.

package main

import (
	"fmt"
	"time"
)

func main() {
	badRFCTime := "2019-02-06T14:00:00+00:00"
	goodRFCTime := "2019-02-06T14:00:00Z"
	badParsed, err := time.Parse(time.RFC3339, badRFCTime)
	if err != nil {
		panic(err)
	}
	goodParsed, err := time.Parse(time.RFC3339, goodRFCTime)
	if err != nil {
		panic(err)
	}
	goodTz, goodOffset := goodParsed.Zone()
	badTz, badOffset := badParsed.Zone()
	fmt.Printf("good TZ: %v, good offset: %v, badTZ: %v, badOffset: %v\n", goodTz, goodOffset, badTz, badOffset)
}

On Darwin, this program prints:

good TZ: UTC, good offset: 0, badTZ: , badOffset: 0

on Linux, this program prints:

good TZ: UTC, good offset: 0, badTZ: UTC, badOffset: 0

@dmitshur dmitshur changed the title time.Parse with 0 UTC offset different on darwin vs linux time: Parse with 0 UTC offset different on darwin vs linux Feb 6, 2019

@antong

This comment has been minimized.

Copy link
Contributor

commented Feb 7, 2019

@briancharous , could it be that your Darwin machine is configured with a local time zone that is not UTC? You can find out Go's notion of the local time zone e.g., by doing fmt.Println(time.Local)

The manual says that numerical offsets only result in the local location:

When parsing a time with a zone offset like -0700, if the offset corresponds to a time zone used by the current location (Local), then Parse uses that location and zone in the returned time. Otherwise it records the time as being in a fabricated location with time fixed at the given zone offset.

So in case your local configuration is not TZ=UTC on Darwin, then your result is as documented.

Now, is this behavior the expected and the right thing to do? There is not a mapping from numerical offset to location (TZ), because there are many locations (TZ) with different time zone rules. For example, your example "2019-02-06T14:00:00+00:00" could either be UTC as you expected, or it could be London, or Reykjavik and so on. There is an important difference here in that if you say ask what time it is five months from the date, then different locations may have different answers, as UTC and Reykjavik (at the example date and currently) do not do daylight saving time, while London does. I do think it is a bit risky for time parsing to behave differently like this depending on the location of the machine running it, and that it could be safer to never turn a numeric offset into a location. But, I guess that is what is most often wanted by the user. There is time.ParseInLocation() if you want control over this.

Here is a playground example based on your code that demonstrates what happens: https://play.golang.org/p/dNIj1QxBxJ1

@antong

This comment has been minimized.

Copy link
Contributor

commented Feb 19, 2019

@briancharous , Brian, Could you please have a look at this and my analysis, and comment whether this is a real bug or whether it was just a misunderstanding about the admittedly confusing behavior of time.Parse() re local time zones.

@briancharous

This comment has been minimized.

Copy link
Author

commented Feb 25, 2019

@antong Yeah I think your analysis of this makes sense. The Mac I was testing this on's clock is not set to UTC, while the Linux "machine" (really a Docker container running in Docker for Mac) has its system clock set to UTC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.