mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
time: read 64-bit data if available
Also store 64-bit data in lib/time/zoneinfo.zip. The comments argue that we don't need the 64-bit data until 2037 or 2106, but that turns out not to be the case. We also need them for dates before December 13, 1901, which is time.Unix(-0x80000000, 0). Fixes #30099 Change-Id: Ib8c9efb29b7b3c08531ae69912c588209d6320e9 Reviewed-on: https://go-review.googlesource.com/c/161202 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
c1050a8e54
commit
068a832a7e
@ -21,21 +21,8 @@ curl -L -O https://www.iana.org/time-zones/repository/releases/tzdata$DATA.tar.g
|
|||||||
tar xzf tzcode$CODE.tar.gz
|
tar xzf tzcode$CODE.tar.gz
|
||||||
tar xzf tzdata$DATA.tar.gz
|
tar xzf tzdata$DATA.tar.gz
|
||||||
|
|
||||||
# Turn off 64-bit output in time zone files.
|
|
||||||
# We don't need those until 2037.
|
|
||||||
perl -p -i -e 's/pass <= 2/pass <= 1/' zic.c
|
|
||||||
|
|
||||||
make CFLAGS=-DSTD_INSPIRED AWK=awk TZDIR=zoneinfo posix_only
|
make CFLAGS=-DSTD_INSPIRED AWK=awk TZDIR=zoneinfo posix_only
|
||||||
|
|
||||||
# America/Los_Angeles should not be bigger than 1100 bytes.
|
|
||||||
# If it is, we probably failed to disable the 64-bit output, which
|
|
||||||
# triples the size of the files.
|
|
||||||
size=$(ls -l zoneinfo/America/Los_Angeles | awk '{print $5}')
|
|
||||||
if [ $size -gt 1200 ]; then
|
|
||||||
echo 'zone file too large; 64-bit edit failed?' >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd zoneinfo
|
cd zoneinfo
|
||||||
rm -f ../../zoneinfo.zip
|
rm -f ../../zoneinfo.zip
|
||||||
zip -0 -r ../../zoneinfo.zip *
|
zip -0 -r ../../zoneinfo.zip *
|
||||||
|
Binary file not shown.
@ -59,6 +59,16 @@ func (d *dataIO) big4() (n uint32, ok bool) {
|
|||||||
return uint32(p[3]) | uint32(p[2])<<8 | uint32(p[1])<<16 | uint32(p[0])<<24, true
|
return uint32(p[3]) | uint32(p[2])<<8 | uint32(p[1])<<16 | uint32(p[0])<<24, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dataIO) big8() (n uint64, ok bool) {
|
||||||
|
n1, ok1 := d.big4()
|
||||||
|
n2, ok2 := d.big4()
|
||||||
|
if !ok1 || !ok2 {
|
||||||
|
d.error = true
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
return (uint64(n1) << 32) | uint64(n2), true
|
||||||
|
}
|
||||||
|
|
||||||
func (d *dataIO) byte() (n byte, ok bool) {
|
func (d *dataIO) byte() (n byte, ok bool) {
|
||||||
p := d.read(1)
|
p := d.read(1)
|
||||||
if len(p) < 1 {
|
if len(p) < 1 {
|
||||||
@ -93,9 +103,21 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1-byte version, then 15 bytes of padding
|
// 1-byte version, then 15 bytes of padding
|
||||||
|
var version int
|
||||||
var p []byte
|
var p []byte
|
||||||
if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' && p[0] != '3' {
|
if p = d.read(16); len(p) != 16 {
|
||||||
return nil, badData
|
return nil, badData
|
||||||
|
} else {
|
||||||
|
switch p[0] {
|
||||||
|
case 0:
|
||||||
|
version = 1
|
||||||
|
case '2':
|
||||||
|
version = 2
|
||||||
|
case '3':
|
||||||
|
version = 3
|
||||||
|
default:
|
||||||
|
return nil, badData
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// six big-endian 32-bit integers:
|
// six big-endian 32-bit integers:
|
||||||
@ -119,11 +141,53 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, badData
|
return nil, badData
|
||||||
}
|
}
|
||||||
|
if uint32(int(nn)) != nn {
|
||||||
|
return nil, badData
|
||||||
|
}
|
||||||
n[i] = int(nn)
|
n[i] = int(nn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have version 2 or 3, then the data is first written out
|
||||||
|
// in a 32-bit format, then written out again in a 64-bit format.
|
||||||
|
// Skip the 32-bit format and read the 64-bit one, as it can
|
||||||
|
// describe a broader range of dates.
|
||||||
|
|
||||||
|
is64 := false
|
||||||
|
if version > 1 {
|
||||||
|
// Skip the 32-bit data.
|
||||||
|
skip := n[NTime]*4 +
|
||||||
|
n[NTime] +
|
||||||
|
n[NZone]*6 +
|
||||||
|
n[NChar] +
|
||||||
|
n[NLeap]*8 +
|
||||||
|
n[NStdWall] +
|
||||||
|
n[NUTCLocal]
|
||||||
|
// Skip the version 2 header that we just read.
|
||||||
|
skip += 4 + 16
|
||||||
|
d.read(skip)
|
||||||
|
|
||||||
|
is64 = true
|
||||||
|
|
||||||
|
// Read the counts again, they can differ.
|
||||||
|
for i := 0; i < 6; i++ {
|
||||||
|
nn, ok := d.big4()
|
||||||
|
if !ok {
|
||||||
|
return nil, badData
|
||||||
|
}
|
||||||
|
if uint32(int(nn)) != nn {
|
||||||
|
return nil, badData
|
||||||
|
}
|
||||||
|
n[i] = int(nn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size := 4
|
||||||
|
if is64 {
|
||||||
|
size = 8
|
||||||
|
}
|
||||||
|
|
||||||
// Transition times.
|
// Transition times.
|
||||||
txtimes := dataIO{d.read(n[NTime] * 4), false}
|
txtimes := dataIO{d.read(n[NTime] * size), false}
|
||||||
|
|
||||||
// Time zone indices for transition times.
|
// Time zone indices for transition times.
|
||||||
txzones := d.read(n[NTime])
|
txzones := d.read(n[NTime])
|
||||||
@ -135,7 +199,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
|||||||
abbrev := d.read(n[NChar])
|
abbrev := d.read(n[NChar])
|
||||||
|
|
||||||
// Leap-second time pairs
|
// Leap-second time pairs
|
||||||
d.read(n[NLeap] * 8)
|
d.read(n[NLeap] * (size + 4))
|
||||||
|
|
||||||
// Whether tx times associated with local time types
|
// Whether tx times associated with local time types
|
||||||
// are specified as standard time or wall time.
|
// are specified as standard time or wall time.
|
||||||
@ -149,10 +213,6 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
|||||||
return nil, badData
|
return nil, badData
|
||||||
}
|
}
|
||||||
|
|
||||||
// If version == 2 or 3, the entire file repeats, this time using
|
|
||||||
// 8-byte ints for txtimes and leap seconds.
|
|
||||||
// We won't need those until 2106.
|
|
||||||
|
|
||||||
// Now we can build up a useful data structure.
|
// Now we can build up a useful data structure.
|
||||||
// First the zone information.
|
// First the zone information.
|
||||||
// utcoff[4] isdst[1] nameindex[1]
|
// utcoff[4] isdst[1] nameindex[1]
|
||||||
@ -163,6 +223,9 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
|||||||
if n, ok = zonedata.big4(); !ok {
|
if n, ok = zonedata.big4(); !ok {
|
||||||
return nil, badData
|
return nil, badData
|
||||||
}
|
}
|
||||||
|
if uint32(int(n)) != n {
|
||||||
|
return nil, badData
|
||||||
|
}
|
||||||
zone[i].offset = int(int32(n))
|
zone[i].offset = int(int32(n))
|
||||||
var b byte
|
var b byte
|
||||||
if b, ok = zonedata.byte(); !ok {
|
if b, ok = zonedata.byte(); !ok {
|
||||||
@ -186,12 +249,21 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
|||||||
// Now the transition time info.
|
// Now the transition time info.
|
||||||
tx := make([]zoneTrans, n[NTime])
|
tx := make([]zoneTrans, n[NTime])
|
||||||
for i := range tx {
|
for i := range tx {
|
||||||
var ok bool
|
var n int64
|
||||||
var n uint32
|
if !is64 {
|
||||||
if n, ok = txtimes.big4(); !ok {
|
if n4, ok := txtimes.big4(); !ok {
|
||||||
return nil, badData
|
return nil, badData
|
||||||
|
} else {
|
||||||
|
n = int64(int32(n4))
|
||||||
}
|
}
|
||||||
tx[i].when = int64(int32(n))
|
} else {
|
||||||
|
if n8, ok := txtimes.big8(); !ok {
|
||||||
|
return nil, badData
|
||||||
|
} else {
|
||||||
|
n = int64(n8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx[i].when = n
|
||||||
if int(txzones[i]) >= len(zone) {
|
if int(txzones[i]) >= len(zone) {
|
||||||
return nil, badData
|
return nil, badData
|
||||||
}
|
}
|
||||||
|
@ -152,3 +152,24 @@ func TestLoadLocationFromTZData(t *testing.T) {
|
|||||||
t.Errorf("return values of LoadLocationFromTZData and LoadLocation don't match")
|
t.Errorf("return values of LoadLocationFromTZData and LoadLocation don't match")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue 30099.
|
||||||
|
func TestEarlyLocation(t *testing.T) {
|
||||||
|
time.ForceZipFileForTesting(true)
|
||||||
|
defer time.ForceZipFileForTesting(false)
|
||||||
|
|
||||||
|
const locName = "America/New_York"
|
||||||
|
loc, err := time.LoadLocation(locName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d := time.Date(1900, time.January, 1, 0, 0, 0, 0, loc)
|
||||||
|
tzName, tzOffset := d.Zone()
|
||||||
|
if want := "EST"; tzName != want {
|
||||||
|
t.Errorf("Zone name == %s, want %s", tzName, want)
|
||||||
|
}
|
||||||
|
if want := -18000; tzOffset != want {
|
||||||
|
t.Errorf("Zone offset == %d, want %d", tzOffset, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user