...

Source file src/time/tzdata/tzdata.go

Documentation: time/tzdata

     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.
     4  
     5  //go:generate go run generate_zipdata.go
     6  
     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.
    11  //
    12  // Importing this package will increase the size of a program by about
    13  // 450 KB.
    14  //
    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.
    18  //
    19  // This package will be automatically imported if you build with
    20  // -tags timetzdata.
    21  package tzdata
    22  
    23  // The test for this package is time/tzdata_test.go.
    24  
    25  import (
    26  	"errors"
    27  	"syscall"
    28  	_ "unsafe" // for go:linkname
    29  )
    30  
    31  // registerLoadFromEmbeddedTZData is defined in package time.
    32  //
    33  //go:linkname registerLoadFromEmbeddedTZData time.registerLoadFromEmbeddedTZData
    34  func registerLoadFromEmbeddedTZData(func(string) (string, error))
    35  
    36  func init() {
    37  	registerLoadFromEmbeddedTZData(loadFromEmbeddedTZData)
    38  }
    39  
    40  // get4s returns the little-endian 32-bit value at the start of s.
    41  func get4s(s string) int {
    42  	if len(s) < 4 {
    43  		return 0
    44  	}
    45  	return int(s[0]) | int(s[1])<<8 | int(s[2])<<16 | int(s[3])<<24
    46  }
    47  
    48  // get2s returns the little-endian 16-bit value at the start of s.
    49  func get2s(s string) int {
    50  	if len(s) < 2 {
    51  		return 0
    52  	}
    53  	return int(s[0]) | int(s[1])<<8
    54  }
    55  
    56  // loadFromEmbeddedTZData returns the contents of the file with the given
    57  // name in an uncompressed zip file, where the contents of the file can
    58  // be found in embeddedTzdata.
    59  // This is similar to time.loadTzinfoFromZip.
    60  func loadFromEmbeddedTZData(name string) (string, error) {
    61  	const (
    62  		zecheader = 0x06054b50
    63  		zcheader  = 0x02014b50
    64  		ztailsize = 22
    65  
    66  		zheadersize = 30
    67  		zheader     = 0x04034b50
    68  	)
    69  
    70  	z := zipdata
    71  
    72  	idx := len(z) - ztailsize
    73  	n := get2s(z[idx+10:])
    74  	idx = get4s(z[idx+16:])
    75  
    76  	for i := 0; i < n; i++ {
    77  		// See time.loadTzinfoFromZip for zip entry layout.
    78  		if get4s(z[idx:]) != zcheader {
    79  			break
    80  		}
    81  		meth := get2s(z[idx+10:])
    82  		size := get4s(z[idx+24:])
    83  		namelen := get2s(z[idx+28:])
    84  		xlen := get2s(z[idx+30:])
    85  		fclen := get2s(z[idx+32:])
    86  		off := get4s(z[idx+42:])
    87  		zname := z[idx+46 : idx+46+namelen]
    88  		idx += 46 + namelen + xlen + fclen
    89  		if zname != name {
    90  			continue
    91  		}
    92  		if meth != 0 {
    93  			return "", errors.New("unsupported compression for " + name + " in embedded tzdata")
    94  		}
    95  
    96  		// See time.loadTzinfoFromZip for zip per-file header layout.
    97  		idx = off
    98  		if get4s(z[idx:]) != zheader ||
    99  			get2s(z[idx+8:]) != meth ||
   100  			get2s(z[idx+26:]) != namelen ||
   101  			z[idx+30:idx+30+namelen] != name {
   102  			return "", errors.New("corrupt embedded tzdata")
   103  		}
   104  		xlen = get2s(z[idx+28:])
   105  		idx += 30 + namelen + xlen
   106  		return z[idx : idx+size], nil
   107  	}
   108  
   109  	return "", syscall.ENOENT
   110  }
   111  

View as plain text