diff options
Diffstat (limited to 'src/pkg/time')
-rw-r--r-- | src/pkg/time/Makefile | 41 | ||||
-rw-r--r-- | src/pkg/time/format.go | 637 | ||||
-rw-r--r-- | src/pkg/time/sleep.go | 177 | ||||
-rw-r--r-- | src/pkg/time/sleep_test.go | 189 | ||||
-rw-r--r-- | src/pkg/time/sys.go | 51 | ||||
-rw-r--r-- | src/pkg/time/sys_plan9.go | 18 | ||||
-rw-r--r-- | src/pkg/time/sys_posix.go | 18 | ||||
-rw-r--r-- | src/pkg/time/tick.go | 177 | ||||
-rw-r--r-- | src/pkg/time/tick_test.go | 58 | ||||
-rw-r--r-- | src/pkg/time/time.go | 204 | ||||
-rw-r--r-- | src/pkg/time/time_test.go | 414 | ||||
-rw-r--r-- | src/pkg/time/zoneinfo_plan9.go | 59 | ||||
-rw-r--r-- | src/pkg/time/zoneinfo_posix.go | 62 | ||||
-rw-r--r-- | src/pkg/time/zoneinfo_unix.go | 215 | ||||
-rw-r--r-- | src/pkg/time/zoneinfo_windows.go | 192 |
15 files changed, 0 insertions, 2512 deletions
diff --git a/src/pkg/time/Makefile b/src/pkg/time/Makefile deleted file mode 100644 index 023e8775e..000000000 --- a/src/pkg/time/Makefile +++ /dev/null @@ -1,41 +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. - -include ../../Make.inc - -TARG=time -GOFILES=\ - format.go\ - sleep.go\ - sys.go\ - tick.go\ - time.go\ - -GOFILES_freebsd=\ - sys_posix.go\ - zoneinfo_posix.go\ - zoneinfo_unix.go\ - -GOFILES_darwin=\ - sys_posix.go\ - zoneinfo_posix.go\ - zoneinfo_unix.go\ - -GOFILES_linux=\ - sys_posix.go\ - zoneinfo_posix.go\ - zoneinfo_unix.go\ - -GOFILES_windows=\ - sys_posix.go\ - zoneinfo_windows.go\ - -GOFILES_plan9=\ - sys_plan9.go\ - zoneinfo_posix.go\ - zoneinfo_plan9.go\ - -GOFILES+=$(GOFILES_$(GOOS)) - -include ../../Make.pkg diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go deleted file mode 100644 index 26f40d141..000000000 --- a/src/pkg/time/format.go +++ /dev/null @@ -1,637 +0,0 @@ -package time - -import ( - "bytes" - "os" - "strconv" -) - -const ( - numeric = iota - alphabetic - separator - plus - minus -) - -// These are predefined layouts for use in Time.Format. -// The standard time used in the layouts is: -// Mon Jan 2 15:04:05 MST 2006 (MST is GMT-0700) -// which is Unix time 1136243045. -// (Think of it as 01/02 03:04:05PM '06 -0700.) -// To define your own format, write down what the standard -// time would look like formatted your way. -// -// Within the format string, an underscore _ represents a space that may be -// replaced by a digit if the following number (a day) has two digits; for -// compatibility with fixed-width Unix time formats. -// -// Numeric time zone offsets format as follows: -// -0700 ±hhmm -// -07:00 ±hh:mm -// Replacing the sign in the format with a Z triggers -// the ISO 8601 behavior of printing Z instead of an -// offset for the UTC zone. Thus: -// Z0700 Z or ±hhmm -// Z07:00 Z or ±hh:mm -const ( - ANSIC = "Mon Jan _2 15:04:05 2006" - UnixDate = "Mon Jan _2 15:04:05 MST 2006" - RubyDate = "Mon Jan 02 15:04:05 -0700 2006" - RFC822 = "02 Jan 06 1504 MST" - // RFC822 with Zulu time. - RFC822Z = "02 Jan 06 1504 -0700" - RFC850 = "Monday, 02-Jan-06 15:04:05 MST" - RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" - RFC3339 = "2006-01-02T15:04:05Z07:00" - Kitchen = "3:04PM" -) - -const ( - stdLongMonth = "January" - stdMonth = "Jan" - stdNumMonth = "1" - stdZeroMonth = "01" - stdLongWeekDay = "Monday" - stdWeekDay = "Mon" - stdDay = "2" - stdUnderDay = "_2" - stdZeroDay = "02" - stdHour = "15" - stdHour12 = "3" - stdZeroHour12 = "03" - stdMinute = "4" - stdZeroMinute = "04" - stdSecond = "5" - stdZeroSecond = "05" - stdLongYear = "2006" - stdYear = "06" - stdPM = "PM" - stdpm = "pm" - stdTZ = "MST" - stdISO8601TZ = "Z0700" // prints Z for UTC - stdISO8601ColonTZ = "Z07:00" // prints Z for UTC - stdNumTZ = "-0700" // always numeric - stdNumShortTZ = "-07" // always numeric - stdNumColonTZ = "-07:00" // always numeric -) - -// nextStdChunk finds the first occurrence of a std string in -// layout and returns the text before, the std string, and the text after. -func nextStdChunk(layout string) (prefix, std, suffix string) { - for i := 0; i < len(layout); i++ { - switch layout[i] { - case 'J': // January, Jan - if len(layout) >= i+7 && layout[i:i+7] == stdLongMonth { - return layout[0:i], stdLongMonth, layout[i+7:] - } - if len(layout) >= i+3 && layout[i:i+3] == stdMonth { - return layout[0:i], stdMonth, layout[i+3:] - } - - case 'M': // Monday, Mon, MST - if len(layout) >= i+6 && layout[i:i+6] == stdLongWeekDay { - return layout[0:i], stdLongWeekDay, layout[i+6:] - } - if len(layout) >= i+3 { - if layout[i:i+3] == stdWeekDay { - return layout[0:i], stdWeekDay, layout[i+3:] - } - if layout[i:i+3] == stdTZ { - return layout[0:i], stdTZ, layout[i+3:] - } - } - - case '0': // 01, 02, 03, 04, 05, 06 - if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' { - return layout[0:i], layout[i : i+2], layout[i+2:] - } - - case '1': // 15, 1 - if len(layout) >= i+2 && layout[i+1] == '5' { - return layout[0:i], stdHour, layout[i+2:] - } - return layout[0:i], stdNumMonth, layout[i+1:] - - case '2': // 2006, 2 - if len(layout) >= i+4 && layout[i:i+4] == stdLongYear { - return layout[0:i], stdLongYear, layout[i+4:] - } - return layout[0:i], stdDay, layout[i+1:] - - case '_': // _2 - if len(layout) >= i+2 && layout[i+1] == '2' { - return layout[0:i], stdUnderDay, layout[i+2:] - } - - case '3', '4', '5': // 3, 4, 5 - return layout[0:i], layout[i : i+1], layout[i+1:] - - case 'P': // PM - if len(layout) >= i+2 && layout[i+1] == 'M' { - return layout[0:i], layout[i : i+2], layout[i+2:] - } - - case 'p': // pm - if len(layout) >= i+2 && layout[i+1] == 'm' { - return layout[0:i], layout[i : i+2], layout[i+2:] - } - - case '-': // -0700, -07:00, -07 - if len(layout) >= i+5 && layout[i:i+5] == stdNumTZ { - return layout[0:i], layout[i : i+5], layout[i+5:] - } - if len(layout) >= i+6 && layout[i:i+6] == stdNumColonTZ { - return layout[0:i], layout[i : i+6], layout[i+6:] - } - if len(layout) >= i+3 && layout[i:i+3] == stdNumShortTZ { - return layout[0:i], layout[i : i+3], layout[i+3:] - } - case 'Z': // Z0700, Z07:00 - if len(layout) >= i+5 && layout[i:i+5] == stdISO8601TZ { - return layout[0:i], layout[i : i+5], layout[i+5:] - } - if len(layout) >= i+6 && layout[i:i+6] == stdISO8601ColonTZ { - return layout[0:i], layout[i : i+6], layout[i+6:] - } - } - } - return layout, "", "" -} - -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", -} - -var longMonthNames = []string{ - "---", - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", -} - -func lookup(tab []string, val string) (int, string, os.Error) { - for i, v := range tab { - if len(val) >= len(v) && val[0:len(v)] == v { - return i, val[len(v):], nil - } - } - return -1, val, errBad -} - -func pad(i int, padding string) string { - s := strconv.Itoa(i) - if i < 10 { - s = padding + s - } - return s -} - -func zeroPad(i int) string { return pad(i, "0") } - -// Format returns a textual representation of the time value formatted -// according to layout. The layout defines the format by showing the -// representation of a standard time, which is then used to describe -// the time to be formatted. Predefined layouts ANSIC, UnixDate, -// RFC3339 and others describe standard representations. For more -// information about the formats, see the documentation for ANSIC. -func (t *Time) Format(layout string) string { - b := new(bytes.Buffer) - // Each iteration generates one std value. - for { - prefix, std, suffix := nextStdChunk(layout) - b.WriteString(prefix) - if std == "" { - break - } - var p string - switch std { - case stdYear: - p = zeroPad(int(t.Year % 100)) - case stdLongYear: - p = strconv.Itoa64(t.Year) - case stdMonth: - p = shortMonthNames[t.Month] - case stdLongMonth: - p = longMonthNames[t.Month] - case stdNumMonth: - p = strconv.Itoa(t.Month) - case stdZeroMonth: - p = zeroPad(t.Month) - case stdWeekDay: - p = shortDayNames[t.Weekday] - case stdLongWeekDay: - p = longDayNames[t.Weekday] - case stdDay: - p = strconv.Itoa(t.Day) - case stdUnderDay: - p = pad(t.Day, " ") - case stdZeroDay: - p = zeroPad(t.Day) - case stdHour: - p = zeroPad(t.Hour) - case stdHour12: - // Noon is 12PM, midnight is 12AM. - hr := t.Hour % 12 - if hr == 0 { - hr = 12 - } - p = strconv.Itoa(hr) - case stdZeroHour12: - // Noon is 12PM, midnight is 12AM. - hr := t.Hour % 12 - if hr == 0 { - hr = 12 - } - p = zeroPad(hr) - case stdMinute: - p = strconv.Itoa(t.Minute) - case stdZeroMinute: - p = zeroPad(t.Minute) - case stdSecond: - p = strconv.Itoa(t.Second) - case stdZeroSecond: - p = zeroPad(t.Second) - case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumColonTZ: - // Ugly special case. We cheat and take the "Z" variants - // to mean "the time zone as formatted for ISO 8601". - if t.ZoneOffset == 0 && std[0] == 'Z' { - p = "Z" - break - } - zone := t.ZoneOffset / 60 // convert to minutes - if zone < 0 { - p = "-" - zone = -zone - } else { - p = "+" - } - p += zeroPad(zone / 60) - if std == stdISO8601ColonTZ || std == stdNumColonTZ { - p += ":" - } - p += zeroPad(zone % 60) - case stdPM: - if t.Hour >= 12 { - p = "PM" - } else { - p = "AM" - } - case stdpm: - if t.Hour >= 12 { - p = "pm" - } else { - p = "am" - } - case stdTZ: - if t.Zone != "" { - p = t.Zone - } else { - // No time zone known for this time, but we must print one. - // Use the -0700 format. - zone := t.ZoneOffset / 60 // convert to minutes - if zone < 0 { - p = "-" - zone = -zone - } else { - p = "+" - } - p += zeroPad(zone / 60) - p += zeroPad(zone % 60) - } - } - b.WriteString(p) - layout = suffix - } - return b.String() -} - -// String returns a Unix-style representation of the time value. -func (t *Time) String() string { - if t == nil { - return "<nil>" - } - return t.Format(UnixDate) -} - -var errBad = os.NewError("bad") // just a marker; not returned to user - -// ParseError describes a problem parsing a time string. -type ParseError struct { - Layout string - Value string - LayoutElem string - ValueElem string - Message string -} - -// String is the string representation of a ParseError. -func (e *ParseError) String() string { - if e.Message == "" { - return "parsing time " + - strconv.Quote(e.Value) + " as " + - strconv.Quote(e.Layout) + ": cannot parse " + - strconv.Quote(e.ValueElem) + " as " + - strconv.Quote(e.LayoutElem) - } - return "parsing time " + - strconv.Quote(e.Value) + e.Message -} - -// getnum parses s[0:1] or s[0:2] (fixed forces the latter) -// as a decimal integer and returns the integer and the -// remainder of the string. -func getnum(s string, fixed bool) (int, string, os.Error) { - if len(s) == 0 || s[0] < '0' || s[0] > '9' { - return 0, s, errBad - } - if len(s) == 1 || s[1] < '0' || s[1] > '9' { - if fixed { - return 0, s, errBad - } - return int(s[0] - '0'), s[1:], nil - } - return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil -} - -func cutspace(s string) string { - for len(s) > 0 && s[0] == ' ' { - s = s[1:] - } - return s -} - -// skip removes the given prefix from value, -// treating runs of space characters as equivalent. -func skip(value, prefix string) (string, os.Error) { - for len(prefix) > 0 { - if prefix[0] == ' ' { - if len(value) > 0 && value[0] != ' ' { - return "", errBad - } - prefix = cutspace(prefix) - value = cutspace(value) - continue - } - if len(value) == 0 || value[0] != prefix[0] { - return "", errBad - } - prefix = prefix[1:] - value = value[1:] - } - return value, nil -} - -// Parse parses a formatted string and returns the time value it represents. -// The layout defines the format by showing the representation of a standard -// time, which is then used to describe the string to be parsed. Predefined -// layouts ANSIC, UnixDate, RFC3339 and others describe standard -// representations.For more information about the formats, see the -// documentation for ANSIC. -// -// Only those elements present in the value will be set in the returned time -// structure. Also, if the input string represents an inconsistent time -// (such as having the wrong day of the week), the returned value will also -// be inconsistent. In any case, the elements of the returned time will be -// sane: hours in 0..23, minutes in 0..59, day of month in 0..31, etc. -// Years must be in the range 0000..9999. -func Parse(alayout, avalue string) (*Time, os.Error) { - var t Time - rangeErrString := "" // set if a value is out of range - amSet := false // do we need to subtract 12 from the hour for midnight? - pmSet := false // do we need to add 12 to the hour? - layout, value := alayout, avalue - // Each iteration processes one std value. - for { - var err os.Error - prefix, std, suffix := nextStdChunk(layout) - value, err = skip(value, prefix) - if err != nil { - return nil, &ParseError{alayout, avalue, prefix, value, ""} - } - if len(std) == 0 { - if len(value) != 0 { - return nil, &ParseError{alayout, avalue, "", value, ": extra text: " + value} - } - break - } - layout = suffix - var p string - switch std { - case stdYear: - if len(value) < 2 { - err = errBad - break - } - p, value = value[0:2], value[2:] - t.Year, err = strconv.Atoi64(p) - if t.Year >= 69 { // Unix time starts Dec 31 1969 in some time zones - t.Year += 1900 - } else { - t.Year += 2000 - } - case stdLongYear: - if len(value) < 4 || value[0] < '0' || value[0] > '9' { - err = errBad - break - } - p, value = value[0:4], value[4:] - t.Year, err = strconv.Atoi64(p) - case stdMonth: - t.Month, value, err = lookup(shortMonthNames, value) - case stdLongMonth: - t.Month, value, err = lookup(longMonthNames, value) - case stdNumMonth, stdZeroMonth: - t.Month, value, err = getnum(value, std == stdZeroMonth) - if t.Month <= 0 || 12 < t.Month { - rangeErrString = "month" - } - case stdWeekDay: - t.Weekday, value, err = lookup(shortDayNames, value) - case stdLongWeekDay: - t.Weekday, value, err = lookup(longDayNames, value) - case stdDay, stdUnderDay, stdZeroDay: - if std == stdUnderDay && len(value) > 0 && value[0] == ' ' { - value = value[1:] - } - t.Day, value, err = getnum(value, std == stdZeroDay) - if t.Day < 0 || 31 < t.Day { - // TODO: be more thorough in date check? - rangeErrString = "day" - } - case stdHour: - t.Hour, value, err = getnum(value, false) - if t.Hour < 0 || 24 <= t.Hour { - rangeErrString = "hour" - } - case stdHour12, stdZeroHour12: - t.Hour, value, err = getnum(value, std == stdZeroHour12) - if t.Hour < 0 || 12 < t.Hour { - rangeErrString = "hour" - } - case stdMinute, stdZeroMinute: - t.Minute, value, err = getnum(value, std == stdZeroMinute) - if t.Minute < 0 || 60 <= t.Minute { - rangeErrString = "minute" - } - case stdSecond, stdZeroSecond: - t.Second, value, err = getnum(value, std == stdZeroSecond) - if t.Second < 0 || 60 <= t.Second { - rangeErrString = "second" - } - case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ: - if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' { - value = value[1:] - t.Zone = "UTC" - break - } - var sign, hh, mm string - if std == stdISO8601ColonTZ || std == stdNumColonTZ { - if len(value) < 6 { - err = errBad - break - } - if value[3] != ':' { - err = errBad - break - } - sign, hh, mm, value = value[0:1], value[1:3], value[4:6], value[6:] - } else if std == stdNumShortTZ { - if len(value) < 3 { - err = errBad - break - } - sign, hh, mm, value = value[0:1], value[1:3], "00", value[3:] - } else { - if len(value) < 5 { - err = errBad - break - } - sign, hh, mm, value = value[0:1], value[1:3], value[3:5], value[5:] - } - var hr, min int - hr, err = strconv.Atoi(hh) - if err == nil { - min, err = strconv.Atoi(mm) - } - t.ZoneOffset = (hr*60 + min) * 60 // offset is in seconds - switch sign[0] { - case '+': - case '-': - t.ZoneOffset = -t.ZoneOffset - default: - err = errBad - } - case stdPM: - if len(value) < 2 { - err = errBad - break - } - p, value = value[0:2], value[2:] - switch p { - case "PM": - pmSet = true - case "AM": - amSet = true - default: - err = errBad - } - case stdpm: - if len(value) < 2 { - err = errBad - break - } - p, value = value[0:2], value[2:] - switch p { - case "pm": - pmSet = true - case "am": - amSet = true - default: - err = errBad - } - case stdTZ: - // Does it look like a time zone? - if len(value) >= 3 && value[0:3] == "UTC" { - t.Zone, value = value[0:3], value[3:] - break - } - - if len(value) >= 3 && value[2] == 'T' { - p, value = value[0:3], value[3:] - } else if len(value) >= 4 && value[3] == 'T' { - p, value = value[0:4], value[4:] - } else { - err = errBad - break - } - for i := 0; i < len(p); i++ { - if p[i] < 'A' || 'Z' < p[i] { - err = errBad - } - } - if err != nil { - break - } - // It's a valid format. - t.Zone = p - // Can we find its offset? - if offset, found := lookupByName(p); found { - t.ZoneOffset = offset - } - } - if rangeErrString != "" { - return nil, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"} - } - if err != nil { - return nil, &ParseError{alayout, avalue, std, value, ""} - } - } - if pmSet && t.Hour < 12 { - t.Hour += 12 - } else if amSet && t.Hour == 12 { - t.Hour = 0 - } - return &t, nil -} diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go deleted file mode 100644 index 314622d0d..000000000 --- a/src/pkg/time/sleep.go +++ /dev/null @@ -1,177 +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 ( - "container/heap" - "sync" -) - -// The Timer type represents a single event. -// When the Timer expires, the current time will be sent on C -// unless the Timer represents an AfterFunc event. -type Timer struct { - C <-chan int64 - t int64 // The absolute time that the event should fire. - f func(int64) // The function to call when the event fires. - i int // The event's index inside eventHeap. -} - -type timerHeap []*Timer - -// forever is the absolute time (in ns) of an event that is forever away. -const forever = 1 << 62 - -// maxSleepTime is the maximum length of time that a sleeper -// sleeps for before checking if it is defunct. -const maxSleepTime = 1e9 - -var ( - // timerMutex guards the variables inside this var group. - timerMutex sync.Mutex - - // timers holds a binary heap of pending events, terminated with a sentinel. - timers timerHeap - - // currentSleeper is an ever-incrementing counter which represents - // the current sleeper. It allows older sleepers to detect that they are - // defunct and exit. - currentSleeper int64 -) - -func init() { - timers.Push(&Timer{t: forever}) // sentinel -} - -// NewTimer creates a new Timer that will send -// the current time on its channel after at least ns nanoseconds. -func NewTimer(ns int64) *Timer { - c := make(chan int64, 1) - e := after(ns, func(t int64) { c <- t }) - e.C = c - return e -} - -// After waits at least ns nanoseconds before sending the current time -// on the returned channel. -// It is equivalent to NewTimer(ns).C. -func After(ns int64) <-chan int64 { - return NewTimer(ns).C -} - -// AfterFunc waits at least ns nanoseconds before calling f -// in its own goroutine. It returns a Timer that can -// be used to cancel the call using its Stop method. -func AfterFunc(ns int64, f func()) *Timer { - return after(ns, func(_ int64) { - go f() - }) -} - -// Stop prevents the Timer from firing. -// It returns true if the call stops the timer, false if the timer has already -// expired or stopped. -func (e *Timer) Stop() (ok bool) { - timerMutex.Lock() - // Avoid removing the first event in the queue so that - // we don't start a new sleeper unnecessarily. - if e.i > 0 { - heap.Remove(timers, e.i) - } - ok = e.f != nil - e.f = nil - timerMutex.Unlock() - return -} - -// after is the implementation of After and AfterFunc. -// When the current time is after ns, it calls f with the current time. -// It assumes that f will not block. -func after(ns int64, f func(int64)) (e *Timer) { - now := Nanoseconds() - t := now + ns - if ns > 0 && t < now { - panic("time: time overflow") - } - timerMutex.Lock() - t0 := timers[0].t - e = &Timer{nil, t, f, -1} - heap.Push(timers, e) - // Start a new sleeper if the new event is before - // the first event in the queue. If the length of time - // until the new event is at least maxSleepTime, - // then we're guaranteed that the sleeper will wake up - // in time to service it, so no new sleeper is needed. - if t0 > t && (t0 == forever || ns < maxSleepTime) { - currentSleeper++ - go sleeper(currentSleeper) - } - timerMutex.Unlock() - return -} - -// sleeper continually looks at the earliest event in the queue, waits until it happens, -// then removes any events in the queue that are due. It stops when the queue -// is empty or when another sleeper has been started. -func sleeper(sleeperId int64) { - timerMutex.Lock() - e := timers[0] - t := Nanoseconds() - for e.t != forever { - if dt := e.t - t; dt > 0 { - if dt > maxSleepTime { - dt = maxSleepTime - } - timerMutex.Unlock() - sysSleep(dt) - timerMutex.Lock() - if currentSleeper != sleeperId { - // Another sleeper has been started, making this one redundant. - break - } - } - e = timers[0] - t = Nanoseconds() - for t >= e.t { - if e.f != nil { - e.f(t) - e.f = nil - } - heap.Pop(timers) - e = timers[0] - } - } - timerMutex.Unlock() -} - -func (timerHeap) Len() int { - return len(timers) -} - -func (timerHeap) Less(i, j int) bool { - return timers[i].t < timers[j].t -} - -func (timerHeap) Swap(i, j int) { - timers[i], timers[j] = timers[j], timers[i] - timers[i].i = i - timers[j].i = j -} - -func (timerHeap) Push(x interface{}) { - e := x.(*Timer) - e.i = len(timers) - timers = append(timers, e) -} - -func (timerHeap) Pop() interface{} { - // TODO: possibly shrink array. - n := len(timers) - 1 - e := timers[n] - timers[n] = nil - timers = timers[0:n] - e.i = -1 - return e -} diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go deleted file mode 100644 index a4a1a429f..000000000 --- a/src/pkg/time/sleep_test.go +++ /dev/null @@ -1,189 +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_test - -import ( - "fmt" - "os" - "syscall" - "testing" - "sort" - . "time" -) - -func TestSleep(t *testing.T) { - const delay = int64(100e6) - go func() { - Sleep(delay / 2) - syscall.Kill(os.Getpid(), syscall.SIGCHLD) - }() - start := Nanoseconds() - Sleep(delay) - duration := Nanoseconds() - start - if duration < delay { - t.Fatalf("Sleep(%d) slept for only %d ns", delay, duration) - } -} - -// Test the basic function calling behavior. Correct queueing -// behavior is tested elsewhere, since After and AfterFunc share -// the same code. -func TestAfterFunc(t *testing.T) { - i := 10 - c := make(chan bool) - var f func() - f = func() { - i-- - if i >= 0 { - AfterFunc(0, f) - Sleep(1e9) - } else { - c <- true - } - } - - AfterFunc(0, f) - <-c -} - -func BenchmarkAfterFunc(b *testing.B) { - i := b.N - c := make(chan bool) - var f func() - f = func() { - i-- - if i >= 0 { - AfterFunc(0, f) - } else { - c <- true - } - } - - AfterFunc(0, f) - <-c -} - -func BenchmarkAfter(b *testing.B) { - for i := 0; i < b.N; i++ { - <-After(1) - } -} - -func BenchmarkStop(b *testing.B) { - for i := 0; i < b.N; i++ { - NewTimer(1e9).Stop() - } -} - -func TestAfter(t *testing.T) { - const delay = int64(100e6) - start := Nanoseconds() - end := <-After(delay) - if duration := Nanoseconds() - start; duration < delay { - t.Fatalf("After(%d) slept for only %d ns", delay, duration) - } - if min := start + delay; end < min { - t.Fatalf("After(%d) expect >= %d, got %d", delay, min, end) - } -} - -func TestAfterTick(t *testing.T) { - const ( - Delta = 100 * 1e6 - Count = 10 - ) - t0 := Nanoseconds() - for i := 0; i < Count; i++ { - <-After(Delta) - } - 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)) - } -} - -func TestAfterStop(t *testing.T) { - const msec = 1e6 - AfterFunc(100*msec, func() {}) - t0 := NewTimer(50 * msec) - c1 := make(chan bool, 1) - t1 := AfterFunc(150*msec, func() { c1 <- true }) - c2 := After(200 * msec) - if !t0.Stop() { - t.Fatalf("failed to stop event 0") - } - if !t1.Stop() { - t.Fatalf("failed to stop event 1") - } - <-c2 - select { - case <-t0.C: - t.Fatalf("event 0 was not stopped") - case <-c1: - t.Fatalf("event 1 was not stopped") - default: - } - if t1.Stop() { - t.Fatalf("Stop returned true twice") - } -} - -func TestAfterQueuing(t *testing.T) { - // This test flakes out on some systems, - // so we'll try it a few times before declaring it a failure. - const attempts = 3 - err := os.NewError("!=nil") - for i := 0; i < attempts && err != nil; i++ { - if err = testAfterQueuing(t); err != nil { - t.Logf("attempt %v failed: %v", i, err) - } - } - if err != nil { - t.Fatal(err) - } -} - -var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, 0} - -type afterResult struct { - slot int - t int64 -} - -func await(slot int, result chan<- afterResult, ac <-chan int64) { - result <- afterResult{slot, <-ac} -} - -func testAfterQueuing(t *testing.T) os.Error { - const ( - Delta = 100 * 1e6 - ) - // make the result channel buffered because we don't want - // to depend on channel queueing semantics that might - // possibly change in the future. - result := make(chan afterResult, len(slots)) - - t0 := Nanoseconds() - for _, slot := range slots { - go await(slot, result, After(int64(slot)*Delta)) - } - sort.Ints(slots) - for _, slot := range slots { - r := <-result - if r.slot != slot { - return fmt.Errorf("after queue got slot %d, expected %d", r.slot, slot) - } - ns := r.t - t0 - target := int64(slot * Delta) - slop := int64(Delta) / 4 - if ns < target-slop || ns > target+slop { - return fmt.Errorf("after queue slot %d arrived at %g, expected [%g,%g]", slot, float64(ns), float64(target-slop), float64(target+slop)) - } - } - return nil -} diff --git a/src/pkg/time/sys.go b/src/pkg/time/sys.go deleted file mode 100644 index 9fde3b3b6..000000000 --- a/src/pkg/time/sys.go +++ /dev/null @@ -1,51 +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" - -// Seconds reports the number of seconds since the Unix epoch, -// January 1, 1970 00:00:00 UTC. -func Seconds() int64 { - sec, _, err := os.Time() - if err != nil { - panic(err) - } - 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(err) - } - return sec*1e9 + nsec -} - -// Sleep pauses the current goroutine for at least ns nanoseconds. -// Higher resolution sleeping may be provided by syscall.Nanosleep -// on some operating systems. -func Sleep(ns int64) os.Error { - _, err := sleep(Nanoseconds(), ns) - return err -} - -// sleep takes the current time and a duration, -// pauses for at least ns nanoseconds, and -// returns the current time and an error. -func sleep(t, ns int64) (int64, os.Error) { - // TODO(cw): use monotonic-time once it's available - end := t + ns - for t < end { - err := sysSleep(end - t) - if err != nil { - return 0, err - } - t = Nanoseconds() - } - return t, nil -} diff --git a/src/pkg/time/sys_plan9.go b/src/pkg/time/sys_plan9.go deleted file mode 100644 index abe8649a2..000000000 --- a/src/pkg/time/sys_plan9.go +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -package time - -import ( - "os" - "syscall" -) - -func sysSleep(t int64) os.Error { - err := syscall.Sleep(t) - if err != nil { - return os.NewSyscallError("sleep", err) - } - return nil -} diff --git a/src/pkg/time/sys_posix.go b/src/pkg/time/sys_posix.go deleted file mode 100644 index 0d1eb72fc..000000000 --- a/src/pkg/time/sys_posix.go +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -package time - -import ( - "os" - "syscall" -) - -func sysSleep(t int64) os.Error { - errno := syscall.Sleep(t) - if errno != 0 && errno != syscall.EINTR { - return os.NewSyscallError("sleep", errno) - } - return nil -} diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go deleted file mode 100644 index 852bae9c9..000000000 --- a/src/pkg/time/tick.go +++ /dev/null @@ -1,177 +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" - "sync" -) - -// A Ticker holds a synchronous channel that delivers `ticks' of a clock -// at intervals. -type Ticker struct { - C <-chan int64 // The channel on which the ticks are delivered. - c chan<- int64 // The same channel, but the end we use. - ns int64 - shutdown chan bool // Buffered channel used to signal shutdown. - nextTick int64 - next *Ticker -} - -// Stop turns off a ticker. After Stop, no more ticks will be sent. -func (t *Ticker) Stop() { - select { - case t.shutdown <- true: - // ok - default: - // Stop in progress already - } -} - -// Tick is a convenience wrapper for NewTicker providing access to the ticking -// channel only. Useful for clients that have no need to shut down the ticker. -func Tick(ns int64) <-chan int64 { - if ns <= 0 { - return nil - } - return NewTicker(ns).C -} - -type alarmer struct { - wakeUp chan bool // wakeup signals sent/received here - wakeMeAt chan int64 - wakeTime int64 -} - -// Set alarm to go off at time ns, if not already set earlier. -func (a *alarmer) set(ns int64) { - switch { - case a.wakeTime > ns: - // Next tick we expect is too late; shut down the late runner - // and (after fallthrough) start a new wakeLoop. - close(a.wakeMeAt) - fallthrough - case a.wakeMeAt == nil: - // There's no wakeLoop, start one. - a.wakeMeAt = make(chan int64) - a.wakeUp = make(chan bool, 1) - go wakeLoop(a.wakeMeAt, a.wakeUp) - fallthrough - case a.wakeTime == 0: - // Nobody else is waiting; it's just us. - a.wakeTime = ns - a.wakeMeAt <- ns - default: - // There's already someone scheduled. - } -} - -// Channel to notify tickerLoop of new Tickers being created. -var newTicker chan *Ticker - -func startTickerLoop() { - newTicker = make(chan *Ticker) - go tickerLoop() -} - -// wakeLoop delivers ticks at scheduled times, sleeping until the right moment. -// If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new -// wakeLoop and signal that this one is done by closing the wakeMeAt channel. -func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) { - for wakeAt := range wakeMeAt { - Sleep(wakeAt - Nanoseconds()) - wakeUp <- true - } -} - -// A single tickerLoop serves all ticks to Tickers. It waits for two events: -// either the creation of a new Ticker or a tick from the alarm, -// signaling a time to wake up one or more Tickers. -func tickerLoop() { - // Represents the next alarm to be delivered. - var alarm alarmer - var now, wakeTime int64 - var tickers *Ticker - for { - select { - case t := <-newTicker: - // Add Ticker to list - t.next = tickers - tickers = t - // Arrange for a new alarm if this one precedes the existing one. - alarm.set(t.nextTick) - case <-alarm.wakeUp: - now = Nanoseconds() - wakeTime = now + 1e15 // very long in the future - var prev *Ticker = nil - // Scan list of tickers, delivering updates to those - // that need it and determining the next wake time. - // TODO(r): list should be sorted in time order. - for t := tickers; t != nil; t = t.next { - select { - case <-t.shutdown: - // Ticker is done; remove it from list. - if prev == nil { - tickers = t.next - } else { - prev.next = t.next - } - continue - default: - } - if t.nextTick <= now { - if len(t.c) == 0 { - // Only send if there's room. We must not block. - // The channel is allocated with a one-element - // buffer, which is sufficient: if he hasn't picked - // up the last tick, no point in sending more. - t.c <- now - } - t.nextTick += t.ns - if t.nextTick <= now { - // Still behind; advance in one big step. - t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns - } - } - if t.nextTick < wakeTime { - wakeTime = t.nextTick - } - prev = t - } - if tickers != nil { - // Please send wakeup at earliest required time. - // If there are no tickers, don't bother. - alarm.wakeTime = wakeTime - alarm.wakeMeAt <- wakeTime - } else { - alarm.wakeTime = 0 - } - } - } -} - -var onceStartTickerLoop sync.Once - -// NewTicker returns a new Ticker containing a 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. The value of -// ns must be greater than zero; if not, NewTicker will panic. -func NewTicker(ns int64) *Ticker { - if ns <= 0 { - panic(os.NewError("non-positive interval for NewTicker")) - } - c := make(chan int64, 1) // See comment on send in tickerLoop - t := &Ticker{ - C: c, - c: c, - ns: ns, - shutdown: make(chan bool, 1), - nextTick: Nanoseconds() + ns, - } - onceStartTickerLoop.Do(startTickerLoop) - // must be run in background so global Tickers can be created - go func() { newTicker <- t }() - return t -} diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go deleted file mode 100644 index 4dcb63956..000000000 --- a/src/pkg/time/tick_test.go +++ /dev/null @@ -1,58 +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_test - -import ( - "testing" - . "time" -) - -func TestTicker(t *testing.T) { - const ( - Delta = 100 * 1e6 - Count = 10 - ) - ticker := NewTicker(Delta) - t0 := Nanoseconds() - for i := 0; i < Count; i++ { - <-ticker.C - } - ticker.Stop() - 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)) - } - // Now test that the ticker stopped - Sleep(2 * Delta) - select { - case <-ticker.C: - t.Fatal("Ticker did not shut down") - default: - // ok - } -} - -// Test that a bug tearing down a ticker has been fixed. This routine should not deadlock. -func TestTeardown(t *testing.T) { - for i := 0; i < 3; i++ { - ticker := NewTicker(1e8) - <-ticker.C - ticker.Stop() - } -} - -func BenchmarkTicker(b *testing.B) { - ticker := NewTicker(1) - b.ResetTimer() - b.StartTimer() - for i := 0; i < b.N; i++ { - <-ticker.C - } - b.StopTimer() - ticker.Stop() -} diff --git a/src/pkg/time/time.go b/src/pkg/time/time.go deleted file mode 100644 index a0480786a..000000000 --- a/src/pkg/time/time.go +++ /dev/null @@ -1,204 +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 provides functionality for measuring and displaying time. -package time - -// 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 // 2006 is 2006 - Month, Day int // Jan-2 is 1, 2 - Hour, Minute, Second int // 15:04:05 is 15, 4, 5. - Weekday int // Sunday, Monday, ... - ZoneOffset int // seconds east of UTC, e.g. -7*60*60 for -0700 - Zone string // e.g., "MST" -} - -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 - } - - // Cut off 400 year cycles. - n := day / daysPer400Years - year += 400 * n - day -= daysPer400Years * n - - // Cut off 100-year cycles - n = day / daysPer100Years - if n > 3 { // happens on last day of 400th year - n = 3 - } - year += 100 * n - day -= daysPer100Years * n - - // Cut off 4-year cycles - n = day / daysPer4Years - if n > 24 { // happens on last day of 100th year - n = 24 - } - year += 4 * n - day -= daysPer4Years * n - - // Cut off non-leap years. - n = day / 365 - if n > 3 { // happens on last day of 4th year - n = 3 - } - 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 := lookupTimezone(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 -} diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go deleted file mode 100644 index eec8a7a5c..000000000 --- a/src/pkg/time/time_test.go +++ /dev/null @@ -1,414 +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_test - -import ( - "os" - "strings" - "testing" - "testing/quick" - . "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", "America/Los_Angeles") -} - -// We should be in PST/PDT, but if the time zone files are missing we -// won't be. The purpose of this test is to at least explain why some of -// the subsequent tests fail. -func TestZoneData(t *testing.T) { - lt := LocalTime() - // PST is 8 hours west, PDT is 7 hours west. We could use the name but it's not unique. - if off := lt.ZoneOffset; off != -8*60*60 && off != -7*60*60 { - t.Errorf("Unable to find US Pacific time zone data for testing; time zone is %q offset %d", lt.Zone, off) - t.Error("Likely problem: the time zone files have not been installed.") - } -} - -type TimeTest struct { - seconds int64 - golden Time -} - -var utctests = []TimeTest{ - {0, Time{1970, 1, 1, 0, 0, 0, Thursday, 0, "UTC"}}, - {1221681866, Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}}, - {-1221681866, Time{1931, 4, 16, 3, 55, 34, Thursday, 0, "UTC"}}, - {-11644473600, Time{1601, 1, 1, 0, 0, 0, Monday, 0, "UTC"}}, - {599529660, Time{1988, 12, 31, 0, 1, 0, Saturday, 0, "UTC"}}, - {978220860, Time{2000, 12, 31, 0, 1, 0, Sunday, 0, "UTC"}}, - {1e18, Time{31688740476, 10, 23, 1, 46, 40, Friday, 0, "UTC"}}, - {-1e18, Time{-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "UTC"}}, - {0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, Sunday, 0, "UTC"}}, - {-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "UTC"}}, -} - -var localtests = []TimeTest{ - {0, Time{1969, 12, 31, 16, 0, 0, Wednesday, -8 * 60 * 60, "PST"}}, - {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) - } - } -} - -func TestSecondsToUTCAndBack(t *testing.T) { - f := func(sec int64) bool { return SecondsToUTC(sec).Seconds() == sec } - f32 := func(sec int32) bool { return f(int64(sec)) } - cfg := &quick.Config{MaxCount: 10000} - - // Try a reasonable date first, then the huge ones. - if err := quick.Check(f32, cfg); err != nil { - t.Fatal(err) - } - if err := quick.Check(f, cfg); err != nil { - t.Fatal(err) - } -} - -type TimeFormatTest struct { - time Time - formattedValue string -} - -var rfc3339Formats = []TimeFormatTest{ - {Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}, "2008-09-17T20:04:26Z"}, - {Time{1994, 9, 17, 20, 4, 26, Wednesday, -18000, "EST"}, "1994-09-17T20:04:26-05:00"}, - {Time{2000, 12, 26, 1, 15, 6, Wednesday, 15600, "OTO"}, "2000-12-26T01:15:06+04:20"}, -} - -func TestRFC3339Conversion(t *testing.T) { - for _, f := range rfc3339Formats { - if f.time.Format(RFC3339) != f.formattedValue { - t.Error("RFC3339:") - t.Errorf(" want=%+v", f.formattedValue) - t.Errorf(" have=%+v", f.time.Format(RFC3339)) - } - } -} - -type FormatTest struct { - name string - format string - result string -} - -var formatTests = []FormatTest{ - {"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"}, - {"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"}, - {"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"}, - {"RFC822", RFC822, "04 Feb 09 2100 PST"}, - {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"}, - {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"}, - {"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"}, - {"Kitchen", Kitchen, "9:00PM"}, - {"am/pm", "3pm", "9pm"}, - {"AM/PM", "3PM", "9PM"}, - {"two-digit year", "06 01 02", "09 02 04"}, -} - -func TestFormat(t *testing.T) { - // The numeric time represents Thu Feb 4 21:00:57 PST 2010 - time := SecondsToLocalTime(1233810057) - for _, test := range formatTests { - result := time.Format(test.format) - if result != test.result { - t.Errorf("%s expected %q got %q", test.name, test.result, result) - } - } -} - -type ParseTest struct { - name string - format string - value string - hasTZ bool // contains a time zone - hasWD bool // contains a weekday - yearSign int64 // sign of year -} - -var parseTests = []ParseTest{ - {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1}, - {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1}, - {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1}, - {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1}, - {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1}, - {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1}, - {"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1}, - // Amount of white space should not matter. - {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1}, - {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1}, -} - -func TestParse(t *testing.T) { - for _, test := range parseTests { - time, err := Parse(test.format, test.value) - if err != nil { - t.Errorf("%s error: %v", test.name, err) - } else { - checkTime(time, &test, t) - } - } -} - -var rubyTests = []ParseTest{ - {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1}, - // Ignore the time zone in the test. If it parses, it'll be OK. - {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1}, - {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1}, - {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1}, -} - -// Problematic time zone format needs special tests. -func TestRubyParse(t *testing.T) { - for _, test := range rubyTests { - time, err := Parse(test.format, test.value) - if err != nil { - t.Errorf("%s error: %v", test.name, err) - } else { - checkTime(time, &test, t) - } - } -} - -func checkTime(time *Time, test *ParseTest, t *testing.T) { - // The time should be Thu Feb 4 21:00:57 PST 2010 - if test.yearSign*time.Year != 2010 { - t.Errorf("%s: bad year: %d not %d", test.name, time.Year, 2010) - } - if time.Month != 2 { - t.Errorf("%s: bad month: %d not %d", test.name, time.Month, 2) - } - if time.Day != 4 { - t.Errorf("%s: bad day: %d not %d", test.name, time.Day, 4) - } - if time.Hour != 21 { - t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour, 21) - } - if time.Minute != 0 { - t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute, 0) - } - if time.Second != 57 { - t.Errorf("%s: bad second: %d not %d", test.name, time.Second, 57) - } - if test.hasTZ && time.ZoneOffset != -28800 { - t.Errorf("%s: bad tz offset: %d not %d", test.name, time.ZoneOffset, -28800) - } - if test.hasWD && time.Weekday != 4 { - t.Errorf("%s: bad weekday: %d not %d", test.name, time.Weekday, 4) - } -} - -func TestFormatAndParse(t *testing.T) { - const fmt = "Mon MST " + RFC3339 // all fields - f := func(sec int64) bool { - t1 := SecondsToLocalTime(sec) - if t1.Year < 1000 || t1.Year > 9999 { - // not required to work - return true - } - t2, err := Parse(fmt, t1.Format(fmt)) - if err != nil { - t.Errorf("error: %s", err) - return false - } - if !same(t1, t2) { - t.Errorf("different: %q %q", t1, t2) - return false - } - return true - } - f32 := func(sec int32) bool { return f(int64(sec)) } - cfg := &quick.Config{MaxCount: 10000} - - // Try a reasonable date first, then the huge ones. - if err := quick.Check(f32, cfg); err != nil { - t.Fatal(err) - } - if err := quick.Check(f, cfg); err != nil { - t.Fatal(err) - } -} - -type ParseErrorTest struct { - format string - value string - expect string // must appear within the error -} - -var parseErrorTests = []ParseErrorTest{ - {ANSIC, "Feb 4 21:00:60 2010", "parse"}, // cannot parse Feb as Mon - {ANSIC, "Thu Feb 4 21:00:57 @2010", "parse"}, - {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"}, - {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"}, - {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"}, -} - -func TestParseErrors(t *testing.T) { - for _, test := range parseErrorTests { - _, err := Parse(test.format, test.value) - if err == nil { - t.Errorf("expected error for %q %q", test.format, test.value) - } else if strings.Index(err.String(), test.expect) < 0 { - t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err) - } - } -} - -func TestNoonIs12PM(t *testing.T) { - noon := Time{Hour: 12} - const expect = "12:00PM" - got := noon.Format("3:04PM") - if got != expect { - t.Errorf("got %q; expect %q", got, expect) - } - got = noon.Format("03:04PM") - if got != expect { - t.Errorf("got %q; expect %q", got, expect) - } -} - -func TestMidnightIs12AM(t *testing.T) { - midnight := Time{Hour: 0} - expect := "12:00AM" - got := midnight.Format("3:04PM") - if got != expect { - t.Errorf("got %q; expect %q", got, expect) - } - got = midnight.Format("03:04PM") - if got != expect { - t.Errorf("got %q; expect %q", got, expect) - } -} - -func Test12PMIsNoon(t *testing.T) { - noon, err := Parse("3:04PM", "12:00PM") - if err != nil { - t.Fatal("error parsing date:", err) - } - if noon.Hour != 12 { - t.Errorf("got %d; expect 12", noon.Hour) - } - noon, err = Parse("03:04PM", "12:00PM") - if err != nil { - t.Fatal("error parsing date:", err) - } - if noon.Hour != 12 { - t.Errorf("got %d; expect 12", noon.Hour) - } -} - -func Test12AMIsMidnight(t *testing.T) { - midnight, err := Parse("3:04PM", "12:00AM") - if err != nil { - t.Fatal("error parsing date:", err) - } - if midnight.Hour != 0 { - t.Errorf("got %d; expect 0", midnight.Hour) - } - midnight, err = Parse("03:04PM", "12:00AM") - if err != nil { - t.Fatal("error parsing date:", err) - } - if midnight.Hour != 0 { - t.Errorf("got %d; expect 0", midnight.Hour) - } -} - -// Check that a time without a Zone still produces a (numeric) time zone -// when formatted with MST as a requested zone. -func TestMissingZone(t *testing.T) { - time, err := Parse(RubyDate, "Tue Feb 02 16:10:03 -0500 2006") - if err != nil { - t.Fatal("error parsing date:", err) - } - expect := "Tue Feb 2 16:10:03 -0500 2006" // -0500 not EST - str := time.Format(UnixDate) // uses MST as its time zone - if str != expect { - t.Errorf("expected %q got %q", expect, str) - } -} - -func TestMinutesInTimeZone(t *testing.T) { - time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006") - if err != nil { - t.Fatal("error parsing date:", err) - } - expected := (1*60 + 23) * 60 - if time.ZoneOffset != expected { - t.Errorf("ZoneOffset incorrect, expected %d got %d", expected, time.ZoneOffset) - } -} - -func BenchmarkSeconds(b *testing.B) { - for i := 0; i < b.N; i++ { - Seconds() - } -} - -func BenchmarkNanoseconds(b *testing.B) { - for i := 0; i < b.N; i++ { - Nanoseconds() - } -} - -func BenchmarkFormat(b *testing.B) { - time := SecondsToLocalTime(1265346057) - for i := 0; i < b.N; i++ { - time.Format("Mon Jan 2 15:04:05 2006") - } -} - -func BenchmarkParse(b *testing.B) { - for i := 0; i < b.N; i++ { - Parse(ANSIC, "Mon Jan 2 15:04:05 2006") - } -} diff --git a/src/pkg/time/zoneinfo_plan9.go b/src/pkg/time/zoneinfo_plan9.go deleted file mode 100644 index 3c3e7c424..000000000 --- a/src/pkg/time/zoneinfo_plan9.go +++ /dev/null @@ -1,59 +0,0 @@ -// 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 ( - "os" - "strconv" - "strings" -) - -func parseZones(s string) (zt []zonetime) { - f := strings.Fields(s) - if len(f) < 4 { - return - } - - // standard timezone offset - o, err := strconv.Atoi(f[1]) - if err != nil { - return - } - std := &zone{name: f[0], utcoff: o, isdst: false} - - // alternate timezone offset - o, err = strconv.Atoi(f[3]) - if err != nil { - return - } - dst := &zone{name: f[2], utcoff: o, isdst: true} - - // transition time pairs - f = f[4:] - for i := 0; i < len(f); i++ { - z := std - if i%2 == 0 { - z = dst - } - t, err := strconv.Atoi(f[i]) - if err != nil { - return nil - } - t -= std.utcoff - zt = append(zt, zonetime{time: int32(t), zone: z}) - } - return -} - -func setupZone() { - t, err := os.Getenverror("timezone") - if err != nil { - // do nothing: use UTC - return - } - zones = parseZones(t) -} diff --git a/src/pkg/time/zoneinfo_posix.go b/src/pkg/time/zoneinfo_posix.go deleted file mode 100644 index b49216410..000000000 --- a/src/pkg/time/zoneinfo_posix.go +++ /dev/null @@ -1,62 +0,0 @@ -// 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. - -package time - -import "sync" - -// 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 -} - -var zones []zonetime -var onceSetupZone sync.Once - -// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location. -func lookupTimezone(sec int64) (zone string, offset int) { - onceSetupZone.Do(setupZone) - if len(zones) == 0 { - return "UTC", 0 - } - - // 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:] - } - } - z := tz[0].zone - return z.name, z.utcoff -} - -// lookupByName returns the time offset for the -// time zone with the given abbreviation. It only considers -// time zones that apply to the current system. -// For example, for a system configured as being in New York, -// it only recognizes "EST" and "EDT". -// For a system in San Francisco, "PST" and "PDT". -// For a system in Sydney, "EST" and "EDT", though they have -// different meanings than they do in New York. -func lookupByName(name string) (off int, found bool) { - onceSetupZone.Do(setupZone) - for _, z := range zones { - if name == z.zone.name { - return z.zone.utcoff, true - } - } - return 0, false -} diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go deleted file mode 100644 index 2a83e0c16..000000000 --- a/src/pkg/time/zoneinfo_unix.go +++ /dev/null @@ -1,215 +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/ioutil" - "os" -) - -const ( - headerSize = 4 + 16 + 4*7 -) - -// 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:] - 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) -} - -func parseinfo(bytes []byte) (zt []zonetime, ok bool) { - d := data{bytes, false} - - // 4-byte magic "TZif" - if magic := d.read(4); string(magic) != "TZif" { - return nil, false - } - - // 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, false - } - - // 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, false - } - 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 - d.read(n[NLeap] * 8) - - // 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, false - } - - // 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, false - } - z[i].utcoff = int(n) - var b byte - if b, ok = zonedata.byte(); !ok { - return nil, false - } - z[i].isdst = b != 0 - if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) { - return nil, false - } - z[i].name = byteString(abbrev[b:]) - } - - // 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, false - } - zt[i].time = int32(n) - if int(txzones[i]) >= len(z) { - return nil, false - } - 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, true -} - -func readinfofile(name string) ([]zonetime, bool) { - buf, err := ioutil.ReadFile(name) - if err != nil { - return nil, false - } - return parseinfo(buf) -} - -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. - // Many systems use /usr/share/zoneinfo, Solaris 2 has - // /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ. - zoneDirs := []string{"/usr/share/zoneinfo/", - "/usr/share/lib/zoneinfo/", - "/usr/lib/locale/TZ/"} - - tz, err := os.Getenverror("TZ") - switch { - case err == os.ENOENV: - zones, _ = readinfofile("/etc/localtime") - case len(tz) > 0: - for _, zoneDir := range zoneDirs { - var ok bool - if zones, ok = readinfofile(zoneDir + tz); ok { - break - } - } - case len(tz) == 0: - // do nothing: use UTC - } -} diff --git a/src/pkg/time/zoneinfo_windows.go b/src/pkg/time/zoneinfo_windows.go deleted file mode 100644 index 83afdfb02..000000000 --- a/src/pkg/time/zoneinfo_windows.go +++ /dev/null @@ -1,192 +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" - "sync" - "os" -) - -// BUG(brainman): The Windows implementation assumes that -// this year's rules for daylight savings time apply to all previous -// and future years as well. - -// TODO(brainman): use GetDynamicTimeZoneInformation, whenever possible (Vista and up), -// to improve on situation described in the bug above. - -type zone struct { - name string - offset int - year int64 - month, day, dayofweek int - hour, minute, second int - abssec int64 - prev *zone -} - -// Populate zone struct with Windows supplied information. Returns true, if data is valid. -func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uint16) (dateisgood bool) { - z.name = syscall.UTF16ToString(name) - z.offset = int(bias) - z.year = int64(d.Year) - z.month = int(d.Month) - z.day = int(d.Day) - z.dayofweek = int(d.DayOfWeek) - z.hour = int(d.Hour) - z.minute = int(d.Minute) - z.second = int(d.Second) - dateisgood = d.Month != 0 - if dateisgood { - z.offset += int(biasdelta) - } - z.offset = -z.offset * 60 - return -} - -// Pre-calculate cutoff time in seconds since the Unix epoch, if data is supplied in "absolute" format. -func (z *zone) preCalculateAbsSec() { - if z.year != 0 { - z.abssec = (&Time{z.year, int(z.month), int(z.day), int(z.hour), int(z.minute), int(z.second), 0, 0, ""}).Seconds() - // Time given is in "local" time. Adjust it for "utc". - z.abssec -= int64(z.prev.offset) - } -} - -// Convert zone cutoff time to sec in number of seconds since the Unix epoch, given particular year. -func (z *zone) cutoffSeconds(year int64) int64 { - // Windows specifies daylight savings information in "day in month" format: - // z.month is month number (1-12) - // z.dayofweek is appropriate weekday (Sunday=0 to Saturday=6) - // z.day is week within the month (1 to 5, where 5 is last week of the month) - // z.hour, z.minute and z.second are absolute time - t := &Time{year, int(z.month), 1, int(z.hour), int(z.minute), int(z.second), 0, 0, ""} - t = SecondsToUTC(t.Seconds()) - i := int(z.dayofweek) - t.Weekday - if i < 0 { - i += 7 - } - t.Day += i - if week := int(z.day) - 1; week < 4 { - t.Day += week * 7 - } else { - // "Last" instance of the day. - t.Day += 4 * 7 - if t.Day > months(year)[t.Month] { - t.Day -= 7 - } - } - // Result is in "local" time. Adjust it for "utc". - return t.Seconds() - int64(z.prev.offset) -} - -// Is t before the cutoff for switching to z? -func (z *zone) isBeforeCutoff(t *Time) bool { - var coff int64 - if z.year == 0 { - // "day in month" format used - coff = z.cutoffSeconds(t.Year) - } else { - // "absolute" format used - coff = z.abssec - } - return t.Seconds() < coff -} - -type zoneinfo struct { - disabled bool // daylight saving time is not used locally - offsetIfDisabled int - januaryIsStd bool // is january 1 standard time? - std, dst zone -} - -// Pick zone (std or dst) t time belongs to. -func (zi *zoneinfo) pickZone(t *Time) *zone { - z := &zi.std - if tz.januaryIsStd { - if !zi.dst.isBeforeCutoff(t) && zi.std.isBeforeCutoff(t) { - // after switch to daylight time and before the switch back to standard - z = &zi.dst - } - } else { - if zi.std.isBeforeCutoff(t) || !zi.dst.isBeforeCutoff(t) { - // before switch to standard time or after the switch back to daylight - z = &zi.dst - } - } - return z -} - -var tz zoneinfo -var initError os.Error -var onceSetupZone sync.Once - -func setupZone() { - var i syscall.Timezoneinformation - if _, e := syscall.GetTimeZoneInformation(&i); e != 0 { - initError = os.NewSyscallError("GetTimeZoneInformation", e) - return - } - if !tz.std.populate(i.Bias, i.StandardBias, &i.StandardDate, i.StandardName[0:]) { - tz.disabled = true - tz.offsetIfDisabled = tz.std.offset - return - } - tz.std.prev = &tz.dst - tz.dst.populate(i.Bias, i.DaylightBias, &i.DaylightDate, i.DaylightName[0:]) - tz.dst.prev = &tz.std - tz.std.preCalculateAbsSec() - tz.dst.preCalculateAbsSec() - // Is january 1 standard time this year? - t := UTC() - tz.januaryIsStd = tz.dst.cutoffSeconds(t.Year) < tz.std.cutoffSeconds(t.Year) -} - -// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location. -func lookupTimezone(sec int64) (zone string, offset int) { - onceSetupZone.Do(setupZone) - if initError != nil { - return "", 0 - } - if tz.disabled { - return "", tz.offsetIfDisabled - } - t := SecondsToUTC(sec) - z := &tz.std - if tz.std.year == 0 { - // "day in month" format used - z = tz.pickZone(t) - } else { - // "absolute" format used - if tz.std.year == t.Year { - // we have rule for the year in question - z = tz.pickZone(t) - } else { - // we do not have any information for that year, - // will assume standard offset all year around - } - } - return z.name, z.offset -} - -// lookupByName returns the time offset for the -// time zone with the given abbreviation. It only considers -// time zones that apply to the current system. -func lookupByName(name string) (off int, found bool) { - onceSetupZone.Do(setupZone) - if initError != nil { - return 0, false - } - if tz.disabled { - return tz.offsetIfDisabled, false - } - switch name { - case tz.std.name: - return tz.std.offset, true - case tz.dst.name: - return tz.dst.offset, true - } - return 0, false -} |