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

Closed
briancharous opened this issue Feb 6, 2019 · 5 comments
Closed

time: Parse with 0 UTC offset different on darwin vs linux #30114

briancharous opened this issue Feb 6, 2019 · 5 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.

Comments

@briancharous
Copy link

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
@dmitshur dmitshur added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Feb 7, 2019
@antong
Copy link
Contributor

antong 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
Copy link
Contributor

antong 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
Copy link
Author

@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.

@antong
Copy link
Contributor

antong commented Sep 7, 2019

I think this is investigated enough, solved and can be closed.

@ALTree
Copy link
Member

ALTree commented Sep 9, 2019

I agree that this is working as documented. Closing here.

@ALTree ALTree closed this as completed Sep 9, 2019
@golang golang locked and limited conversation to collaborators Sep 8, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

5 participants