diff options
Diffstat (limited to 'src/time/zoneinfo_plan9.go')
-rw-r--r-- | src/time/zoneinfo_plan9.go | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/time/zoneinfo_plan9.go b/src/time/zoneinfo_plan9.go new file mode 100644 index 0000000..4ae718c --- /dev/null +++ b/src/time/zoneinfo_plan9.go @@ -0,0 +1,142 @@ +// Copyright 2011 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. + +// Parse Plan 9 timezone(2) files. + +package time + +import ( + "runtime" + "syscall" +) + +var zoneSources = []string{ + runtime.GOROOT() + "/lib/time/zoneinfo.zip", +} + +func isSpace(r rune) bool { + return r == ' ' || r == '\t' || r == '\n' +} + +// Copied from strings to avoid a dependency. +func fields(s string) []string { + // First count the fields. + n := 0 + inField := false + for _, rune := range s { + wasInField := inField + inField = !isSpace(rune) + if inField && !wasInField { + n++ + } + } + + // Now create them. + a := make([]string, n) + na := 0 + fieldStart := -1 // Set to -1 when looking for start of field. + for i, rune := range s { + if isSpace(rune) { + if fieldStart >= 0 { + a[na] = s[fieldStart:i] + na++ + fieldStart = -1 + } + } else if fieldStart == -1 { + fieldStart = i + } + } + if fieldStart >= 0 { // Last field might end at EOF. + a[na] = s[fieldStart:] + } + return a +} + +func loadZoneDataPlan9(s string) (l *Location, err error) { + f := fields(s) + if len(f) < 4 { + if len(f) == 2 && f[0] == "GMT" { + return UTC, nil + } + return nil, badData + } + + var zones [2]zone + + // standard timezone offset + o, err := atoi(f[1]) + if err != nil { + return nil, badData + } + zones[0] = zone{name: f[0], offset: o, isDST: false} + + // alternate timezone offset + o, err = atoi(f[3]) + if err != nil { + return nil, badData + } + zones[1] = zone{name: f[2], offset: o, isDST: true} + + // transition time pairs + var tx []zoneTrans + f = f[4:] + for i := 0; i < len(f); i++ { + zi := 0 + if i%2 == 0 { + zi = 1 + } + t, err := atoi(f[i]) + if err != nil { + return nil, badData + } + t -= zones[0].offset + tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)}) + } + + // Committed to succeed. + l = &Location{zone: zones[:], tx: tx} + + // Fill in the cache with information about right now, + // since that will be the most common lookup. + sec, _, _ := now() + for i := range tx { + if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) { + l.cacheStart = tx[i].when + l.cacheEnd = omega + if i+1 < len(tx) { + l.cacheEnd = tx[i+1].when + } + l.cacheZone = &l.zone[tx[i].index] + } + } + + return l, nil +} + +func loadZoneFilePlan9(name string) (*Location, error) { + b, err := readFile(name) + if err != nil { + return nil, err + } + return loadZoneDataPlan9(string(b)) +} + +func initLocal() { + t, ok := syscall.Getenv("timezone") + if ok { + if z, err := loadZoneDataPlan9(t); err == nil { + localLoc = *z + return + } + } else { + if z, err := loadZoneFilePlan9("/adm/timezone/local"); err == nil { + localLoc = *z + localLoc.name = "Local" + return + } + } + + // Fall back to UTC. + localLoc.name = "UTC" +} |