github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/src/time/zoneinfo_plan9.go (about) 1 // Copyright 2011 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 // Parse Plan 9 timezone(2) files. 6 7 package time 8 9 import ( 10 "runtime" 11 "syscall" 12 ) 13 14 var zoneSources = []string{ 15 runtime.GOROOT() + "/lib/time/zoneinfo.zip", 16 } 17 18 func isSpace(r rune) bool { 19 return r == ' ' || r == '\t' || r == '\n' 20 } 21 22 // Copied from strings to avoid a dependency. 23 func fields(s string) []string { 24 // First count the fields. 25 n := 0 26 inField := false 27 for _, rune := range s { 28 wasInField := inField 29 inField = !isSpace(rune) 30 if inField && !wasInField { 31 n++ 32 } 33 } 34 35 // Now create them. 36 a := make([]string, n) 37 na := 0 38 fieldStart := -1 // Set to -1 when looking for start of field. 39 for i, rune := range s { 40 if isSpace(rune) { 41 if fieldStart >= 0 { 42 a[na] = s[fieldStart:i] 43 na++ 44 fieldStart = -1 45 } 46 } else if fieldStart == -1 { 47 fieldStart = i 48 } 49 } 50 if fieldStart >= 0 { // Last field might end at EOF. 51 a[na] = s[fieldStart:] 52 } 53 return a 54 } 55 56 func loadZoneDataPlan9(s string) (l *Location, err error) { 57 f := fields(s) 58 if len(f) < 4 { 59 if len(f) == 2 && f[0] == "GMT" { 60 return UTC, nil 61 } 62 return nil, badData 63 } 64 65 var zones [2]zone 66 67 // standard timezone offset 68 o, err := atoi(f[1]) 69 if err != nil { 70 return nil, badData 71 } 72 zones[0] = zone{name: f[0], offset: o, isDST: false} 73 74 // alternate timezone offset 75 o, err = atoi(f[3]) 76 if err != nil { 77 return nil, badData 78 } 79 zones[1] = zone{name: f[2], offset: o, isDST: true} 80 81 // transition time pairs 82 var tx []zoneTrans 83 f = f[4:] 84 for i := 0; i < len(f); i++ { 85 zi := 0 86 if i%2 == 0 { 87 zi = 1 88 } 89 t, err := atoi(f[i]) 90 if err != nil { 91 return nil, badData 92 } 93 t -= zones[0].offset 94 tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)}) 95 } 96 97 // Committed to succeed. 98 l = &Location{zone: zones[:], tx: tx} 99 100 // Fill in the cache with information about right now, 101 // since that will be the most common lookup. 102 sec, _, _ := now() 103 for i := range tx { 104 if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) { 105 l.cacheStart = tx[i].when 106 l.cacheEnd = omega 107 if i+1 < len(tx) { 108 l.cacheEnd = tx[i+1].when 109 } 110 l.cacheZone = &l.zone[tx[i].index] 111 } 112 } 113 114 return l, nil 115 } 116 117 func loadZoneFilePlan9(name string) (*Location, error) { 118 b, err := readFile(name) 119 if err != nil { 120 return nil, err 121 } 122 return loadZoneDataPlan9(string(b)) 123 } 124 125 func initLocal() { 126 t, ok := syscall.Getenv("timezone") 127 if ok { 128 if z, err := loadZoneDataPlan9(t); err == nil { 129 localLoc = *z 130 return 131 } 132 } else { 133 if z, err := loadZoneFilePlan9("/adm/timezone/local"); err == nil { 134 localLoc = *z 135 localLoc.name = "Local" 136 return 137 } 138 } 139 140 // Fall back to UTC. 141 localLoc.name = "UTC" 142 }