summaryrefslogtreecommitdiffstats
path: root/src/time/zoneinfo_plan9.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/time/zoneinfo_plan9.go')
-rw-r--r--src/time/zoneinfo_plan9.go142
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"
+}