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