summaryrefslogtreecommitdiff
path: root/src/pkg/time/zoneinfo_plan9.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/time/zoneinfo_plan9.go')
-rw-r--r--src/pkg/time/zoneinfo_plan9.go152
1 files changed, 117 insertions, 35 deletions
diff --git a/src/pkg/time/zoneinfo_plan9.go b/src/pkg/time/zoneinfo_plan9.go
index 577ef85bd..9c052d42c 100644
--- a/src/pkg/time/zoneinfo_plan9.go
+++ b/src/pkg/time/zoneinfo_plan9.go
@@ -7,69 +7,151 @@
package time
import (
- "os"
- "strconv"
- "strings"
+ "errors"
+ "syscall"
)
-func parseZones(s string) (zt []zonetime) {
- f := strings.Fields(s)
+var badData = errors.New("malformed time zone information")
+
+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 loadZoneData(s string) (l *Location, err error) {
+ f := fields(s)
if len(f) < 4 {
- return
+ if len(f) == 2 && f[0] == "GMT" {
+ return UTC, nil
+ }
+ return nil, badData
}
+ var zones [2]zone
+
// standard timezone offset
- o, err := strconv.Atoi(f[1])
+ o, err := atoi(f[1])
if err != nil {
- return
+ return nil, badData
}
- std := &zone{name: f[0], utcoff: o, isdst: false}
+ zones[0] = zone{name: f[0], offset: o, isDST: false}
// alternate timezone offset
- o, err = strconv.Atoi(f[3])
+ o, err = atoi(f[3])
if err != nil {
- return
+ return nil, badData
}
- dst := &zone{name: f[2], utcoff: o, isdst: true}
+ 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++ {
- z := std
+ zi := 0
if i%2 == 0 {
- z = dst
+ zi = 1
}
- t, err := strconv.Atoi(f[i])
+ t, err := atoi(f[i])
if err != nil {
- return 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 = 1<<63 - 1
+ if i+1 < len(tx) {
+ l.cacheEnd = tx[i+1].when
+ }
+ l.cacheZone = &l.zone[tx[i].index]
}
- t -= std.utcoff
- zt = append(zt, zonetime{time: int32(t), zone: z})
}
- return
+
+ return l, nil
}
-func setupZone() {
- t, err := os.Getenverror("timezone")
+func loadZoneFile(name string) (*Location, error) {
+ b, err := readFile(name)
if err != nil {
- // do nothing: use UTC
- return
+ return nil, err
}
- zones = parseZones(t)
+ return loadZoneData(string(b))
}
-func setupTestingZone() {
- f, err := os.Open("/adm/timezone/US_Pacific")
- if err != nil {
+func initTestingZone() {
+ if z, err := loadZoneFile("/adm/timezone/US_Pacific"); err == nil {
+ localLoc = *z
return
}
- defer f.Close()
- l, _ := f.Seek(0, 2)
- f.Seek(0, 0)
- buf := make([]byte, l)
- _, err = f.Read(buf)
- if err != nil {
- return
+
+ // Fall back to UTC.
+ localLoc.name = "UTC"
+}
+
+func initLocal() {
+ t, ok := syscall.Getenv("timezone")
+ if ok {
+ if z, err := loadZoneData(t); err == nil {
+ localLoc = *z
+ return
+ }
+ } else {
+ if z, err := loadZoneFile("/adm/timezone/local"); err == nil {
+ localLoc = *z
+ localLoc.name = "Local"
+ return
+ }
+ }
+
+ // Fall back to UTC.
+ localLoc.name = "UTC"
+}
+
+func loadLocation(name string) (*Location, error) {
+ if z, err := loadZoneFile("/adm/timezone/" + name); err == nil {
+ return z, nil
}
- zones = parseZones(string(buf))
+ return nil, errors.New("unknown time zone " + name)
}