mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
time: use offset and isDST when caching zone 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. Fixes #45370 Change-Id: I79102e4873b6de20d8a65f8a3057519ff5fae608 Reviewed-on: https://go-review.googlesource.com/c/go/+/307190 Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> Trust: Emmanuel Odeke <emmanuel@orijtech.com> Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
cf148f3d46
commit
a11244e95e
2 changed files with 40 additions and 18 deletions
|
|
@ -247,8 +247,8 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
||||||
// This also avoids a panic later when we add and then use a fake transition (golang.org/issue/29437).
|
// This also avoids a panic later when we add and then use a fake transition (golang.org/issue/29437).
|
||||||
return nil, badData
|
return nil, badData
|
||||||
}
|
}
|
||||||
zone := make([]zone, nzone)
|
zones := make([]zone, nzone)
|
||||||
for i := range zone {
|
for i := range zones {
|
||||||
var ok bool
|
var ok bool
|
||||||
var n uint32
|
var n uint32
|
||||||
if n, ok = zonedata.big4(); !ok {
|
if n, ok = zonedata.big4(); !ok {
|
||||||
|
|
@ -257,22 +257,22 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
||||||
if uint32(int(n)) != n {
|
if uint32(int(n)) != n {
|
||||||
return nil, badData
|
return nil, badData
|
||||||
}
|
}
|
||||||
zone[i].offset = int(int32(n))
|
zones[i].offset = int(int32(n))
|
||||||
var b byte
|
var b byte
|
||||||
if b, ok = zonedata.byte(); !ok {
|
if b, ok = zonedata.byte(); !ok {
|
||||||
return nil, badData
|
return nil, badData
|
||||||
}
|
}
|
||||||
zone[i].isDST = b != 0
|
zones[i].isDST = b != 0
|
||||||
if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
|
if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
|
||||||
return nil, badData
|
return nil, badData
|
||||||
}
|
}
|
||||||
zone[i].name = byteString(abbrev[b:])
|
zones[i].name = byteString(abbrev[b:])
|
||||||
if runtime.GOOS == "aix" && len(name) > 8 && (name[:8] == "Etc/GMT+" || name[:8] == "Etc/GMT-") {
|
if runtime.GOOS == "aix" && len(name) > 8 && (name[:8] == "Etc/GMT+" || name[:8] == "Etc/GMT-") {
|
||||||
// There is a bug with AIX 7.2 TL 0 with files in Etc,
|
// There is a bug with AIX 7.2 TL 0 with files in Etc,
|
||||||
// GMT+1 will return GMT-1 instead of GMT+1 or -01.
|
// GMT+1 will return GMT-1 instead of GMT+1 or -01.
|
||||||
if name != "Etc/GMT+0" {
|
if name != "Etc/GMT+0" {
|
||||||
// GMT+0 is OK
|
// GMT+0 is OK
|
||||||
zone[i].name = name[4:]
|
zones[i].name = name[4:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -295,7 +295,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tx[i].when = n
|
tx[i].when = n
|
||||||
if int(txzones[i]) >= len(zone) {
|
if int(txzones[i]) >= len(zones) {
|
||||||
return nil, badData
|
return nil, badData
|
||||||
}
|
}
|
||||||
tx[i].index = txzones[i]
|
tx[i].index = txzones[i]
|
||||||
|
|
@ -314,7 +314,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Committed to succeed.
|
// Committed to succeed.
|
||||||
l := &Location{zone: zone, tx: tx, name: name, extend: extend}
|
l := &Location{zone: zones, tx: tx, name: name, extend: extend}
|
||||||
|
|
||||||
// Fill in the cache with information about right now,
|
// Fill in the cache with information about right now,
|
||||||
// since that will be the most common lookup.
|
// since that will be the most common lookup.
|
||||||
|
|
@ -323,26 +323,27 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
||||||
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
|
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
|
||||||
l.cacheStart = tx[i].when
|
l.cacheStart = tx[i].when
|
||||||
l.cacheEnd = omega
|
l.cacheEnd = omega
|
||||||
zoneIdx := tx[i].index
|
l.cacheZone = &l.zone[tx[i].index]
|
||||||
if i+1 < len(tx) {
|
if i+1 < len(tx) {
|
||||||
l.cacheEnd = tx[i+1].when
|
l.cacheEnd = tx[i+1].when
|
||||||
} else if l.extend != "" {
|
} else if l.extend != "" {
|
||||||
// If we're at the end of the known zone transitions,
|
// If we're at the end of the known zone transitions,
|
||||||
// try the extend string.
|
// try the extend string.
|
||||||
if name, _, estart, eend, _, ok := tzset(l.extend, l.cacheEnd, sec); ok {
|
if name, offset, estart, eend, isDST, ok := tzset(l.extend, l.cacheEnd, sec); ok {
|
||||||
l.cacheStart = estart
|
l.cacheStart = estart
|
||||||
l.cacheEnd = eend
|
l.cacheEnd = eend
|
||||||
// Find the zone that is returned by tzset,
|
// Find the zone that is returned by tzset to avoid allocation if possible.
|
||||||
// the last transition is not always the correct zone.
|
if zoneIdx := findZone(l.zone, name, offset, isDST); zoneIdx != -1 {
|
||||||
for i, z := range l.zone {
|
|
||||||
if z.name == name {
|
|
||||||
zoneIdx = uint8(i)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
l.cacheZone = &l.zone[zoneIdx]
|
l.cacheZone = &l.zone[zoneIdx]
|
||||||
|
} else {
|
||||||
|
l.cacheZone = &zone{
|
||||||
|
name: name,
|
||||||
|
offset: offset,
|
||||||
|
isDST: isDST,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -350,6 +351,15 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findZone(zones []zone, name string, offset int, isDST bool) int {
|
||||||
|
for i, z := range zones {
|
||||||
|
if z.name == name && z.offset == offset && z.isDST == isDST {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
// loadTzinfoFromDirOrZip returns the contents of the file with the given name
|
// loadTzinfoFromDirOrZip returns the contents of the file with the given name
|
||||||
// in dir. dir can either be an uncompressed zip file, or a directory.
|
// in dir. dir can either be an uncompressed zip file, or a directory.
|
||||||
func loadTzinfoFromDirOrZip(dir, name string) ([]byte, error) {
|
func loadTzinfoFromDirOrZip(dir, name string) ([]byte, error) {
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue