1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 //go:generate go run generate_zipdata.go
7 // Package tzdata provides an embedded copy of the timezone database.
8 // If this package is imported anywhere in the program, then if
9 // the time package cannot find tzdata files on the system,
10 // it will use this embedded information.
12 // Importing this package will increase the size of a program by about
15 // This package should normally be imported by a program's main package,
16 // not by a library. Libraries normally shouldn't decide whether to
17 // include the timezone database in a program.
19 // This package will be automatically imported if you build with
26 _ "unsafe" // for go:linkname
29 // registerLoadFromEmbeddedTZData is defined in package time.
30 //go:linkname registerLoadFromEmbeddedTZData time.registerLoadFromEmbeddedTZData
31 func registerLoadFromEmbeddedTZData(func(string) (string, error))
34 registerLoadFromEmbeddedTZData(loadFromEmbeddedTZData)
37 // get4s returns the little-endian 32-bit value at the start of s.
38 func get4s(s string) int {
42 return int(s[0]) | int(s[1])<<8 | int(s[2])<<16 | int(s[3])<<24
45 // get2s returns the little-endian 16-bit value at the start of s.
46 func get2s(s string) int {
50 return int(s[0]) | int(s[1])<<8
53 // loadFromEmbeddedTZData returns the contents of the file with the given
54 // name in an uncompressed zip file, where the contents of the file can
55 // be found in embeddedTzdata.
56 // This is similar to time.loadTzinfoFromZip.
57 func loadFromEmbeddedTZData(name string) (string, error) {
59 zecheader = 0x06054b50
69 idx := len(z) - ztailsize
70 n := get2s(z[idx+10:])
71 idx = get4s(z[idx+16:])
73 for i := 0; i < n; i++ {
74 // See time.loadTzinfoFromZip for zip entry layout.
75 if get4s(z[idx:]) != zcheader {
78 meth := get2s(z[idx+10:])
79 size := get4s(z[idx+24:])
80 namelen := get2s(z[idx+28:])
81 xlen := get2s(z[idx+30:])
82 fclen := get2s(z[idx+32:])
83 off := get4s(z[idx+42:])
84 zname := z[idx+46 : idx+46+namelen]
85 idx += 46 + namelen + xlen + fclen
90 return "", errors.New("unsupported compression for " + name + " in embedded tzdata")
93 // See time.loadTzinfoFromZip for zip per-file header layout.
95 if get4s(z[idx:]) != zheader ||
96 get2s(z[idx+8:]) != meth ||
97 get2s(z[idx+26:]) != namelen ||
98 z[idx+30:idx+30+namelen] != name {
99 return "", errors.New("corrupt embedded tzdata")
101 xlen = get2s(z[idx+28:])
102 idx += 30 + namelen + xlen
103 return z[idx : idx+size], nil
106 return "", syscall.ENOENT