summaryrefslogtreecommitdiff
path: root/src/lib/time
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2009-06-09 09:53:44 -0700
committerRob Pike <r@golang.org>2009-06-09 09:53:44 -0700
commit7249ea4df2b4f12a4e7ed446f270cea87e4ffd34 (patch)
tree7032a11d0cac2ae4d3e90f7a189b575b5a50f848 /src/lib/time
parentacf6ef7a82b3fe61516a1bac4563706552bdf078 (diff)
downloadgolang-7249ea4df2b4f12a4e7ed446f270cea87e4ffd34.tar.gz
mv src/lib to src/pkg
tests: all.bash passes, gobuild still works, godoc still works. R=rsc OCL=30096 CL=30102
Diffstat (limited to 'src/lib/time')
-rw-r--r--src/lib/time/Makefile77
-rw-r--r--src/lib/time/sleep.go17
-rw-r--r--src/lib/time/tick.go62
-rw-r--r--src/lib/time/tick_test.go29
-rw-r--r--src/lib/time/time.go372
-rw-r--r--src/lib/time/time_test.go85
-rw-r--r--src/lib/time/zoneinfo.go285
7 files changed, 0 insertions, 927 deletions
diff --git a/src/lib/time/Makefile b/src/lib/time/Makefile
deleted file mode 100644
index 8d3c3b65f..000000000
--- a/src/lib/time/Makefile
+++ /dev/null
@@ -1,77 +0,0 @@
-# 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.
-
-# DO NOT EDIT. Automatically generated by gobuild.
-# gobuild -m >Makefile
-
-D=
-
-include $(GOROOT)/src/Make.$(GOARCH)
-AR=gopack
-
-default: packages
-
-clean:
- rm -rf *.[$(OS)] *.a [$(OS)].out _obj
-
-test: packages
- gotest
-
-coverage: packages
- gotest
- 6cov -g `pwd` | grep -v '_test\.go:'
-
-%.$O: %.go
- $(GC) -I_obj $*.go
-
-%.$O: %.c
- $(CC) $*.c
-
-%.$O: %.s
- $(AS) $*.s
-
-O1=\
- sleep.$O\
- zoneinfo.$O\
-
-O2=\
- time.$O\
-
-O3=\
- tick.$O\
-
-
-phases: a1 a2 a3
-_obj$D/time.a: phases
-
-a1: $(O1)
- $(AR) grc _obj$D/time.a sleep.$O zoneinfo.$O
- rm -f $(O1)
-
-a2: $(O2)
- $(AR) grc _obj$D/time.a time.$O
- rm -f $(O2)
-
-a3: $(O3)
- $(AR) grc _obj$D/time.a tick.$O
- rm -f $(O3)
-
-
-newpkg: clean
- mkdir -p _obj$D
- $(AR) grc _obj$D/time.a
-
-$(O1): newpkg
-$(O2): a1
-$(O3): a2
-$(O4): a3
-
-nuke: clean
- rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/time.a
-
-packages: _obj$D/time.a
-
-install: packages
- test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
- cp _obj$D/time.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/time.a
diff --git a/src/lib/time/sleep.go b/src/lib/time/sleep.go
deleted file mode 100644
index 3bb76cf47..000000000
--- a/src/lib/time/sleep.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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 (
- "os";
- "syscall";
- "unsafe";
-)
-
-// Sleep pauses the current goroutine for ns nanoseconds.
-// It returns os.EINTR if interrupted.
-func Sleep(ns int64) os.Error {
- return os.ErrnoToError(syscall.Sleep(ns));
-}
diff --git a/src/lib/time/tick.go b/src/lib/time/tick.go
deleted file mode 100644
index 53e2234f8..000000000
--- a/src/lib/time/tick.go
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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";
- "time";
- "unsafe";
-)
-
-// TODO(rsc): This implementation of time.Tick is a
-// simple placeholder. Eventually, there will need to be
-// a single central time server no matter how many tickers
-// are active. There also needs to be a way to cancel a ticker.
-//
-// Also, if timeouts become part of the select statement,
-// perhaps the Ticker is just:
-//
-// func Ticker(ns int64, c chan int64) {
-// for {
-// select { timeout ns: }
-// nsec, err := time.Nanoseconds();
-// c <- nsec;
-// }
-
-func ticker(ns int64, c chan int64) {
- var tv syscall.Timeval;
- now := time.Nanoseconds();
- when := now;
- for {
- when += ns; // next alarm
-
- // if c <- now took too long, skip ahead
- if when < now {
- // one big step
- when += (now-when)/ns * ns;
- }
- for when <= now {
- // little steps until when > now
- when += ns
- }
-
- time.Sleep(when - now);
- now = time.Nanoseconds();
- c <- now;
- }
-}
-
-// Tick creates a synchronous channel that will send the time, in nanoseconds,
-// every ns nanoseconds. It adjusts the intervals to make up for pauses in
-// delivery of the ticks.
-func Tick(ns int64) chan int64 {
- if ns <= 0 {
- return nil
- }
- c := make(chan int64);
- go ticker(ns, c);
- return c;
-}
-
diff --git a/src/lib/time/tick_test.go b/src/lib/time/tick_test.go
deleted file mode 100644
index 0667be679..000000000
--- a/src/lib/time/tick_test.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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 (
- "testing";
- "time";
-)
-
-func TestTick(t *testing.T) {
- const (
- Delta = 100*1e6;
- Count = 10;
- );
- c := Tick(Delta);
- t0 := Nanoseconds();
- for i := 0; i < Count; i++ {
- <-c;
- }
- t1 := Nanoseconds();
- ns := t1 - t0;
- target := int64(Delta*Count);
- slop := target*2/10;
- if ns < target - slop || ns > target + slop {
- t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target));
- }
-}
diff --git a/src/lib/time/time.go b/src/lib/time/time.go
deleted file mode 100644
index ea9b66cbc..000000000
--- a/src/lib/time/time.go
+++ /dev/null
@@ -1,372 +0,0 @@
-// 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.
-
-// The time package provides functionality for measuring and
-// displaying time.
-package time
-
-import (
- "os";
- "time"
-)
-
-// Seconds reports the number of seconds since the Unix epoch,
-// January 1, 1970 00:00:00 UTC.
-func Seconds() int64 {
- sec, nsec, err := os.Time();
- if err != nil {
- panic("time: os.Time: ", err.String());
- }
- return sec
-}
-
-// Nanoseconds reports the number of nanoseconds since the Unix epoch,
-// January 1, 1970 00:00:00 UTC.
-func Nanoseconds() int64 {
- sec, nsec, err := os.Time();
- if err != nil {
- panic("time: os.Time: ", err.String());
- }
- return sec*1e9 + nsec
-}
-
-// Days of the week.
-const (
- Sunday = iota;
- Monday;
- Tuesday;
- Wednesday;
- Thursday;
- Friday;
- Saturday;
-)
-
-// Time is the struct representing a parsed time value.
-type Time struct {
- Year int64; // 2008 is 2008
- Month, Day int; // Sep-17 is 9, 17
- Hour, Minute, Second int; // 10:43:12 is 10, 43, 12
- Weekday int; // Sunday, Monday, ...
- ZoneOffset int; // seconds west of UTC
- Zone string;
-}
-
-var nonleapyear = []int{
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-}
-var leapyear = []int{
- 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-}
-
-func months(year int64) []int {
- if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
- return leapyear
- }
- return nonleapyear
-}
-
-const (
- secondsPerDay = 24*60*60;
-
- daysPer400Years = 365*400+97;
- daysPer100Years = 365*100+24;
- daysPer4Years = 365*4+1;
-
- days1970To2001 = 31*365+8;
-)
-
-// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
-// into a parsed Time value in the UTC time zone.
-func SecondsToUTC(sec int64) *Time {
- t := new(Time);
-
- // Split into time and day.
- day := sec/secondsPerDay;
- sec -= day*secondsPerDay;
- if sec < 0 {
- day--;
- sec += secondsPerDay
- }
-
- // Time
- t.Hour = int(sec/3600);
- t.Minute = int((sec/60)%60);
- t.Second = int(sec%60);
-
- // Day 0 = January 1, 1970 was a Thursday
- t.Weekday = int((day + Thursday) % 7);
- if t.Weekday < 0 {
- t.Weekday += 7
- }
-
- // Change day from 0 = 1970 to 0 = 2001,
- // to make leap year calculations easier
- // (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
- day -= days1970To2001;
-
- year := int64(2001);
- if day < 0 {
- // Go back enough 400 year cycles to make day positive.
- n := -day/daysPer400Years + 1;
- year -= 400*n;
- day += daysPer400Years*n;
- } else {
- // Cut off 400 year cycles.
- n := day/daysPer400Years;
- year += 400*n;
- day -= daysPer400Years*n;
- }
-
- // Cut off 100-year cycles
- n := day/daysPer100Years;
- year += 100*n;
- day -= daysPer100Years*n;
-
- // Cut off 4-year cycles
- n = day/daysPer4Years;
- year += 4*n;
- day -= daysPer4Years*n;
-
- // Cut off non-leap years.
- n = day/365;
- year += n;
- day -= 365*n;
-
- t.Year = year;
-
- // If someone ever needs yearday,
- // tyearday = day (+1?)
-
- months := months(year);
- var m int;
- yday := int(day);
- for m = 0; m < 12 && yday >= months[m]; m++ {
- yday -= months[m]
- }
- t.Month = m+1;
- t.Day = yday+1;
- t.Zone = "UTC";
-
- return t;
-}
-
-// UTC returns the current time as a parsed Time value in the UTC time zone.
-func UTC() *Time {
- return SecondsToUTC(Seconds())
-}
-
-// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
-// into a parsed Time value in the local time zone.
-func SecondsToLocalTime(sec int64) *Time {
- z, offset, err := time.lookupTimezone(sec);
- if err != nil {
- return SecondsToUTC(sec)
- }
- t := SecondsToUTC(sec+int64(offset));
- t.Zone = z;
- t.ZoneOffset = offset;
- return t
-}
-
-// LocalTime returns the current time as a parsed Time value in the local time zone.
-func LocalTime() *Time {
- return SecondsToLocalTime(Seconds())
-}
-
-// Seconds returns the number of seconds since January 1, 1970 represented by the
-// parsed Time value.
-func (t *Time) Seconds() int64 {
- // First, accumulate days since January 1, 2001.
- // Using 2001 instead of 1970 makes the leap-year
- // handling easier (see SecondsToUTC), because
- // it is at the beginning of the 4-, 100-, and 400-year cycles.
- day := int64(0);
-
- // Rewrite year to be >= 2001.
- year := t.Year;
- if year < 2001 {
- n := (2001 - year)/400 + 1;
- year += 400*n;
- day -= daysPer400Years*n;
- }
-
- // Add in days from 400-year cycles.
- n := (year - 2001) / 400;
- year -= 400*n;
- day += daysPer400Years*n;
-
- // Add in 100-year cycles.
- n = (year - 2001) / 100;
- year -= 100*n;
- day += daysPer100Years*n;
-
- // Add in 4-year cycles.
- n = (year - 2001) / 4;
- year -= 4*n;
- day += daysPer4Years*n;
-
- // Add in non-leap years.
- n = year - 2001;
- day += 365*n;
-
- // Add in days this year.
- months := months(t.Year);
- for m := 0; m < t.Month-1; m++ {
- day += int64(months[m])
- }
- day += int64(t.Day - 1);
-
- // Convert days to seconds since January 1, 2001.
- sec := day * secondsPerDay;
-
- // Add in time elapsed today.
- sec += int64(t.Hour) * 3600;
- sec += int64(t.Minute) * 60;
- sec += int64(t.Second);
-
- // Convert from seconds since 2001 to seconds since 1970.
- sec += days1970To2001 * secondsPerDay;
-
- // Account for local time zone.
- sec -= int64(t.ZoneOffset);
- return sec
-}
-
-var longDayNames = []string{
- "Sunday",
- "Monday",
- "Tuesday",
- "Wednesday",
- "Thursday",
- "Friday",
- "Saturday"
-}
-
-var shortDayNames = []string{
- "Sun",
- "Mon",
- "Tue",
- "Wed",
- "Thu",
- "Fri",
- "Sat"
-}
-
-var shortMonthNames = []string{
- "Jan",
- "Feb",
- "Mar",
- "Apr",
- "May",
- "Jun",
- "Jul",
- "Aug",
- "Sep",
- "Oct",
- "Nov",
- "Dec"
-}
-
-func copy(dst []byte, s string) {
- for i := 0; i < len(s); i++ {
- dst[i] = s[i]
- }
-}
-
-func decimal(dst []byte, n int) {
- if n < 0 {
- n = 0
- }
- for i := len(dst)-1; i >= 0; i-- {
- dst[i] = byte(n%10 + '0');
- n /= 10
- }
-}
-
-func addString(buf []byte, bp int, s string) int {
- n := len(s);
- copy(buf[bp:bp+n], s);
- return bp+n
-}
-
-// Just enough of strftime to implement the date formats below.
-// Not exported.
-func format(t *Time, fmt string) string {
- buf := make([]byte, 128);
- bp := 0;
-
- for i := 0; i < len(fmt); i++ {
- if fmt[i] == '%' {
- i++;
- switch fmt[i] {
- case 'A': // %A full weekday name
- bp = addString(buf, bp, longDayNames[t.Weekday]);
- case 'a': // %a abbreviated weekday name
- bp = addString(buf, bp, shortDayNames[t.Weekday]);
- case 'b': // %b abbreviated month name
- bp = addString(buf, bp, shortMonthNames[t.Month-1]);
- case 'd': // %d day of month (01-31)
- decimal(buf[bp:bp+2], t.Day);
- bp += 2;
- case 'e': // %e day of month ( 1-31)
- if t.Day >= 10 {
- decimal(buf[bp:bp+2], t.Day)
- } else {
- buf[bp] = ' ';
- buf[bp+1] = byte(t.Day + '0')
- }
- bp += 2;
- case 'H': // %H hour 00-23
- decimal(buf[bp:bp+2], t.Hour);
- bp += 2;
- case 'M': // %M minute 00-59
- decimal(buf[bp:bp+2], t.Minute);
- bp += 2;
- case 'S': // %S second 00-59
- decimal(buf[bp:bp+2], t.Second);
- bp += 2;
- case 'Y': // %Y year 2008
- decimal(buf[bp:bp+4], int(t.Year));
- bp += 4;
- case 'y': // %y year 08
- decimal(buf[bp:bp+2], int(t.Year%100));
- bp += 2;
- case 'Z':
- bp = addString(buf, bp, t.Zone);
- default:
- buf[bp] = '%';
- buf[bp+1] = fmt[i];
- bp += 2
- }
- } else {
- buf[bp] = fmt[i];
- bp++;
- }
- }
- return string(buf[0:bp])
-}
-
-// Asctime formats the parsed time value in the style of
-// ANSI C asctime: Sun Nov 6 08:49:37 1994
-func (t *Time) Asctime() string {
- return format(t, "%a %b %e %H:%M:%S %Y")
-}
-
-// RFC850 formats the parsed time value in the style of
-// RFC 850: Sunday, 06-Nov-94 08:49:37 UTC
-func (t *Time) RFC850() string {
- return format(t, "%A, %d-%b-%y %H:%M:%S %Z")
-}
-
-// RFC1123 formats the parsed time value in the style of
-// RFC 1123: Sun, 06 Nov 1994 08:49:37 UTC
-func (t *Time) RFC1123() string {
- return format(t, "%a, %d %b %Y %H:%M:%S %Z")
-}
-
-// String formats the parsed time value in the style of
-// date(1) - Sun Nov 6 08:49:37 UTC 1994
-func (t *Time) String() string {
- return format(t, "%a %b %e %H:%M:%S %Z %Y")
-}
diff --git a/src/lib/time/time_test.go b/src/lib/time/time_test.go
deleted file mode 100644
index 41e6736e8..000000000
--- a/src/lib/time/time_test.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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 (
- "os";
- "testing";
- "time";
-)
-
-func init() {
- // Force US Pacific time for daylight-savings
- // tests below (localtests). Needs to be set
- // before the first call into the time library.
- os.Setenv("TZ", "US/Pacific");
-}
-
-type TimeTest struct {
- seconds int64;
- golden Time;
-}
-
-var utctests = []TimeTest {
- TimeTest{0, Time{1970, 1, 1, 0, 0, 0, Thursday, 0, "UTC"}},
- TimeTest{1221681866, Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}},
- TimeTest{-1221681866, Time{1931, 4, 16, 3, 55, 34, Thursday, 0, "UTC"}},
- TimeTest{1e18, Time{31688740476, 10, 23, 1, 46, 40, Friday, 0, "UTC"}},
- TimeTest{-1e18, Time{-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "UTC"}},
- TimeTest{0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, Sunday, 0, "UTC"}},
- TimeTest{-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "UTC"}}
-}
-
-var localtests = []TimeTest {
- TimeTest{0, Time{1969, 12, 31, 16, 0, 0, Wednesday, -8*60*60, "PST"}},
- TimeTest{1221681866, Time{2008, 9, 17, 13, 4, 26, Wednesday, -7*60*60, "PDT"}}
-}
-
-func same(t, u *Time) bool {
- return t.Year == u.Year
- && t.Month == u.Month
- && t.Day == u.Day
- && t.Hour == u.Hour
- && t.Minute == u.Minute
- && t.Second == u.Second
- && t.Weekday == u.Weekday
- && t.ZoneOffset == u.ZoneOffset
- && t.Zone == u.Zone
-}
-
-func TestSecondsToUTC(t *testing.T) {
- for i := 0; i < len(utctests); i++ {
- sec := utctests[i].seconds;
- golden := &utctests[i].golden;
- tm := SecondsToUTC(sec);
- newsec := tm.Seconds();
- if newsec != sec {
- t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec);
- }
- if !same(tm, golden) {
- t.Errorf("SecondsToUTC(%d):", sec);
- t.Errorf(" want=%v", *golden);
- t.Errorf(" have=%v", *tm);
- }
- }
-}
-
-func TestSecondsToLocalTime(t *testing.T) {
- for i := 0; i < len(localtests); i++ {
- sec := localtests[i].seconds;
- golden := &localtests[i].golden;
- tm := SecondsToLocalTime(sec);
- newsec := tm.Seconds();
- if newsec != sec {
- t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec);
- }
- if !same(tm, golden) {
- t.Errorf("SecondsToLocalTime(%d):", sec);
- t.Errorf(" want=%v", *golden);
- t.Errorf(" have=%v", *tm);
- }
- }
-}
-
diff --git a/src/lib/time/zoneinfo.go b/src/lib/time/zoneinfo.go
deleted file mode 100644
index 751afc931..000000000
--- a/src/lib/time/zoneinfo.go
+++ /dev/null
@@ -1,285 +0,0 @@
-// 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.
-
-// Parse "zoneinfo" time zone file.
-// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
-// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
-// and ftp://munnari.oz.au/pub/oldtz/
-
-package time
-
-import (
- "io";
- "once";
- "os"
-)
-
-const (
- maxFileSize = 8192; // actual files are closer to 1K
- headerSize = 4+16+4*7;
-
- zoneDir = "/usr/share/zoneinfo/";
-)
-
-// Errors that can be generated recovering time zone information.
-type TimeZoneError struct {
- os.ErrorString
-}
-
-var errShort = TimeZoneError{ "time: short zone file" }
-var errInvalid = TimeZoneError{ "time: invalid zone file" }
-var errLong = TimeZoneError{ "time: zone file too long" }
-
-// Simple I/O interface to binary blob of data.
-type data struct {
- p []byte;
- error bool;
-}
-
-
-func (d *data) read(n int) []byte {
- if len(d.p) < n {
- d.p = nil;
- d.error = true;
- return nil;
- }
- p := d.p[0:n];
- d.p = d.p[n:len(d.p)];
- return p
-}
-
-func (d *data) big4() (n uint32, ok bool) {
- p := d.read(4);
- if len(p) < 4 {
- d.error = true;
- return 0, false
- }
- return uint32(p[0]) << 24 | uint32(p[1]) << 16 | uint32(p[2]) << 8 | uint32(p[3]), true
-}
-
-func (d *data) byte() (n byte, ok bool) {
- p := d.read(1);
- if len(p) < 1 {
- d.error = true;
- return 0, false
- }
- return p[0], true
-}
-
-
-// Make a string by stopping at the first NUL
-func byteString(p []byte) string {
- for i := 0; i < len(p); i++ {
- if p[i] == 0 {
- return string(p[0:i])
- }
- }
- return string(p)
-}
-
-// Parsed representation
-type zone struct {
- utcoff int;
- isdst bool;
- name string;
-}
-
-type zonetime struct {
- time int32; // transition time, in seconds since 1970 GMT
- zone *zone; // the zone that goes into effect at that time
- isstd, isutc bool; // ignored - no idea what these mean
-}
-
-func parseinfo(bytes []byte) (zt []zonetime, err os.Error) {
- d := data{bytes, false};
-
- // 4-byte magic "TZif"
- if magic := d.read(4); string(magic) != "TZif" {
- return nil, TimeZoneError{ "time: bad zone magic" }
- }
-
- // 1-byte version, then 15 bytes of padding
- var p []byte;
- if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
- return nil, TimeZoneError { "time: bad zone file version" }
- }
- vers := p[0];
-
- // six big-endian 32-bit integers:
- // number of UTC/local indicators
- // number of standard/wall indicators
- // number of leap seconds
- // number of transition times
- // number of local time zones
- // number of characters of time zone abbrev strings
- const (
- NUTCLocal = iota;
- NStdWall;
- NLeap;
- NTime;
- NZone;
- NChar
- )
- var n [6]int;
- for i := 0; i < 6; i++ {
- nn, ok := d.big4();
- if !ok {
- return nil, errShort
- }
- n[i] = int(nn);
- }
-
- // Transition times.
- txtimes := data{d.read(n[NTime]*4), false};
-
- // Time zone indices for transition times.
- txzones := d.read(n[NTime]);
-
- // Zone info structures
- zonedata := data{d.read(n[NZone]*6), false};
-
- // Time zone abbreviations.
- abbrev := d.read(n[NChar]);
-
- // Leap-second time pairs
- leapdata := data{d.read(n[NLeap]*8), false};
-
- // Whether tx times associated with local time types
- // are specified as standard time or wall time.
- isstd := d.read(n[NStdWall]);
-
- // Whether tx times associated with local time types
- // are specified as UTC or local time.
- isutc := d.read(n[NUTCLocal]);
-
- if d.error { // ran out of data
- return nil, errShort
- }
-
- // If version == 2, the entire file repeats, this time using
- // 8-byte ints for txtimes and leap seconds.
- // We won't need those until 2106.
-
- // Now we can build up a useful data structure.
- // First the zone information.
- // utcoff[4] isdst[1] nameindex[1]
- z := make([]zone, n[NZone]);
- for i := 0; i < len(z); i++ {
- var ok bool;
- var n uint32;
- if n, ok = zonedata.big4(); !ok {
- return nil, errShort
- }
- z[i].utcoff = int(n);
- var b byte;
- if b, ok = zonedata.byte(); !ok {
- return nil, errShort
- }
- z[i].isdst = b != 0;
- if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
- return nil, errInvalid
- }
- z[i].name = byteString(abbrev[b:len(abbrev)])
- }
-
- // Now the transition time info.
- zt = make([]zonetime, n[NTime]);
- for i := 0; i < len(zt); i++ {
- var ok bool;
- var n uint32;
- if n, ok = txtimes.big4(); !ok {
- return nil, errShort
- }
- zt[i].time = int32(n);
- if int(txzones[i]) >= len(z) {
- return nil, errInvalid
- }
- zt[i].zone = &z[txzones[i]];
- if i < len(isstd) {
- zt[i].isstd = isstd[i] != 0
- }
- if i < len(isutc) {
- zt[i].isutc = isutc[i] != 0
- }
- }
- return zt, nil
-}
-
-func readfile(name string, max int) (p []byte, err os.Error) {
- f, e := os.Open(name, os.O_RDONLY, 0);
- if e != nil {
- return nil, e;
- }
- p = make([]byte, max);
- n, err1 := io.FullRead(f, p);
- f.Close();
- if err1 == nil { // too long
- return nil, errLong;
- }
- if err1 != io.ErrEOF {
- return nil, err1;
- }
- return p[0:n], nil;
-}
-
-func readinfofile(name string) ([]zonetime, os.Error) {
- buf, err := readfile(name, maxFileSize);
- if err != nil {
- goto Error;
- }
- tx, err := parseinfo(buf);
- if err != nil {
- goto Error;
- }
- return tx, nil;
-
-Error:
- if tzerr, ok := err.(TimeZoneError); ok {
- tzerr.ErrorString = os.ErrorString(tzerr.String() + ": " + name)
- }
- return nil, err
-}
-
-var zones []zonetime
-var zoneerr os.Error
-
-func setupZone() {
- // consult $TZ to find the time zone to use.
- // no $TZ means use the system default /etc/localtime.
- // $TZ="" means use UTC.
- // $TZ="foo" means use /usr/share/zoneinfo/foo.
-
- tz, err := os.Getenv("TZ");
- var file string;
- switch {
- case err == os.ENOENV:
- zones, zoneerr = readinfofile("/etc/localtime");
- case err != nil:
- zoneerr = err;
- case len(tz) > 0:
- zones, zoneerr = readinfofile(zoneDir + tz);
- case len(tz) == 0:
- // do nothing: use UTC
- }
-}
-
-func lookupTimezone(sec int64) (zone string, offset int, err os.Error) {
- once.Do(setupZone);
- if zoneerr != nil || len(zones) == 0 {
- return "UTC", 0, zoneerr
- }
-
- // Binary search for entry with largest time <= sec
- tz := zones;
- for len(tz) > 1 {
- m := len(tz)/2;
- if sec < int64(tz[m].time) {
- tz = tz[0:m]
- } else {
- tz = tz[m:len(tz)]
- }
- }
- z := tz[0].zone;
- return z.name, z.utcoff, nil
-}