summaryrefslogtreecommitdiffstats
path: root/src/time/tzdata/tzdata.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/time/tzdata/tzdata.go')
-rw-r--r--src/time/tzdata/tzdata.go109
1 files changed, 109 insertions, 0 deletions
diff --git a/src/time/tzdata/tzdata.go b/src/time/tzdata/tzdata.go
new file mode 100644
index 0000000..25725bd
--- /dev/null
+++ b/src/time/tzdata/tzdata.go
@@ -0,0 +1,109 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run generate_zipdata.go
+
+// Package tzdata provides an embedded copy of the timezone database.
+// If this package is imported anywhere in the program, then if
+// the time package cannot find tzdata files on the system,
+// it will use this embedded information.
+//
+// Importing this package will increase the size of a program by about
+// 450 KB.
+//
+// This package should normally be imported by a program's main package,
+// not by a library. Libraries normally shouldn't decide whether to
+// include the timezone database in a program.
+//
+// This package will be automatically imported if you build with
+// -tags timetzdata.
+package tzdata
+
+// The test for this package is time/tzdata_test.go.
+
+import (
+ "errors"
+ "syscall"
+ _ "unsafe" // for go:linkname
+)
+
+// registerLoadFromEmbeddedTZData is defined in package time.
+//go:linkname registerLoadFromEmbeddedTZData time.registerLoadFromEmbeddedTZData
+func registerLoadFromEmbeddedTZData(func(string) (string, error))
+
+func init() {
+ registerLoadFromEmbeddedTZData(loadFromEmbeddedTZData)
+}
+
+// get4s returns the little-endian 32-bit value at the start of s.
+func get4s(s string) int {
+ if len(s) < 4 {
+ return 0
+ }
+ return int(s[0]) | int(s[1])<<8 | int(s[2])<<16 | int(s[3])<<24
+}
+
+// get2s returns the little-endian 16-bit value at the start of s.
+func get2s(s string) int {
+ if len(s) < 2 {
+ return 0
+ }
+ return int(s[0]) | int(s[1])<<8
+}
+
+// loadFromEmbeddedTZData returns the contents of the file with the given
+// name in an uncompressed zip file, where the contents of the file can
+// be found in embeddedTzdata.
+// This is similar to time.loadTzinfoFromZip.
+func loadFromEmbeddedTZData(name string) (string, error) {
+ const (
+ zecheader = 0x06054b50
+ zcheader = 0x02014b50
+ ztailsize = 22
+
+ zheadersize = 30
+ zheader = 0x04034b50
+ )
+
+ z := zipdata
+
+ idx := len(z) - ztailsize
+ n := get2s(z[idx+10:])
+ idx = get4s(z[idx+16:])
+
+ for i := 0; i < n; i++ {
+ // See time.loadTzinfoFromZip for zip entry layout.
+ if get4s(z[idx:]) != zcheader {
+ break
+ }
+ meth := get2s(z[idx+10:])
+ size := get4s(z[idx+24:])
+ namelen := get2s(z[idx+28:])
+ xlen := get2s(z[idx+30:])
+ fclen := get2s(z[idx+32:])
+ off := get4s(z[idx+42:])
+ zname := z[idx+46 : idx+46+namelen]
+ idx += 46 + namelen + xlen + fclen
+ if zname != name {
+ continue
+ }
+ if meth != 0 {
+ return "", errors.New("unsupported compression for " + name + " in embedded tzdata")
+ }
+
+ // See time.loadTzinfoFromZip for zip per-file header layout.
+ idx = off
+ if get4s(z[idx:]) != zheader ||
+ get2s(z[idx+8:]) != meth ||
+ get2s(z[idx+26:]) != namelen ||
+ z[idx+30:idx+30+namelen] != name {
+ return "", errors.New("corrupt embedded tzdata")
+ }
+ xlen = get2s(z[idx+28:])
+ idx += 30 + namelen + xlen
+ return z[idx : idx+size], nil
+ }
+
+ return "", syscall.ENOENT
+}