+++ /dev/null
-// Copyright 2009 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.
-
-package time
-
-import "syscall"
-
-// Sleep pauses the current goroutine for the duration d.
-func Sleep(d Duration)
-
-// readFile reads and returns the content of the named file.
-// It is a trivial implementation of ioutil.ReadFile, reimplemented
-// here to avoid depending on io/ioutil or os.
-func readFile(name string) ([]byte, error) {
- f, err := syscall.Open(name, syscall.O_RDONLY, 0)
- if err != nil {
- return nil, err
- }
- defer syscall.Close(f)
- var (
- buf [4096]byte
- ret []byte
- n int
- )
- for {
- n, err = syscall.Read(f, buf[:])
- if n > 0 {
- ret = append(ret, buf[:n]...)
- }
- if n == 0 || err != nil {
- break
- }
- }
- return ret, err
-}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build plan9
+
package time
+import "syscall"
+
// for testing: whatever interrupts a sleep
func interrupt() {
// cannot predict pid, don't want to kill group
}
+
+// readFile reads and returns the content of the named file.
+// It is a trivial implementation of ioutil.ReadFile, reimplemented
+// here to avoid depending on io/ioutil or os.
+func readFile(name string) ([]byte, error) {
+ f, err := syscall.Open(name, syscall.O_RDONLY)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.Close(f)
+ var (
+ buf [4096]byte
+ ret []byte
+ n int
+ )
+ for {
+ n, err = syscall.Read(f, buf[:])
+ if n > 0 {
+ ret = append(ret, buf[:n]...)
+ }
+ if n == 0 || err != nil {
+ break
+ }
+ }
+ return ret, err
+}
func interrupt() {
syscall.Kill(syscall.Getpid(), syscall.SIGCHLD)
}
+
+// readFile reads and returns the content of the named file.
+// It is a trivial implementation of ioutil.ReadFile, reimplemented
+// here to avoid depending on io/ioutil or os.
+func readFile(name string) ([]byte, error) {
+ f, err := syscall.Open(name, syscall.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.Close(f)
+ var (
+ buf [4096]byte
+ ret []byte
+ n int
+ )
+ for {
+ n, err = syscall.Read(f, buf[:])
+ if n > 0 {
+ ret = append(ret, buf[:n]...)
+ }
+ if n == 0 || err != nil {
+ break
+ }
+ }
+ return ret, err
+}
package time
-//import (
-// "strconv"
-// "strings"
-//)
+import (
+ "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 -= std.utcoff
- zt = append(zt, zonetime{time: int32(t), zone: z})
+ t -= zones[0].offset
+ tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)})
}
- return
+
+ // 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]
+ }
+ }
+
+ return l, nil
}
-func initLocal() {
- 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 initTestingZone() {
- buf, err := readFile("/adm/timezone/US_Pacific")
- if err != nil {
+ if z, err := loadZoneFile("/adm/timezone/US_Pacific"); err == nil {
+ localLoc = *z
return
}
- zones = parseZones(string(buf))
+
+ // 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
+ }
+ return nil, errors.New("unknown time zone " + name)
}