From 06c9756333bb506dcbf322be77af85b3162b6345 Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor <iant@golang.org>
Date: Mon, 5 Apr 2021 12:12:25 -0700
Subject: [PATCH 37/44] [release-branch.go1.15] 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.

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>

Conflict:NA
Reference:https://github.com/golang/go/commit/06c9756333bb506dcbf322be77af85b3162b6345

---
 src/time/zoneinfo.go      | 27 ++++++++++++++----------
 src/time/zoneinfo_read.go | 44 ++++++++++++++++++++++++---------------
 src/time/zoneinfo_test.go | 37 +++++++++++++++++++++-----------
 3 files changed, 68 insertions(+), 40 deletions(-)

diff --git a/src/time/zoneinfo.go b/src/time/zoneinfo.go
index 6db9443474..57052338d0 100644
--- a/src/time/zoneinfo.go
+++ b/src/time/zoneinfo.go
@@ -178,7 +178,7 @@ func (l *Location) lookup(sec int64) (name string, offset int, start, end int64)
 	// If we're at the end of the known zone transitions,
 	// try the extend string.
 	if lo == len(tx)-1 && l.extend != "" {
-		if ename, eoffset, estart, eend, ok := tzset(l.extend, end, sec); ok {
+		if ename, eoffset, estart, eend, _, ok := tzset(l.extend, end, sec); ok {
 			return ename, eoffset, estart, eend
 		}
 	}
@@ -244,7 +244,7 @@ func (l *Location) firstZoneUsed() bool {
 // We call this a tzset string since in C the function tzset reads TZ.
 // The return values are as for lookup, plus ok which reports whether the
 // parse succeeded.
-func tzset(s string, initEnd, sec int64) (name string, offset int, start, end int64, ok bool) {
+func tzset(s string, initEnd, sec int64) (name string, offset int, start, end int64, isDST, ok bool) {
 	var (
 		stdName, dstName     string
 		stdOffset, dstOffset int
@@ -255,7 +255,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
 		stdOffset, s, ok = tzsetOffset(s)
 	}
 	if !ok {
-		return "", 0, 0, 0, false
+		return "", 0, 0, 0, false, false
 	}
 
 	// The numbers in the tzset string are added to local time to get UTC,
@@ -265,7 +265,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
 
 	if len(s) == 0 || s[0] == ',' {
 		// No daylight savings time.
-		return stdName, stdOffset, initEnd, omega, true
+		return stdName, stdOffset, initEnd, omega, false, true
 	}
 
 	dstName, s, ok = tzsetName(s)
@@ -278,7 +278,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
 		}
 	}
 	if !ok {
-		return "", 0, 0, 0, false
+		return "", 0, 0, 0, false, false
 	}
 
 	if len(s) == 0 {
@@ -287,19 +287,19 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
 	}
 	// The TZ definition does not mention ';' here but tzcode accepts it.
 	if s[0] != ',' && s[0] != ';' {
-		return "", 0, 0, 0, false
+		return "", 0, 0, 0, false, false
 	}
 	s = s[1:]
 
 	var startRule, endRule rule
 	startRule, s, ok = tzsetRule(s)
 	if !ok || len(s) == 0 || s[0] != ',' {
-		return "", 0, 0, 0, false
+		return "", 0, 0, 0, false, false
 	}
 	s = s[1:]
 	endRule, s, ok = tzsetRule(s)
 	if !ok || len(s) > 0 {
-		return "", 0, 0, 0, false
+		return "", 0, 0, 0, false, false
 	}
 
 	year, _, _, yday := absDate(uint64(sec+unixToInternal+internalToAbsolute), false)
@@ -313,10 +313,15 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
 
 	startSec := int64(tzruleTime(year, startRule, stdOffset))
 	endSec := int64(tzruleTime(year, endRule, dstOffset))
+	dstIsDST, stdIsDST := true, false
+	// Note: this is a flipping of "DST" and "STD" while retaining the labels
+	// This happens in southern hemispheres. The labelling here thus is a little
+	// inconsistent with the goal.
 	if endSec < startSec {
 		startSec, endSec = endSec, startSec
 		stdName, dstName = dstName, stdName
 		stdOffset, dstOffset = dstOffset, stdOffset
+		stdIsDST, dstIsDST = dstIsDST, stdIsDST
 	}
 
 	// The start and end values that we return are accurate
@@ -324,11 +329,11 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
 	// just the start and end of the year. That suffices for
 	// the only caller that cares, which is Date.
 	if ysec < startSec {
-		return stdName, stdOffset, abs, startSec + abs, true
+		return stdName, stdOffset, abs, startSec + abs, stdIsDST, true
 	} else if ysec >= endSec {
-		return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, true
+		return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, stdIsDST, true
 	} else {
-		return dstName, dstOffset, startSec + abs, endSec + abs, true
+		return dstName, dstOffset, startSec + abs, endSec + abs, dstIsDST, true
 	}
 }
 
diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go
index 22a60f3211..f7fe59c385 100644
--- a/src/time/zoneinfo_read.go
+++ b/src/time/zoneinfo_read.go
@@ -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).
 		return nil, badData
 	}
-	zone := make([]zone, nzone)
-	for i := range zone {
+	zones := make([]zone, nzone)
+	for i := range zones {
 		var ok bool
 		var n uint32
 		if n, ok = zonedata.big4(); !ok {
@@ -257,22 +257,22 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
 		if uint32(int(n)) != n {
 			return nil, badData
 		}
-		zone[i].offset = int(int32(n))
+		zones[i].offset = int(int32(n))
 		var b byte
 		if b, ok = zonedata.byte(); !ok {
 			return nil, badData
 		}
-		zone[i].isDST = b != 0
+		zones[i].isDST = b != 0
 		if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
 			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-") {
 			// 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.
 			if name != "Etc/GMT+0" {
 				// 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
-		if int(txzones[i]) >= len(zone) {
+		if int(txzones[i]) >= len(zones) {
 			return nil, badData
 		}
 		tx[i].index = txzones[i]
@@ -314,7 +314,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
 	}
 
 	// 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,
 	// 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) {
 			l.cacheStart = tx[i].when
 			l.cacheEnd = omega
-			zoneIdx := tx[i].index
+			l.cacheZone = &l.zone[tx[i].index]
 			if i+1 < len(tx) {
 				l.cacheEnd = tx[i+1].when
 			} else if l.extend != "" {
 				// 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 {
+				if name, offset, estart, eend, isDST, 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
+					// Find the zone that is returned by tzset to avoid allocation if possible.
+					if zoneIdx := findZone(l.zone, name, offset, isDST); zoneIdx != -1 {
+						l.cacheZone = &l.zone[zoneIdx]
+					} else {
+						l.cacheZone = &zone{
+							name:   name,
+							offset: offset,
+							isDST:  isDST,
 						}
 					}
 				}
 			}
-			l.cacheZone = &l.zone[zoneIdx]
 			break
 		}
 	}
@@ -350,6 +351,15 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
 	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
 // in dir. dir can either be an uncompressed zip file, or a directory.
 func loadTzinfoFromDirOrZip(dir, name string) ([]byte, error) {
diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go
index d043e1e9f1..7ba1229741 100644
--- a/src/time/zoneinfo_test.go
+++ b/src/time/zoneinfo_test.go
@@ -186,6 +186,7 @@ func TestMalformedTZData(t *testing.T) {
 var slimTests = []struct {
 	zoneName   string
 	tzData     string
+	date       func(*time.Location) time.Time
 	wantName   string
 	wantOffset int
 }{
@@ -193,6 +194,7 @@ var slimTests = []struct {
 		// 2020b slim tzdata for Europe/Berlin.
 		zoneName:   "Europe/Berlin",
 		tzData:     "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\f\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9cٮ\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\tq\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xffͩ\x17\x90\xff\xff\xff\xff\u03a2C\x10\xff\xff\xff\xffϒ4\x10\xff\xff\xff\xffЂ%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xffѶ\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xffҡO\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xffըs\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\t\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00#<E\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%\x1c'\x10\x00\x00\x00\x00&\f\x18\x10\x00\x00\x00\x00'\x05C\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00(\xe5%\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xc5\a\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xa4\xe9\x90\x00\x00\x00\x00-\x94ڐ\x00\x00\x00\x00.\x84ː\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000d\xad\x90\x00\x00\x00\x001]\xd9\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\f\x88\x00\x00\x00\x00\x1c \x01\x04\x00\x00\x0e\x10\x00\t\x00\x00*0\x01\rLMT\x00CEST\x00CET\x00CEMT\x00\nCET-1CEST,M3.5.0,M10.5.0/3\n",
+		date:       func(loc *time.Location) time.Time { return time.Date(2020, time.October, 29, 15, 30, 0, 0, loc) },
 		wantName:   "CET",
 		wantOffset: 3600,
 	},
@@ -200,6 +202,7 @@ var slimTests = []struct {
 		// 2021a slim tzdata for America/Nuuk.
 		zoneName:   "America/Nuuk",
 		tzData:     "TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"\x00\x00\x00\x03\x00\x00\x00\f\xff\xff\xff\xff\x9b\x80h\x00\x00\x00\x00\x00\x13M|P\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00#<E\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%\x1c'\x10\x00\x00\x00\x00&\f\x18\x10\x00\x00\x00\x00'\x05C\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00(\xe5%\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xc5\a\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xa4\xe9\x90\x00\x00\x00\x00-\x94ڐ\x00\x00\x00\x00.\x84ː\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000d\xad\x90\x00\x00\x00\x001]\xd9\x10\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xffπ\x00\x00\xff\xff\xd5\xd0\x00\x04\xff\xff\xe3\xe0\x01\bLMT\x00-03\x00-02\x00\n<-03>3<-02>,M3.5.0/-2,M10.5.0/-1\n",
+		date:       func(loc *time.Location) time.Time { return time.Date(2020, time.October, 29, 15, 30, 0, 0, loc) },
 		wantName:   "-03",
 		wantOffset: -10800,
 	},
@@ -207,9 +210,18 @@ var slimTests = []struct {
 		// 2021a slim tzdata for Asia/Gaza.
 		zoneName:   "Asia/Gaza",
 		tzData:     "TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff}\xbdJ\xb0\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xffͬ\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xffϏ\x83\x00\xff\xff\xff\xffЩ\xa4\x00\xff\xff\xff\xffф}\x00\xff\xff\xff\xffҊ׀\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\v\x00\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\v\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\u007f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xffﰳp\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb'BP\x00\x00\x00\x00\b|\x8b\xe0\x00\x00\x00\x00\b\xfd\xb0\xd0\x00\x00\x00\x00\t\xf6\xea`\x00\x00\x00\x00\n\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\"^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\v\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x000\xe7\a\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\n`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007\x16a`\x00\x00\x00\x008\x06DP\x00\x00\x00\x008\xff}\xe0\x00\x00\x00\x009\xef`\xd0\x00\x00\x00\x00:\xdf_\xe0\x00\x00\x00\x00;\xcfB\xd0\x00\x00\x00\x00<\xbfA\xe0\x00\x00\x00\x00=\xaf$\xd0\x00\x00\x00\x00>\x9f#\xe0\x00\x00\x00\x00?\x8f\x06\xd0\x00\x00\x00\x00@\u007f\x05\xe0\x00\x00\x00\x00A\\\x81\xe0\x00\x00\x00\x00B^\xe7\xe0\x00\x00\x00\x00CA\xb7\xf0\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0e\xd9\xe0\x00\x00\x00\x00F\xe8op\x00\x00\x00\x00G\xec\x18\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xa0<`\x00\x00\x00\x00K\xad.\x9c\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00M\x94\xf9\x9c\x00\x00\x00\x00N5\xc2P\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P[\x91\xe0\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00RD\xa0P\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TIlP\x00\x00\x00\x00U\x15\xd2\xe0\x00\x00\x00\x00V)\\`\x00\x00\x00\x00V\xf5\xc2\xf0\x00\x00\x00\x00X\x13\xca`\x00\x00\x00\x00Xդ\xf0\x00\x00\x00\x00Y\xf3\xac`\x00\x00\x00\x00Z\xb5\x86\xf0\x00\x00\x00\x00[ӎ`\x00\x00\x00\x00\\\x9dC\xe0\x00\x00\x00\x00]\xb3bP\x00\x00\x00\x00^~w`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00 P\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\t\x00\x00*0\x01\r\x00\x00\x1c \x00\x11LMT\x00EEST\x00EET\x00IDT\x00IST\x00\nEET-2EEST,M3.4.4/48,M10.4.4/49\n",
+		date:       func(loc *time.Location) time.Time { return time.Date(2020, time.October, 29, 15, 30, 0, 0, loc) },
 		wantName:   "EET",
 		wantOffset: 7200,
 	},
+	{
+		// 2021a slim tzdata for Europe/Dublin.
+		zoneName:   "Europe/Dublin",
+		tzData:     "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91\x00\x00\x00\x08\x00\x00\x00\x14\xff\xff\xff\xffW\xd1\n\xdc\xff\xff\xff\xff\x9b&\xb3\x91\xff\xff\xff\xff\x9b\xd6\x0b\x11\xff\xff\xff\xff\x9c\xcf0\xa0\xff\xff\xff\xff\x9d\xa4\xc3\xa0\xff\xff\xff\xff\x9e\x9c\x9d\xa0\xff\xff\xff\xff\x9f\x97\x1a\xa0\xff\xff\xff\xff\xa0\x85\xba\x20\xff\xff\xff\xff\xa1v\xfc\xa0\xff\xff\xff\xff\xa2e\x9c\x20\xff\xff\xff\xff\xa3{\xc8\xa0\xff\xff\xff\xff\xa4N\xb8\xa0\xff\xff\xff\xff\xa5?\xfb\x20\xff\xff\xff\xff\xa6%`\x20\xff\xff\xff\xff\xa7'\xc6\x20\xff\xff\xff\xff\xa8*,\x20\xff\xff\xff\xff\xa8\xeb\xf8\xa0\xff\xff\xff\xff\xaa\x00\xd3\xa0\xff\xff\xff\xff\xaa\xd5\x15\x20\xff\xff\xff\xff\xab\xe9\xf0\x20\xff\xff\xff\xff\xac\xc7l\x20\xff\xff\xff\xff\xad\xc9\xd2\x20\xff\xff\xff\xff\xae\xa7N\x20\xff\xff\xff\xff\xaf\xa0y\xa0\xff\xff\xff\xff\xb0\x870\x20\xff\xff\xff\xff\xb1\x92\xd0\xa0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ\x20\xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb9\x12X\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xe9\x00\x20\xff\xff\xff\xff\xbb\xd8\xf1\x20\xff\xff\xff\xff\xbc\xdbW\x20\xff\xff\xff\xff\xbd\xb8\xd3\x20\xff\xff\xff\xff\xbe\xb1\xfe\xa0\xff\xff\xff\xff\xbf\x98\xb5\x20\xff\xff\xff\xff\xc0\x9b\x1b\x20\xff\xff\xff\xff\xc1x\x97\x20\xff\xff\xff\xff\xc2z\xfd\x20\xff\xff\xff\xff\xc3Xy\x20\xff\xff\xff\xff\xc4Q\xa4\xa0\xff\xff\xff\xff\xc58[\x20\xff\xff\xff\xff\xc6:\xc1\x20\xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xd4I\xe0\x20\xff\xff\xff\xff\xd5\x1e!\xa0\xff\xff\xff\xff\xd6N\xac\x20\xff\xff\xff\xff\xd7,(\x20\xff\xff\xff\xff\xd8.\x8e\x20\xff\xff\xff\xff\xd8\xf9\x95\x20\xff\xff\xff\xff\xda\x0ep\x20\xff\xff\xff\xff\xda\xeb\xec\x20\xff\xff\xff\xff\xdb\xe5\x17\xa0\xff\xff\xff\xff\xdc\xcb\xce\x20\xff\xff\xff\xff\xdd\xc4\xf9\xa0\xff\xff\xff\xff\xde\xb4\xea\xa0\xff\xff\xff\xff\xdf\xae\x16\x20\xff\xff\xff\xff\xe0\x94\xcc\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2kt\x20\xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4T\x90\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6=\xad\x20\xff\xff\xff\xff\xe7\x1b)\x20\xff\xff\xff\xff\xe8\x14T\xa0\xff\xff\xff\xff\xe8\xfb\x0b\x20\xff\xff\xff\xff\xe9\xfdq\x20\xff\xff\xff\xff\xea\xda\xed\x20\xff\xff\xff\xff\xeb\xddS\x20\xff\xff\xff\xff\xec\xba\xcf\x20\xff\xff\xff\xff\xed\xb3\xfa\xa0\xff\xff\xff\xff\xee\x9a\xb1\x20\xff\xff\xff\xff\xef\x81g\xa0\xff\xff\xff\xff\xf0\x9f}\x20\xff\xff\xff\xff\xf1aI\xa0\xff\xff\xff\xff\xf2\x7f_\x20\xff\xff\xff\xff\xf3Jf\x20\xff\xff\xff\xff\xf4_A\x20\xff\xff\xff\xff\xf5!\x0d\xa0\xff\xff\xff\xff\xf6?#\x20\xff\xff\xff\xff\xf7\x00\xef\xa0\xff\xff\xff\xff\xf8\x1f\x05\x20\xff\xff\xff\xff\xf8\xe0\xd1\xa0\xff\xff\xff\xff\xf9\xfe\xe7\x20\xff\xff\xff\xff\xfa\xc0\xb3\xa0\xff\xff\xff\xff\xfb\xe8\x03\xa0\xff\xff\xff\xff\xfc{\xab\xa0\xff\xff\xff\xff\xfd\xc7\xbbp\x00\x00\x00\x00\x03p\xc6\x20\x00\x00\x00\x00\x04)X\x20\x00\x00\x00\x00\x05P\xa8\x20\x00\x00\x00\x00\x06\x09:\x20\x00\x00\x00\x00\x070\x8a\x20\x00\x00\x00\x00\x07\xe9\x1c\x20\x00\x00\x00\x00\x09\x10l\x20\x00\x00\x00\x00\x09\xc8\xfe\x20\x00\x00\x00\x00\n\xf0N\x20\x00\x00\x00\x00\x0b\xb2\x1a\xa0\x00\x00\x00\x00\x0c\xd00\x20\x00\x00\x00\x00\x0d\x91\xfc\xa0\x00\x00\x00\x00\x0e\xb0\x12\x20\x00\x00\x00\x00\x0fq\xde\xa0\x00\x00\x00\x00\x10\x99.\xa0\x00\x00\x00\x00\x11Q\xc0\xa0\x00\x00\x00\x00\x12y\x10\xa0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00\x14X\xf2\xa0\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x168\xc6\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x18\x18\xa8\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xf8\x8a\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xe1\xa7\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\xc1\x89\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f\xa1k\x10\x00\x00\x00\x00\x20lr\x10\x00\x00\x00\x00!\x81M\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#a/\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%JK\x90\x00\x00\x00\x00&\x0c\x18\x10\x00\x00\x00\x00'*-\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00)\n\x0f\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xe9\xf1\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xc9\xd3\x90\x00\x00\x00\x00-\x94\xda\x90\x00\x00\x00\x00.\xa9\xb5\x90\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000\x89\x97\x90\x00\x00\x00\x001]\xd9\x10\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\xff\xff\xfa$\x00\x00\xff\xff\xfa\x0f\x00\x04\x00\x00\x08\x1f\x01\x08\x00\x00\x0e\x10\x01\x0c\x00\x00\x00\x00\x00\x10\x00\x00\x0e\x10\x01\x08\x00\x00\x00\x00\x01\x10\x00\x00\x0e\x10\x00\x08LMT\x00DMT\x00IST\x00BST\x00GMT\x00\nIST-1GMT0,M10.5.0,M3.5.0/1\n",
+		date:       func(loc *time.Location) time.Time { return time.Date(2021, time.April, 2, 11, 12, 13, 0, loc) },
+		wantName:   "IST",
+		wantOffset: 3600,
+	},
 }
 
 func TestLoadLocationFromTZDataSlim(t *testing.T) {
@@ -219,7 +231,7 @@ func TestLoadLocationFromTZDataSlim(t *testing.T) {
 			t.Fatal(err)
 		}
 
-		d := time.Date(2020, time.October, 29, 15, 30, 0, 0, reference)
+		d := test.date(reference)
 		tzName, tzOffset := d.Zone()
 		if tzName != test.wantName {
 			t.Errorf("Zone name == %s, want %s", tzName, test.wantName)
@@ -239,20 +251,21 @@ func TestTzset(t *testing.T) {
 		off   int
 		start int64
 		end   int64
+		isDST bool
 		ok    bool
 	}{
-		{"", 0, 0, "", 0, 0, 0, false},
-		{"PST8PDT,M3.2.0,M11.1.0", 0, 2159200800, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true},
-		{"PST8PDT,M3.2.0,M11.1.0", 0, 2152173599, "PST", -8 * 60 * 60, 2145916800, 2152173600, true},
-		{"PST8PDT,M3.2.0,M11.1.0", 0, 2152173600, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true},
-		{"PST8PDT,M3.2.0,M11.1.0", 0, 2152173601, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true},
-		{"PST8PDT,M3.2.0,M11.1.0", 0, 2172733199, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true},
-		{"PST8PDT,M3.2.0,M11.1.0", 0, 2172733200, "PST", -8 * 60 * 60, 2172733200, 2177452800, true},
-		{"PST8PDT,M3.2.0,M11.1.0", 0, 2172733201, "PST", -8 * 60 * 60, 2172733200, 2177452800, true},
+		{"", 0, 0, "", 0, 0, 0, false, false},
+		{"PST8PDT,M3.2.0,M11.1.0", 0, 2159200800, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true},
+		{"PST8PDT,M3.2.0,M11.1.0", 0, 2152173599, "PST", -8 * 60 * 60, 2145916800, 2152173600, false, true},
+		{"PST8PDT,M3.2.0,M11.1.0", 0, 2152173600, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true},
+		{"PST8PDT,M3.2.0,M11.1.0", 0, 2152173601, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true},
+		{"PST8PDT,M3.2.0,M11.1.0", 0, 2172733199, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true},
+		{"PST8PDT,M3.2.0,M11.1.0", 0, 2172733200, "PST", -8 * 60 * 60, 2172733200, 2177452800, false, true},
+		{"PST8PDT,M3.2.0,M11.1.0", 0, 2172733201, "PST", -8 * 60 * 60, 2172733200, 2177452800, false, true},
 	} {
-		name, off, start, end, ok := time.Tzset(test.inStr, test.inEnd, test.inSec)
-		if name != test.name || off != test.off || start != test.start || end != test.end || ok != test.ok {
-			t.Errorf("tzset(%q, %d, %d) = %q, %d, %d, %d, %t, want %q, %d, %d, %d, %t", test.inStr, test.inEnd, test.inSec, name, off, start, end, ok, test.name, test.off, test.start, test.end, test.ok)
+		name, off, start, end, isDST, ok := time.Tzset(test.inStr, test.inEnd, test.inSec)
+		if name != test.name || off != test.off || start != test.start || end != test.end || isDST != test.isDST || ok != test.ok {
+			t.Errorf("tzset(%q, %d, %d) = %q, %d, %d, %d, %t, %t, want %q, %d, %d, %d, %t, %t", test.inStr, test.inEnd, test.inSec, name, off, start, end, isDST, ok, test.name, test.off, test.start, test.end, test.isDST, test.ok)
 		}
 	}
 }
-- 
2.27.0

