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: Europe/Dublin timezone handling broken with embedded timezone database #45370

Closed
martin-sucha opened this issue Apr 3, 2021 · 8 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@martin-sucha
Copy link
Contributor

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

$ go version
go version go1.16.3 linux/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
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.16.3"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
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 -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2227163467=/tmp/go-build -gno-record-gcc-switches"

What did you do?

When I run the following test program in Go 1.16.3 Docker image:

docker run --rm -it golang:1.16.3 /bin/bash
root@7f026683314e:/go# cat >/main.go
package main

import (
	"fmt"
	"time"
)

func main() {
	loc, err := time.LoadLocation("Europe/Dublin")
	if err != nil {
		panic(err)
	}
	t, err := time.ParseInLocation("2006-01-02T15:04:05", "2021-04-02T11:12:13", loc)
	if err != nil {
		panic(err)
	}
	fmt.Println(t)
}
root@7f026683314e:/go# go run /main.go
2021-04-02 11:12:13 +0100 IST
root@7f026683314e:/go# ZONEINFO=/usr/local/go/lib/time/zoneinfo.zip go run /main.go
2021-04-02 11:12:13 +0034 IST

What did you expect to see?

I expect to see 2021-04-02 11:12:13 +0100 IST also when using the embedded timezone database.

What did you see instead?

2021-04-02 11:12:13 +0034 IST which has incorrect offset from UTC.

@martin-sucha
Copy link
Contributor Author

martin-sucha commented Apr 3, 2021

I have converted the Europe/Dublin timezone file from the system (/usr/share/zoneinfo/Europe/Dublin) and the one in /usr/local/go/lib/time/zoneinfo.zip to text (with tzif2text) and noticed in the diff that the version in Go distribution has last transition time 828234000 (1996-03-31T01:00:00 UTC) while the system one contains more transitions, up to 2140045200 (2037-10-25T01:00:00 UTC).

Note that both versions (Go/system one) should be 2021a (the package version in the Docker image is 2021a-0+deb10u1 to be exact)

@martin-sucha
Copy link
Contributor Author

In this case the missing zone transitions in the embedded timezone database lead to LoadLocationFromTZData using the extend string when building the cache. However, LoadLocationFromTZData ignores the computed offset from tzset (which is correct) and instead looks up using the zone name IST:

// If we're at the end of the known zone transitions,
				// try the extend string.
				if name, _, estart, eend, ok := tzset(l.extend, l.cacheEnd, sec); ok {
					l.cacheStart = estart
					l.cacheEnd = eend
					// Find the zone that is returned by tzset,
					// the last transition is not always the correct zone.
					for i, z := range l.zone {
						if z.name == name {
							zoneIdx = uint8(i)
							break
						}
					}
				}

This leads to a similar situation as in #36529, because there are two variants of IST. At index 2 there is name=IST offset=2079 isDST=true, at index 7 there is name=IST offset=3600 isDST=false.

Since a9b3c4b tzset returns also isDST flag in addition to the offset, so we could construct a zone to assign to the l.cacheZone directly without any lookup of zone by name.

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/307190 mentions this issue: time: Fix cached extended zone

@odeke-em odeke-em changed the title Europe/Dublin timezone handling broken with embedded timezone database time: Europe/Dublin timezone handling broken with embedded timezone database Apr 4, 2021
@ianlancetaylor
Copy link
Member

@gopherbot Please open a backport issue.

This issue will cause incorrect timezone information to be used on systems using the slim tzdata format, which are increasingly likely as it is now the default.

@gopherbot
Copy link
Contributor

Backport issue(s) opened: #45384 (for 1.15), #45385 (for 1.16).

Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://golang.org/wiki/MinorReleases.

@ALTree ALTree added the NeedsFix The path to resolution is known, but the work has not been done. label Apr 5, 2021
@ALTree ALTree added this to the Go1.17 milestone Apr 5, 2021
@martin-sucha
Copy link
Contributor Author

martin-sucha commented Apr 5, 2021

For the record, I compared the zone offsets for 2021-04-02T11:12:13 and 2021-11-02T11:12:13 obtained when using the 2021a slim files from Go distribution and 2021a files in my system (2021a-0ubuntu0.18.04). The following had different offsets for at least one of those times, so at least these time zones are affected:

America/Indiana/Petersburg
America/North_Dakota/Beulah
America/St_Johns
Canada/Newfoundland
Eire
Europe/Dublin

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/307212 mentions this issue: [release-branch.go1.15] time: use offset and isDST when caching zone from extend string

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/307211 mentions this issue: [release-branch.go1.16] time: use offset and isDST when caching zone from extend string

gopherbot pushed a commit that referenced this issue Apr 12, 2021
…from extend string

If the current time is computed from extend string
and the zone file contains multiple zones with the
same name, the lookup by name might find incorrect
zone.

This happens for example with the slim Europe/Dublin
time zone file in the embedded zip. This zone file
has last transition in 1996 and rest is covered by
extend string.
tzset returns IST as the zone name to use, but there
are two records with IST name. Lookup by name finds
the wrong one. We need to check offset and isDST too.

In case we can't find an existing zone, we allocate
a new zone so that we use correct offset and isDST.

I have renamed zone variable to zones as it shadowed
the zone type that we need to allocate the cached zone.

Backport note: this change also incorporates portions of
CL 264077.

For #45370
Fixes #45384

Change-Id: I43d416d009e20878261156c821a5784e2407ed1f
Reviewed-on: https://go-review.googlesource.com/c/go/+/307212
Trust: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
gopherbot pushed a commit that referenced this issue Apr 12, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
…from extend string

If the current time is computed from extend string
and the zone file contains multiple zones with the
same name, the lookup by name might find incorrect
zone.

This happens for example with the slim Europe/Dublin
time zone file in the embedded zip. This zone file
has last transition in 1996 and rest is covered by
extend string.
tzset returns IST as the zone name to use, but there
are two records with IST name. Lookup by name finds
the wrong one. We need to check offset and isDST too.

In case we can't find an existing zone, we allocate
a new zone so that we use correct offset and isDST.

I have renamed zone variable to zones as it shadowed
the zone type that we need to allocate the cached zone.

Backport note: this change also incorporates portions of
CL 264077.

For #45370
Fixes #45385

Change-Id: If7a0cccc1908e27f0509bf422d824133133250fc
Reviewed-on: https://go-review.googlesource.com/c/go/+/307211
Trust: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
@golang golang locked and limited conversation to collaborators Apr 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

5 participants
@martin-sucha @ianlancetaylor @ALTree @gopherbot and others