Go: time: incorrect timezone for dates after 2038

Created on 20 Jan 2020  路  11Comments  路  Source: golang/go

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

$ go version
go version go1.13.4 darwin/amd64

Does this issue reproduce with the latest release?

Yes. See: https://play.golang.org/p/zhDzRup9BRP

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

go env Output

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/artem/Library/Caches/go-build"
GOENV="/Users/artem/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/artem/parsec/fed:/Users/artem/parsec/fed/_vendor"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.13.4/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.13.4/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
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/n0/2pcvtf912dz4qq61kl72vsg00000gn/T/go-build253354351=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

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

package main

import (
    "fmt"
    "time"
)

func main() {
    loc, _ := time.LoadLocation("America/Los_Angeles")
    d1 := time.Date(2037, 6, 3, 11, 0, 0, 0, loc)
    d2 := time.Date(2038, 6, 3, 11, 0, 0, 0, loc)
    fmt.Println(d1)
    fmt.Println(d2)
}

What did you expect to see?

2037-06-03 11:00:00 -0700 PDT
2038-06-03 11:00:00 -0700 PDT

This is behavior that has been produced by other time processing tools and libraries. For example:

$ TZ='America/Los_Angeles' date --date="@2159200800"
Thu Jun  3 11:00:00 PDT 2038

What did you see instead?

2037-06-03 11:00:00 -0700 PDT
2038-06-03 11:00:00 -0800 PST
NeedsFix

Most helpful comment

In the CL that I sent, it will slow down all timezone operations that involve dates in 2038 and later. It will not affect timezone operations for current dates.

My guess is that before 2038 the tzdata format will change to push the slowdown farther into the future. Anyhow, since nobody has complained about this until now, I assume that not too many people care about it, so let's start by getting it right, and only then worry about making it fast.

(My hope is that by 2038 we'll all stop using daylight savings time, and all of this code will become a peculiar historical artifact.)

All 11 comments

This is happening because the time package does not consider the "extended" information that is available in the tzdata database.

Change https://golang.org/cl/215539 mentions this issue: time: use extended time format past end of zone transitions

2038 support is becoming more and more important, we only have 18 left years to get it right now. Already some future dates will start to fail. So I'm glad to see this is being fixed.

But note that this particular fix, while worth doing, is somewhat speculative. We don't actually know what the daylight savings time transitions will be in 2038, and so reporting future times as PDT or PST is a guess. Since this particular example uses America/Los_Angeles, it's worth noting that California passed a referendum to stop doing daylight savings time transitions at all (https://ballotpedia.org/California_Proposition_7,_Legislative_Power_to_Change_Daylight_Saving_Time_Measure_(2018)) and that may still happen. If it does, the program above will report incorrect results, at least until the tzdata files are updated.

Well, at least it should report a correct ("as of known today") time zone, and I understood your patch correctly, it does fix that.

What I kind of did not understand - will that code addition of extended tz info parsing slow down all time-related ops, or this happens "once" and that's it?

In the CL that I sent, it will slow down all timezone operations that involve dates in 2038 and later. It will not affect timezone operations for current dates.

My guess is that before 2038 the tzdata format will change to push the slowdown farther into the future. Anyhow, since nobody has complained about this until now, I assume that not too many people care about it, so let's start by getting it right, and only then worry about making it fast.

(My hope is that by 2038 we'll all stop using daylight savings time, and all of this code will become a peculiar historical artifact.)

The CL does not seem restricted to US time zones. Regarding European time (EU), the trend is to discontinue Daylight Saving Time in the coming years (cf. https://ec.europa.eu/transport/themes/summertime_en) although final decision does not seem available.

But note that this particular fix, while worth doing, is somewhat speculative. We don't actually know what the daylight savings time transitions will be in 2038, and so reporting future times as PDT or PST is a guess.

As @ianlancetaylor points out, this is an inherent problem with trying to report future civil times. There is nothing to prevent the relevant authorities from changing the laws back and forth, potentially on multiple occasions. Technically some jurisdictions could even enact law that retroactively changes the interpretation of past times.... (Weirder things have happened. The tzdata files make fascinating reading.) More prosaically, the tzdata files can be updated or corrected post-facto.

In general, any attempt to make non-trivial use of a future civil time is fraught with difficulty. Making a best guess in displaying it is about as far as one should probably go.

Change https://golang.org/cl/264302 mentions this issue: [release-branch.go1.14] time: use extended time format past end of zone transitions

Australia/Sydney is returning non-DST currently (while we are in DST), at least under Alpine with the tzdata package in version 2020c-r0. The 2020a-r0 version was fine.

Looking at the internals of the TZ data being parsed, DST transition data being parsed by Go for this timezone appears to end ~2008 in the 1.14.2 release of Go

EDIT: Confirmed the same behaviour in Go 1.15.3 releases with Alpine (which now provides 2020c version of tzdata). Buster does not present the same issue, but currently uses the 2020a tzdata, which was fine under Alpine.

package main

import (
    "fmt"
    "os"
    "time"
)

func main() {
    loc, err := time.LoadLocation("Australia/Sydney")
    if err != nil {
        fmt.Fprintln(os.Stderr, err.Error())
        os.Exit(1)
    }

    sept := time.Date(2020, time.September, 23, 15, 43, 22, 0, loc)
    oct := time.Date(2020, time.October, 23, 15, 43, 22, 0, loc)

    fmt.Fprintln(os.Stdout, sept.Format(time.RFC3339))
    fmt.Fprintln(os.Stdout, oct.Format(time.RFC3339))
}
FROM golang:1.15.3-alpine3.12

RUN apk add --no-cache tzdata

COPY main.go /go/src/tz/

WORKDIR /go/src/tz

ENTRYPOINT ["go", "run", "main.go"]

Alpine Output (incorrect):

2020-09-23T15:43:22+10:00
2020-10-23T15:43:22+10:00

tzdata for Alpine: 2020c-r0 (2020a-r0 was fine)

Buster Output (correct):

2020-09-23T15:43:22+10:00
2020-10-23T15:43:22+11:00

tzdata for Buster: 2020a-0+deb10u1

This issues with 2020b and beyond appear to have been captured by https://github.com/golang/go/issues/42138

Was this page helpful?
0 / 5 - 0 ratings