diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/pkg/time | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/pkg/time')
25 files changed, 0 insertions, 6722 deletions
diff --git a/src/pkg/time/Makefile b/src/pkg/time/Makefile deleted file mode 100644 index cba58e4e0..000000000 --- a/src/pkg/time/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2013 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. - -genzabbrs: genzabbrs.go - go build genzabbrs.go - -windows: genzabbrs - ./genzabbrs | gofmt >zoneinfo_abbrs_windows.go diff --git a/src/pkg/time/example_test.go b/src/pkg/time/example_test.go deleted file mode 100644 index cfa5b38c5..000000000 --- a/src/pkg/time/example_test.go +++ /dev/null @@ -1,160 +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_test - -import ( - "fmt" - "time" -) - -func expensiveCall() {} - -func ExampleDuration() { - t0 := time.Now() - expensiveCall() - t1 := time.Now() - fmt.Printf("The call took %v to run.\n", t1.Sub(t0)) -} - -var c chan int - -func handle(int) {} - -func ExampleAfter() { - select { - case m := <-c: - handle(m) - case <-time.After(5 * time.Minute): - fmt.Println("timed out") - } -} - -func ExampleSleep() { - time.Sleep(100 * time.Millisecond) -} - -func statusUpdate() string { return "" } - -func ExampleTick() { - c := time.Tick(1 * time.Minute) - for now := range c { - fmt.Printf("%v %s\n", now, statusUpdate()) - } -} - -func ExampleMonth() { - _, month, day := time.Now().Date() - if month == time.November && day == 10 { - fmt.Println("Happy Go day!") - } -} - -func ExampleDate() { - t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) - fmt.Printf("Go launched at %s\n", t.Local()) - // Output: Go launched at 2009-11-10 15:00:00 -0800 PST -} - -func ExampleTime_Format() { - // layout shows by example how the reference time should be represented. - const layout = "Jan 2, 2006 at 3:04pm (MST)" - t := time.Date(2009, time.November, 10, 15, 0, 0, 0, time.Local) - fmt.Println(t.Format(layout)) - fmt.Println(t.UTC().Format(layout)) - // Output: - // Nov 10, 2009 at 3:00pm (PST) - // Nov 10, 2009 at 11:00pm (UTC) -} - -func ExampleParse() { - // longForm shows by example how the reference time would be represented in - // the desired layout. - const longForm = "Jan 2, 2006 at 3:04pm (MST)" - t, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)") - fmt.Println(t) - - // shortForm is another way the reference time would be represented - // in the desired layout; it has no time zone present. - // Note: without explicit zone, returns time in UTC. - const shortForm = "2006-Jan-02" - t, _ = time.Parse(shortForm, "2013-Feb-03") - fmt.Println(t) - - // Output: - // 2013-02-03 19:54:00 -0800 PST - // 2013-02-03 00:00:00 +0000 UTC -} - -func ExampleParseInLocation() { - loc, _ := time.LoadLocation("Europe/Berlin") - - const longForm = "Jan 2, 2006 at 3:04pm (MST)" - t, _ := time.ParseInLocation(longForm, "Jul 9, 2012 at 5:02am (CEST)", loc) - fmt.Println(t) - - // Note: without explicit zone, returns time in given location. - const shortForm = "2006-Jan-02" - t, _ = time.ParseInLocation(shortForm, "2012-Jul-09", loc) - fmt.Println(t) - - // Output: - // 2012-07-09 05:02:00 +0200 CEST - // 2012-07-09 00:00:00 +0200 CEST -} - -func ExampleTime_Round() { - t := time.Date(0, 0, 0, 12, 15, 30, 918273645, time.UTC) - round := []time.Duration{ - time.Nanosecond, - time.Microsecond, - time.Millisecond, - time.Second, - 2 * time.Second, - time.Minute, - 10 * time.Minute, - time.Hour, - } - - for _, d := range round { - fmt.Printf("t.Round(%6s) = %s\n", d, t.Round(d).Format("15:04:05.999999999")) - } - // Output: - // t.Round( 1ns) = 12:15:30.918273645 - // t.Round( 1us) = 12:15:30.918274 - // t.Round( 1ms) = 12:15:30.918 - // t.Round( 1s) = 12:15:31 - // t.Round( 2s) = 12:15:30 - // t.Round( 1m0s) = 12:16:00 - // t.Round( 10m0s) = 12:20:00 - // t.Round(1h0m0s) = 12:00:00 -} - -func ExampleTime_Truncate() { - t, _ := time.Parse("2006 Jan 02 15:04:05", "2012 Dec 07 12:15:30.918273645") - trunc := []time.Duration{ - time.Nanosecond, - time.Microsecond, - time.Millisecond, - time.Second, - 2 * time.Second, - time.Minute, - 10 * time.Minute, - time.Hour, - } - - for _, d := range trunc { - fmt.Printf("t.Truncate(%6s) = %s\n", d, t.Truncate(d).Format("15:04:05.999999999")) - } - - // Output: - // t.Truncate( 1ns) = 12:15:30.918273645 - // t.Truncate( 1us) = 12:15:30.918273 - // t.Truncate( 1ms) = 12:15:30.918 - // t.Truncate( 1s) = 12:15:30 - // t.Truncate( 2s) = 12:15:30 - // t.Truncate( 1m0s) = 12:15:00 - // t.Truncate( 10m0s) = 12:10:00 - // t.Truncate(1h0m0s) = 12:00:00 -} diff --git a/src/pkg/time/export_test.go b/src/pkg/time/export_test.go deleted file mode 100644 index 6cd535f6b..000000000 --- a/src/pkg/time/export_test.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2013 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" -) - -func ResetLocalOnceForTest() { - localOnce = sync.Once{} - localLoc = Location{} -} - -func ForceUSPacificForTesting() { - ResetLocalOnceForTest() - localOnce.Do(initTestingZone) -} - -var ( - ForceZipFileForTesting = forceZipFileForTesting - ParseTimeZone = parseTimeZone -) diff --git a/src/pkg/time/export_windows_test.go b/src/pkg/time/export_windows_test.go deleted file mode 100644 index 7e689b829..000000000 --- a/src/pkg/time/export_windows_test.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2013 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 - -func ForceAusForTesting() { - ResetLocalOnceForTest() - localOnce.Do(initAusTestingZone) -} diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go deleted file mode 100644 index 9f210ea27..000000000 --- a/src/pkg/time/format.go +++ /dev/null @@ -1,1247 +0,0 @@ -// Copyright 2010 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 "errors" - -// These are predefined layouts for use in Time.Format and Time.Parse. -// The reference time used in the layouts is: -// Mon Jan 2 15:04:05 MST 2006 -// which is Unix time 1136239445. Since MST is GMT-0700, -// the reference time can be thought of as -// 01/02 03:04:05PM '06 -0700 -// To define your own format, write down what the reference time would look -// like formatted your way; see the values of constants like ANSIC, -// StampMicro or Kitchen for examples. The model is to demonstrate what the -// reference time looks like so that the Format and Parse methods can apply -// the same transformation to a general time value. -// -// 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. -// -// A decimal point followed by one or more zeros represents a fractional -// second, printed to the given number of decimal places. A decimal point -// followed by one or more nines represents a fractional second, printed to -// the given number of decimal places, with trailing zeros removed. -// When parsing (only), the input may contain a fractional second -// field immediately after the seconds field, even if the layout does not -// signify its presence. In that case a decimal point followed by a maximal -// series of digits is parsed as a fractional second. -// -// 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 15:04 MST" - RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone - RFC850 = "Monday, 02-Jan-06 15:04:05 MST" - RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" - RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone - RFC3339 = "2006-01-02T15:04:05Z07:00" - RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" - Kitchen = "3:04PM" - // Handy time stamps. - Stamp = "Jan _2 15:04:05" - StampMilli = "Jan _2 15:04:05.000" - StampMicro = "Jan _2 15:04:05.000000" - StampNano = "Jan _2 15:04:05.000000000" -) - -const ( - _ = iota - stdLongMonth = iota + stdNeedDate // "January" - stdMonth // "Jan" - stdNumMonth // "1" - stdZeroMonth // "01" - stdLongWeekDay // "Monday" - stdWeekDay // "Mon" - stdDay // "2" - stdUnderDay // "_2" - stdZeroDay // "02" - stdHour = iota + stdNeedClock // "15" - stdHour12 // "3" - stdZeroHour12 // "03" - stdMinute // "4" - stdZeroMinute // "04" - stdSecond // "5" - stdZeroSecond // "05" - stdLongYear = iota + stdNeedDate // "2006" - stdYear // "06" - stdPM = iota + stdNeedClock // "PM" - stdpm // "pm" - stdTZ = iota // "MST" - stdISO8601TZ // "Z0700" // prints Z for UTC - stdISO8601SecondsTZ // "Z070000" - stdISO8601ColonTZ // "Z07:00" // prints Z for UTC - stdISO8601ColonSecondsTZ // "Z07:00:00" - stdNumTZ // "-0700" // always numeric - stdNumSecondsTz // "-070000" - stdNumShortTZ // "-07" // always numeric - stdNumColonTZ // "-07:00" // always numeric - stdNumColonSecondsTZ // "-07:00:00" - stdFracSecond0 // ".0", ".00", ... , trailing zeros included - stdFracSecond9 // ".9", ".99", ..., trailing zeros omitted - - stdNeedDate = 1 << 8 // need month, day, year - stdNeedClock = 2 << 8 // need hour, minute, second - stdArgShift = 16 // extra argument in high bits, above low stdArgShift - stdMask = 1<<stdArgShift - 1 // mask out argument -) - -// std0x records the std values for "01", "02", ..., "06". -var std0x = [...]int{stdZeroMonth, stdZeroDay, stdZeroHour12, stdZeroMinute, stdZeroSecond, stdYear} - -// startsWithLowerCase reports whether the string has a lower-case letter at the beginning. -// Its purpose is to prevent matching strings like "Month" when looking for "Mon". -func startsWithLowerCase(str string) bool { - if len(str) == 0 { - return false - } - c := str[0] - return 'a' <= c && c <= 'z' -} - -// 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 string, std int, suffix string) { - for i := 0; i < len(layout); i++ { - switch c := int(layout[i]); c { - case 'J': // January, Jan - if len(layout) >= i+3 && layout[i:i+3] == "Jan" { - if len(layout) >= i+7 && layout[i:i+7] == "January" { - return layout[0:i], stdLongMonth, layout[i+7:] - } - if !startsWithLowerCase(layout[i+3:]) { - return layout[0:i], stdMonth, layout[i+3:] - } - } - - case 'M': // Monday, Mon, MST - if len(layout) >= i+3 { - if layout[i:i+3] == "Mon" { - if len(layout) >= i+6 && layout[i:i+6] == "Monday" { - return layout[0:i], stdLongWeekDay, layout[i+6:] - } - if !startsWithLowerCase(layout[i+3:]) { - return layout[0:i], stdWeekDay, layout[i+3:] - } - } - if layout[i:i+3] == "MST" { - 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], std0x[layout[i+1]-'1'], 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] == "2006" { - 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': - return layout[0:i], stdHour12, layout[i+1:] - - case '4': - return layout[0:i], stdMinute, layout[i+1:] - - case '5': - return layout[0:i], stdSecond, layout[i+1:] - - case 'P': // PM - if len(layout) >= i+2 && layout[i+1] == 'M' { - return layout[0:i], stdPM, layout[i+2:] - } - - case 'p': // pm - if len(layout) >= i+2 && layout[i+1] == 'm' { - return layout[0:i], stdpm, layout[i+2:] - } - - case '-': // -070000, -07:00:00, -0700, -07:00, -07 - if len(layout) >= i+7 && layout[i:i+7] == "-070000" { - return layout[0:i], stdNumSecondsTz, layout[i+7:] - } - if len(layout) >= i+9 && layout[i:i+9] == "-07:00:00" { - return layout[0:i], stdNumColonSecondsTZ, layout[i+9:] - } - if len(layout) >= i+5 && layout[i:i+5] == "-0700" { - return layout[0:i], stdNumTZ, layout[i+5:] - } - if len(layout) >= i+6 && layout[i:i+6] == "-07:00" { - return layout[0:i], stdNumColonTZ, layout[i+6:] - } - if len(layout) >= i+3 && layout[i:i+3] == "-07" { - return layout[0:i], stdNumShortTZ, layout[i+3:] - } - - case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00, - if len(layout) >= i+7 && layout[i:i+7] == "Z070000" { - return layout[0:i], stdISO8601SecondsTZ, layout[i+7:] - } - if len(layout) >= i+9 && layout[i:i+9] == "Z07:00:00" { - return layout[0:i], stdISO8601ColonSecondsTZ, layout[i+9:] - } - if len(layout) >= i+5 && layout[i:i+5] == "Z0700" { - return layout[0:i], stdISO8601TZ, layout[i+5:] - } - if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" { - return layout[0:i], stdISO8601ColonTZ, layout[i+6:] - } - - case '.': // .000 or .999 - repeated digits for fractional seconds. - if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') { - ch := layout[i+1] - j := i + 1 - for j < len(layout) && layout[j] == ch { - j++ - } - // String of digits must end here - only fractional second is all digits. - if !isDigit(layout, j) { - std := stdFracSecond0 - if layout[i+1] == '9' { - std = stdFracSecond9 - } - std |= (j - (i + 1)) << stdArgShift - return layout[0:i], std, layout[j:] - } - } - } - } - return layout, 0, "" -} - -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", -} - -// match returns true if s1 and s2 match ignoring case. -// It is assumed s1 and s2 are the same length. -func match(s1, s2 string) bool { - for i := 0; i < len(s1); i++ { - c1 := s1[i] - c2 := s2[i] - if c1 != c2 { - // Switch to lower-case; 'a'-'A' is known to be a single bit. - c1 |= 'a' - 'A' - c2 |= 'a' - 'A' - if c1 != c2 || c1 < 'a' || c1 > 'z' { - return false - } - } - } - return true -} - -func lookup(tab []string, val string) (int, string, error) { - for i, v := range tab { - if len(val) >= len(v) && match(val[0:len(v)], v) { - return i, val[len(v):], nil - } - } - return -1, val, errBad -} - -// appendUint appends the decimal form of x to b and returns the result. -// If x is a single-digit number and pad != 0, appendUint inserts the pad byte -// before the digit. -// Duplicates functionality in strconv, but avoids dependency. -func appendUint(b []byte, x uint, pad byte) []byte { - if x < 10 { - if pad != 0 { - b = append(b, pad) - } - return append(b, byte('0'+x)) - } - if x < 100 { - b = append(b, byte('0'+x/10)) - b = append(b, byte('0'+x%10)) - return b - } - - var buf [32]byte - n := len(buf) - if x == 0 { - return append(b, '0') - } - for x >= 10 { - n-- - buf[n] = byte(x%10 + '0') - x /= 10 - } - n-- - buf[n] = byte(x + '0') - return append(b, buf[n:]...) -} - -// Never printed, just needs to be non-nil for return by atoi. -var atoiError = errors.New("time: invalid number") - -// Duplicates functionality in strconv, but avoids dependency. -func atoi(s string) (x int, err error) { - neg := false - if s != "" && (s[0] == '-' || s[0] == '+') { - neg = s[0] == '-' - s = s[1:] - } - q, rem, err := leadingInt(s) - x = int(q) - if err != nil || rem != "" { - return 0, atoiError - } - if neg { - x = -x - } - return x, nil -} - -// formatNano appends a fractional second, as nanoseconds, to b -// and returns the result. -func formatNano(b []byte, nanosec uint, n int, trim bool) []byte { - u := nanosec - var buf [9]byte - for start := len(buf); start > 0; { - start-- - buf[start] = byte(u%10 + '0') - u /= 10 - } - - if n > 9 { - n = 9 - } - if trim { - for n > 0 && buf[n-1] == '0' { - n-- - } - if n == 0 { - return b - } - } - b = append(b, '.') - return append(b, buf[:n]...) -} - -// String returns the time formatted using the format string -// "2006-01-02 15:04:05.999999999 -0700 MST" -func (t Time) String() string { - return t.Format("2006-01-02 15:04:05.999999999 -0700 MST") -} - -// Format returns a textual representation of the time value formatted -// according to layout, which defines the format by showing how the reference -// time, -// Mon Jan 2 15:04:05 -0700 MST 2006 -// would be displayed if it were the value; it serves as an example of the -// desired output. The same display rules will then be applied to the time -// value. -// Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard -// and convenient representations of the reference time. For more information -// about the formats and the definition of the reference time, see the -// documentation for ANSIC and the other constants defined by this package. -func (t Time) Format(layout string) string { - var ( - name, offset, abs = t.locabs() - - year int = -1 - month Month - day int - hour int = -1 - min int - sec int - - b []byte - buf [64]byte - ) - max := len(layout) + 10 - if max <= len(buf) { - b = buf[:0] - } else { - b = make([]byte, 0, max) - } - // Each iteration generates one std value. - for layout != "" { - prefix, std, suffix := nextStdChunk(layout) - if prefix != "" { - b = append(b, prefix...) - } - if std == 0 { - break - } - layout = suffix - - // Compute year, month, day if needed. - if year < 0 && std&stdNeedDate != 0 { - year, month, day, _ = absDate(abs, true) - } - - // Compute hour, minute, second if needed. - if hour < 0 && std&stdNeedClock != 0 { - hour, min, sec = absClock(abs) - } - - switch std & stdMask { - case stdYear: - y := year - if y < 0 { - y = -y - } - b = appendUint(b, uint(y%100), '0') - case stdLongYear: - // Pad year to at least 4 digits. - y := year - switch { - case year <= -1000: - b = append(b, '-') - y = -y - case year <= -100: - b = append(b, "-0"...) - y = -y - case year <= -10: - b = append(b, "-00"...) - y = -y - case year < 0: - b = append(b, "-000"...) - y = -y - case year < 10: - b = append(b, "000"...) - case year < 100: - b = append(b, "00"...) - case year < 1000: - b = append(b, '0') - } - b = appendUint(b, uint(y), 0) - case stdMonth: - b = append(b, month.String()[:3]...) - case stdLongMonth: - m := month.String() - b = append(b, m...) - case stdNumMonth: - b = appendUint(b, uint(month), 0) - case stdZeroMonth: - b = appendUint(b, uint(month), '0') - case stdWeekDay: - b = append(b, absWeekday(abs).String()[:3]...) - case stdLongWeekDay: - s := absWeekday(abs).String() - b = append(b, s...) - case stdDay: - b = appendUint(b, uint(day), 0) - case stdUnderDay: - b = appendUint(b, uint(day), ' ') - case stdZeroDay: - b = appendUint(b, uint(day), '0') - case stdHour: - b = appendUint(b, uint(hour), '0') - case stdHour12: - // Noon is 12PM, midnight is 12AM. - hr := hour % 12 - if hr == 0 { - hr = 12 - } - b = appendUint(b, uint(hr), 0) - case stdZeroHour12: - // Noon is 12PM, midnight is 12AM. - hr := hour % 12 - if hr == 0 { - hr = 12 - } - b = appendUint(b, uint(hr), '0') - case stdMinute: - b = appendUint(b, uint(min), 0) - case stdZeroMinute: - b = appendUint(b, uint(min), '0') - case stdSecond: - b = appendUint(b, uint(sec), 0) - case stdZeroSecond: - b = appendUint(b, uint(sec), '0') - case stdPM: - if hour >= 12 { - b = append(b, "PM"...) - } else { - b = append(b, "AM"...) - } - case stdpm: - if hour >= 12 { - b = append(b, "pm"...) - } else { - b = append(b, "am"...) - } - case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ: - // Ugly special case. We cheat and take the "Z" variants - // to mean "the time zone as formatted for ISO 8601". - if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ColonSecondsTZ) { - b = append(b, 'Z') - break - } - zone := offset / 60 // convert to minutes - absoffset := offset - if zone < 0 { - b = append(b, '-') - zone = -zone - absoffset = -absoffset - } else { - b = append(b, '+') - } - b = appendUint(b, uint(zone/60), '0') - if std == stdISO8601ColonTZ || std == stdNumColonTZ { - b = append(b, ':') - } - b = appendUint(b, uint(zone%60), '0') - - // append seconds if appropriate - if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { - if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { - b = append(b, ':') - } - b = appendUint(b, uint(absoffset%60), '0') - } - - case stdTZ: - if name != "" { - b = append(b, name...) - break - } - // No time zone known for this time, but we must print one. - // Use the -0700 format. - zone := offset / 60 // convert to minutes - if zone < 0 { - b = append(b, '-') - zone = -zone - } else { - b = append(b, '+') - } - b = appendUint(b, uint(zone/60), '0') - b = appendUint(b, uint(zone%60), '0') - case stdFracSecond0, stdFracSecond9: - b = formatNano(b, uint(t.Nanosecond()), std>>stdArgShift, std&stdMask == stdFracSecond9) - } - } - return string(b) -} - -var errBad = errors.New("bad value for field") // placeholder not passed to user - -// ParseError describes a problem parsing a time string. -type ParseError struct { - Layout string - Value string - LayoutElem string - ValueElem string - Message string -} - -func quote(s string) string { - return "\"" + s + "\"" -} - -// Error returns the string representation of a ParseError. -func (e *ParseError) Error() string { - if e.Message == "" { - return "parsing time " + - quote(e.Value) + " as " + - quote(e.Layout) + ": cannot parse " + - quote(e.ValueElem) + " as " + - quote(e.LayoutElem) - } - return "parsing time " + - quote(e.Value) + e.Message -} - -// isDigit returns true if s[i] is a decimal digit, false if not or -// if s[i] is out of range. -func isDigit(s string, i int) bool { - if len(s) <= i { - return false - } - c := s[i] - return '0' <= c && c <= '9' -} - -// 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, error) { - if !isDigit(s, 0) { - return 0, s, errBad - } - if !isDigit(s, 1) { - 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, error) { - for len(prefix) > 0 { - if prefix[0] == ' ' { - if len(value) > 0 && value[0] != ' ' { - return value, errBad - } - prefix = cutspace(prefix) - value = cutspace(value) - continue - } - if len(value) == 0 || value[0] != prefix[0] { - return value, 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 how the reference time, -// Mon Jan 2 15:04:05 -0700 MST 2006 -// would be interpreted if it were the value; it serves as an example of -// the input format. The same interpretation will then be made to the -// input string. -// Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard -// and convenient representations of the reference time. For more information -// about the formats and the definition of the reference time, see the -// documentation for ANSIC and the other constants defined by this package. -// -// Elements omitted from the value are assumed to be zero or, when -// zero is impossible, one, so parsing "3:04pm" returns the time -// corresponding to Jan 1, year 0, 15:04:00 UTC (note that because the year is -// 0, this time is before the zero Time). -// Years must be in the range 0000..9999. The day of the week is checked -// for syntax but it is otherwise ignored. -// -// In the absence of a time zone indicator, Parse returns a time in UTC. -// -// When parsing a time with a zone offset like -0700, if the offset corresponds -// to a time zone used by the current location (Local), then Parse uses that -// location and zone in the returned time. Otherwise it records the time as -// being in a fabricated location with time fixed at the given zone offset. -// -// When parsing a time with a zone abbreviation like MST, if the zone abbreviation -// has a defined offset in the current location, then that offset is used. -// The zone abbreviation "UTC" is recognized as UTC regardless of location. -// If the zone abbreviation is unknown, Parse records the time as being -// in a fabricated location with the given zone abbreviation and a zero offset. -// This choice means that such a time can be parse and reformatted with the -// same layout losslessly, but the exact instant used in the representation will -// differ by the actual zone offset. To avoid such problems, prefer time layouts -// that use a numeric zone offset, or use ParseInLocation. -func Parse(layout, value string) (Time, error) { - return parse(layout, value, UTC, Local) -} - -// ParseInLocation is like Parse but differs in two important ways. -// First, in the absence of time zone information, Parse interprets a time as UTC; -// ParseInLocation interprets the time as in the given location. -// Second, when given a zone offset or abbreviation, Parse tries to match it -// against the Local location; ParseInLocation uses the given location. -func ParseInLocation(layout, value string, loc *Location) (Time, error) { - return parse(layout, value, loc, loc) -} - -func parse(layout, value string, defaultLocation, local *Location) (Time, error) { - alayout, avalue := layout, value - 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? - - // Time being constructed. - var ( - year int - month int = 1 // January - day int = 1 - hour int - min int - sec int - nsec int - z *Location - zoneOffset int = -1 - zoneName string - ) - - // Each iteration processes one std value. - for { - var err error - prefix, std, suffix := nextStdChunk(layout) - stdstr := layout[len(prefix) : len(layout)-len(suffix)] - value, err = skip(value, prefix) - if err != nil { - return Time{}, &ParseError{alayout, avalue, prefix, value, ""} - } - if std == 0 { - if len(value) != 0 { - return Time{}, &ParseError{alayout, avalue, "", value, ": extra text: " + value} - } - break - } - layout = suffix - var p string - switch std & stdMask { - case stdYear: - if len(value) < 2 { - err = errBad - break - } - p, value = value[0:2], value[2:] - year, err = atoi(p) - if year >= 69 { // Unix time starts Dec 31 1969 in some time zones - year += 1900 - } else { - year += 2000 - } - case stdLongYear: - if len(value) < 4 || !isDigit(value, 0) { - err = errBad - break - } - p, value = value[0:4], value[4:] - year, err = atoi(p) - case stdMonth: - month, value, err = lookup(shortMonthNames, value) - case stdLongMonth: - month, value, err = lookup(longMonthNames, value) - case stdNumMonth, stdZeroMonth: - month, value, err = getnum(value, std == stdZeroMonth) - if month <= 0 || 12 < month { - rangeErrString = "month" - } - case stdWeekDay: - // Ignore weekday except for error checking. - _, value, err = lookup(shortDayNames, value) - case stdLongWeekDay: - _, value, err = lookup(longDayNames, value) - case stdDay, stdUnderDay, stdZeroDay: - if std == stdUnderDay && len(value) > 0 && value[0] == ' ' { - value = value[1:] - } - day, value, err = getnum(value, std == stdZeroDay) - if day < 0 || 31 < day { - rangeErrString = "day" - } - case stdHour: - hour, value, err = getnum(value, false) - if hour < 0 || 24 <= hour { - rangeErrString = "hour" - } - case stdHour12, stdZeroHour12: - hour, value, err = getnum(value, std == stdZeroHour12) - if hour < 0 || 12 < hour { - rangeErrString = "hour" - } - case stdMinute, stdZeroMinute: - min, value, err = getnum(value, std == stdZeroMinute) - if min < 0 || 60 <= min { - rangeErrString = "minute" - } - case stdSecond, stdZeroSecond: - sec, value, err = getnum(value, std == stdZeroSecond) - if sec < 0 || 60 <= sec { - rangeErrString = "second" - } - // Special case: do we have a fractional second but no - // fractional second in the format? - if len(value) >= 2 && value[0] == '.' && isDigit(value, 1) { - _, std, _ = nextStdChunk(layout) - std &= stdMask - if std == stdFracSecond0 || std == stdFracSecond9 { - // Fractional second in the layout; proceed normally - break - } - // No fractional second in the layout but we have one in the input. - n := 2 - for ; n < len(value) && isDigit(value, n); n++ { - } - nsec, rangeErrString, err = parseNanoseconds(value, n) - value = value[n:] - } - 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 stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ: - if (std == stdISO8601TZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' { - value = value[1:] - z = UTC - break - } - var sign, hour, min, seconds string - if std == stdISO8601ColonTZ || std == stdNumColonTZ { - if len(value) < 6 { - err = errBad - break - } - if value[3] != ':' { - err = errBad - break - } - sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:] - } else if std == stdNumShortTZ { - if len(value) < 3 { - err = errBad - break - } - sign, hour, min, seconds, value = value[0:1], value[1:3], "00", "00", value[3:] - } else if std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { - if len(value) < 9 { - err = errBad - break - } - if value[3] != ':' || value[6] != ':' { - err = errBad - break - } - sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], value[7:9], value[9:] - } else if std == stdISO8601SecondsTZ || std == stdNumSecondsTz { - if len(value) < 7 { - err = errBad - break - } - sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], value[5:7], value[7:] - } else { - if len(value) < 5 { - err = errBad - break - } - sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], "00", value[5:] - } - var hr, mm, ss int - hr, err = atoi(hour) - if err == nil { - mm, err = atoi(min) - } - if err == nil { - ss, err = atoi(seconds) - } - zoneOffset = (hr*60+mm)*60 + ss // offset is in seconds - switch sign[0] { - case '+': - case '-': - zoneOffset = -zoneOffset - default: - err = errBad - } - case stdTZ: - // Does it look like a time zone? - if len(value) >= 3 && value[0:3] == "UTC" { - z = UTC - value = value[3:] - break - } - n, ok := parseTimeZone(value) - if !ok { - err = errBad - break - } - zoneName, value = value[:n], value[n:] - - case stdFracSecond0: - // stdFracSecond0 requires the exact number of digits as specified in - // the layout. - ndigit := 1 + (std >> stdArgShift) - if len(value) < ndigit { - err = errBad - break - } - nsec, rangeErrString, err = parseNanoseconds(value, ndigit) - value = value[ndigit:] - - case stdFracSecond9: - if len(value) < 2 || value[0] != '.' || value[1] < '0' || '9' < value[1] { - // Fractional second omitted. - break - } - // Take any number of digits, even more than asked for, - // because it is what the stdSecond case would do. - i := 0 - for i < 9 && i+1 < len(value) && '0' <= value[i+1] && value[i+1] <= '9' { - i++ - } - nsec, rangeErrString, err = parseNanoseconds(value, 1+i) - value = value[1+i:] - } - if rangeErrString != "" { - return Time{}, &ParseError{alayout, avalue, stdstr, value, ": " + rangeErrString + " out of range"} - } - if err != nil { - return Time{}, &ParseError{alayout, avalue, stdstr, value, ""} - } - } - if pmSet && hour < 12 { - hour += 12 - } else if amSet && hour == 12 { - hour = 0 - } - - if z != nil { - return Date(year, Month(month), day, hour, min, sec, nsec, z), nil - } - - if zoneOffset != -1 { - t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) - t.sec -= int64(zoneOffset) - - // Look for local zone with the given offset. - // If that zone was in effect at the given time, use it. - name, offset, _, _, _ := local.lookup(t.sec + internalToUnix) - if offset == zoneOffset && (zoneName == "" || name == zoneName) { - t.loc = local - return t, nil - } - - // Otherwise create fake zone to record offset. - t.loc = FixedZone(zoneName, zoneOffset) - return t, nil - } - - if zoneName != "" { - t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) - // Look for local zone with the given offset. - // If that zone was in effect at the given time, use it. - offset, _, ok := local.lookupName(zoneName, t.sec+internalToUnix) - if ok { - t.sec -= int64(offset) - t.loc = local - return t, nil - } - - // Otherwise, create fake zone with unknown offset. - if len(zoneName) > 3 && zoneName[:3] == "GMT" { - offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT. - offset *= 3600 - } - t.loc = FixedZone(zoneName, offset) - return t, nil - } - - // Otherwise, fall back to default. - return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil -} - -// parseTimeZone parses a time zone string and returns its length. Time zones -// are human-generated and unpredictable. We can't do precise error checking. -// On the other hand, for a correct parse there must be a time zone at the -// beginning of the string, so it's almost always true that there's one -// there. We look at the beginning of the string for a run of upper-case letters. -// If there are more than 5, it's an error. -// If there are 4 or 5 and the last is a T, it's a time zone. -// If there are 3, it's a time zone. -// Otherwise, other than special cases, it's not a time zone. -// GMT is special because it can have an hour offset. -func parseTimeZone(value string) (length int, ok bool) { - if len(value) < 3 { - return 0, false - } - // Special case 1: ChST and MeST are the only zones with a lower-case letter. - if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") { - return 4, true - } - // Special case 2: GMT may have an hour offset; treat it specially. - if value[:3] == "GMT" { - length = parseGMT(value) - return length, true - } - // How many upper-case letters are there? Need at least three, at most five. - var nUpper int - for nUpper = 0; nUpper < 6; nUpper++ { - if nUpper >= len(value) { - break - } - if c := value[nUpper]; c < 'A' || 'Z' < c { - break - } - } - switch nUpper { - case 0, 1, 2, 6: - return 0, false - case 5: // Must end in T to match. - if value[4] == 'T' { - return 5, true - } - case 4: // Must end in T to match. - if value[3] == 'T' { - return 4, true - } - case 3: - return 3, true - } - return 0, false -} - -// parseGMT parses a GMT time zone. The input string is known to start "GMT". -// The function checks whether that is followed by a sign and a number in the -// range -14 through 12 excluding zero. -func parseGMT(value string) int { - value = value[3:] - if len(value) == 0 { - return 3 - } - sign := value[0] - if sign != '-' && sign != '+' { - return 3 - } - x, rem, err := leadingInt(value[1:]) - if err != nil { - return 3 - } - if sign == '-' { - x = -x - } - if x == 0 || x < -14 || 12 < x { - return 3 - } - return 3 + len(value) - len(rem) -} - -func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) { - if value[0] != '.' { - err = errBad - return - } - if ns, err = atoi(value[1:nbytes]); err != nil { - return - } - if ns < 0 || 1e9 <= ns { - rangeErrString = "fractional second" - return - } - // We need nanoseconds, which means scaling by the number - // of missing digits in the format, maximum length 10. If it's - // longer than 10, we won't scale. - scaleDigits := 10 - nbytes - for i := 0; i < scaleDigits; i++ { - ns *= 10 - } - return -} - -var errLeadingInt = errors.New("time: bad [0-9]*") // never printed - -// leadingInt consumes the leading [0-9]* from s. -func leadingInt(s string) (x int64, rem string, err error) { - i := 0 - for ; i < len(s); i++ { - c := s[i] - if c < '0' || c > '9' { - break - } - if x >= (1<<63-10)/10 { - // overflow - return 0, "", errLeadingInt - } - x = x*10 + int64(c) - '0' - } - return x, s[i:], nil -} - -var unitMap = map[string]float64{ - "ns": float64(Nanosecond), - "us": float64(Microsecond), - "µs": float64(Microsecond), // U+00B5 = micro symbol - "μs": float64(Microsecond), // U+03BC = Greek letter mu - "ms": float64(Millisecond), - "s": float64(Second), - "m": float64(Minute), - "h": float64(Hour), -} - -// ParseDuration parses a duration string. -// A duration string is a possibly signed sequence of -// decimal numbers, each with optional fraction and a unit suffix, -// such as "300ms", "-1.5h" or "2h45m". -// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". -func ParseDuration(s string) (Duration, error) { - // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ - orig := s - f := float64(0) - neg := false - - // Consume [-+]? - if s != "" { - c := s[0] - if c == '-' || c == '+' { - neg = c == '-' - s = s[1:] - } - } - // Special case: if all that is left is "0", this is zero. - if s == "0" { - return 0, nil - } - if s == "" { - return 0, errors.New("time: invalid duration " + orig) - } - for s != "" { - g := float64(0) // this element of the sequence - - var x int64 - var err error - - // The next character must be [0-9.] - if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) { - return 0, errors.New("time: invalid duration " + orig) - } - // Consume [0-9]* - pl := len(s) - x, s, err = leadingInt(s) - if err != nil { - return 0, errors.New("time: invalid duration " + orig) - } - g = float64(x) - pre := pl != len(s) // whether we consumed anything before a period - - // Consume (\.[0-9]*)? - post := false - if s != "" && s[0] == '.' { - s = s[1:] - pl := len(s) - x, s, err = leadingInt(s) - if err != nil { - return 0, errors.New("time: invalid duration " + orig) - } - scale := 1.0 - for n := pl - len(s); n > 0; n-- { - scale *= 10 - } - g += float64(x) / scale - post = pl != len(s) - } - if !pre && !post { - // no digits (e.g. ".s" or "-.s") - return 0, errors.New("time: invalid duration " + orig) - } - - // Consume unit. - i := 0 - for ; i < len(s); i++ { - c := s[i] - if c == '.' || ('0' <= c && c <= '9') { - break - } - } - if i == 0 { - return 0, errors.New("time: missing unit in duration " + orig) - } - u := s[:i] - s = s[i:] - unit, ok := unitMap[u] - if !ok { - return 0, errors.New("time: unknown unit " + u + " in duration " + orig) - } - - f += g * unit - } - - if neg { - f = -f - } - if f < float64(-1<<63) || f > float64(1<<63-1) { - return 0, errors.New("time: overflow parsing duration") - } - return Duration(f), nil -} diff --git a/src/pkg/time/format_test.go b/src/pkg/time/format_test.go deleted file mode 100644 index 46a598155..000000000 --- a/src/pkg/time/format_test.go +++ /dev/null @@ -1,517 +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" - "strconv" - "strings" - "testing" - "testing/quick" - . "time" -) - -type TimeFormatTest struct { - time Time - formattedValue string -} - -var rfc3339Formats = []TimeFormatTest{ - {Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"}, - {Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"}, - {Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "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 21:00 PST"}, - {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"}, - {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"}, - {"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"}, - {"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"}, - {"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"}, - {"Kitchen", Kitchen, "9:00PM"}, - {"am/pm", "3pm", "9pm"}, - {"AM/PM", "3PM", "9PM"}, - {"two-digit year", "06 01 02", "09 02 04"}, - // Three-letter months and days must not be followed by lower-case letter. - {"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"}, - // Time stamps, Fractional seconds. - {"Stamp", Stamp, "Feb 4 21:00:57"}, - {"StampMilli", StampMilli, "Feb 4 21:00:57.012"}, - {"StampMicro", StampMicro, "Feb 4 21:00:57.012345"}, - {"StampNano", StampNano, "Feb 4 21:00:57.012345600"}, -} - -func TestFormat(t *testing.T) { - // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2010 - time := Unix(0, 1233810057012345600) - 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) - } - } -} - -func TestFormatShortYear(t *testing.T) { - years := []int{ - -100001, -100000, -99999, - -10001, -10000, -9999, - -1001, -1000, -999, - -101, -100, -99, - -11, -10, -9, - -1, 0, 1, - 9, 10, 11, - 99, 100, 101, - 999, 1000, 1001, - 9999, 10000, 10001, - 99999, 100000, 100001, - } - - for _, y := range years { - time := Date(y, January, 1, 0, 0, 0, 0, UTC) - result := time.Format("2006.01.02") - var want string - if y < 0 { - // The 4 in %04d counts the - sign, so print -y instead - // and introduce our own - sign. - want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1) - } else { - want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1) - } - if result != want { - t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want) - } - } -} - -type ParseTest struct { - name string - format string - value string - hasTZ bool // contains a time zone - hasWD bool // contains a weekday - yearSign int // sign of year, -1 indicates the year is not present in the format - fracDigits int // number of digits of fractional second -} - -var parseTests = []ParseTest{ - {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0}, - {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1, 0}, - {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0}, - {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0}, - {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0}, - {"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0}, - {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0}, - {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0}, - {"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, 0}, - // Optional fractional seconds. - {"ANSIC", ANSIC, "Thu Feb 4 21:00:57.0 2010", false, true, 1, 1}, - {"UnixDate", UnixDate, "Thu Feb 4 21:00:57.01 PST 2010", true, true, 1, 2}, - {"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3}, - {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4}, - {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5}, - {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5}, - {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9}, - {"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0}, - // Amount of white space should not matter. - {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0}, - {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0}, - // Case should not matter - {"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0}, - {"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0}, - // Fractional seconds. - {"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3}, - {"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6}, - {"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9}, - // Leading zeros in other places should not be taken as fractional seconds. - {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1}, - {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2}, - // Month and day names only match when not followed by a lower-case letter. - {"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb 4 21:00:57 2010", false, true, 1, 0}, - - // GMT with offset. - {"GMT-8", UnixDate, "Fri Feb 5 05:00:57 GMT-8 2010", true, true, 1, 0}, - - // Accept any number of fractional second digits (including none) for .999... - // In Go 1, .999... was completely ignored in the format, meaning the first two - // cases would succeed, but the next four would not. Go 1.1 accepts all six. - {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0}, - {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0}, - {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4}, - {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4}, - {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9}, - {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9}, - - // issue 4502. - {"", StampNano, "Feb 4 21:00:57.012345678", false, false, -1, 9}, - {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012300000", false, false, -1, 4}, - {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012345678", false, false, -1, 9}, - {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.0123", false, false, -1, 4}, - {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.012345678", false, false, -1, 9}, -} - -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) - } - } -} - -func TestParseInLocation(t *testing.T) { - // Check that Parse (and ParseInLocation) understand that - // Feb 01 AST (Arabia Standard Time) and Feb 01 AST (Atlantic Standard Time) - // are in different time zones even though both are called AST - - baghdad, err := LoadLocation("Asia/Baghdad") - if err != nil { - t.Fatal(err) - } - - t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad) - if err != nil { - t.Fatal(err) - } - t2 := Date(2013, February, 1, 00, 00, 00, 0, baghdad) - if t1 != t2 { - t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2) - } - _, offset := t1.Zone() - if offset != 3*60*60 { - t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60) - } - - blancSablon, err := LoadLocation("America/Blanc-Sablon") - if err != nil { - t.Fatal(err) - } - - t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", blancSablon) - if err != nil { - t.Fatal(err) - } - t2 = Date(2013, February, 1, 00, 00, 00, 0, blancSablon) - if t1 != t2 { - t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon) = %v, want %v", t1, t2) - } - _, offset = t1.Zone() - if offset != -4*60*60 { - t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon).Zone = _, %d, want _, %d", offset, -4*60*60) - } -} - -func TestLoadLocationZipFile(t *testing.T) { - ForceZipFileForTesting(true) - defer ForceZipFileForTesting(false) - - _, err := LoadLocation("Australia/Sydney") - if err != nil { - t.Fatal(err) - } -} - -var rubyTests = []ParseTest{ - {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0}, - // 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, 0}, - {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0}, - {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0}, -} - -// 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 >= 0 && test.yearSign*time.Year() != 2010 { - t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010) - } - if time.Month() != February { - t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February) - } - 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) - } - // Nanoseconds must be checked against the precision of the input. - nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0) - if err != nil { - panic(err) - } - if time.Nanosecond() != int(nanosec) { - t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec) - } - name, offset := time.Zone() - if test.hasTZ && offset != -28800 { - t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800) - } - if test.hasWD && time.Weekday() != Thursday { - t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday) - } -} - -func TestFormatAndParse(t *testing.T) { - const fmt = "Mon MST " + RFC3339 // all fields - f := func(sec int64) bool { - t1 := Unix(sec, 0) - 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 t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() { - t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix()) - 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 ParseTimeZoneTest struct { - value string - length int - ok bool -} - -var parseTimeZoneTests = []ParseTimeZoneTest{ - {"gmt hi there", 0, false}, - {"GMT hi there", 3, true}, - {"GMT+12 hi there", 6, true}, - {"GMT+00 hi there", 3, true}, // 0 or 00 is not a legal offset. - {"GMT-5 hi there", 5, true}, - {"GMT-51 hi there", 3, true}, - {"ChST hi there", 4, true}, - {"MeST hi there", 4, true}, - {"MSDx", 3, true}, - {"MSDY", 0, false}, // four letters must end in T. - {"ESAST hi", 5, true}, - {"ESASTT hi", 0, false}, // run of upper-case letters too long. - {"ESATY hi", 0, false}, // five letters must end in T. -} - -func TestParseTimeZone(t *testing.T) { - for _, test := range parseTimeZoneTests { - length, ok := ParseTimeZone(test.value) - if ok != test.ok { - t.Errorf("expected %t for %q got %t", test.ok, test.value, ok) - } else if length != test.length { - t.Errorf("expected %d for %q got %d", test.length, test.value, length) - } - } -} - -type ParseErrorTest struct { - format string - value string - expect string // must appear within the error -} - -var parseErrorTests = []ParseErrorTest{ - {ANSIC, "Feb 4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon - {ANSIC, "Thu Feb 4 21:00:57 @2010", "cannot 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"}, - {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59x01 2010", "cannot parse"}, - {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.xxx 2010", "cannot parse"}, - {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.-123 2010", "fractional second out of range"}, - // issue 4502. StampNano requires exactly 9 digits of precision. - {StampNano, "Dec 7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`}, - {StampNano, "Dec 7 11:22:01.0000000000", "extra text: 0"}, - // issue 4493. Helpful errors. - {RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: 07:00`}, - {RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`}, - {RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`}, - {RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`}, -} - -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.Error(), 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 := Date(0, January, 1, 12, 0, 0, 0, UTC) - 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 := Date(0, January, 1, 0, 0, 0, 0, UTC) - 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, "Thu Feb 02 16:10:03 -0500 2006") - if err != nil { - t.Fatal("error parsing date:", err) - } - expect := "Thu 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("got %s; expect %s", str, expect) - } -} - -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 - _, offset := time.Zone() - if offset != expected { - t.Errorf("ZoneOffset = %d, want %d", offset, expected) - } -} - -type SecondsTimeZoneOffsetTest struct { - format string - value string - expectedoffset int -} - -var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{ - {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)}, - {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)}, - {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8}, - {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8}, - {"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)}, - {"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8}, -} - -func TestParseSecondsInTimeZone(t *testing.T) { - // should accept timezone offsets with seconds like: Zone America/New_York -4:56:02 - LMT 1883 Nov 18 12:03:58 - for _, test := range secondsTimeZoneOffsetTests { - time, err := Parse(test.format, test.value) - if err != nil { - t.Fatal("error parsing date:", err) - } - _, offset := time.Zone() - if offset != test.expectedoffset { - t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset) - } - } -} - -func TestFormatSecondsInTimeZone(t *testing.T) { - d := Date(1871, 9, 17, 20, 4, 26, 0, FixedZone("LMT", -(34*60+8))) - timestr := d.Format("2006-01-02T15:04:05Z070000") - expected := "1871-09-17T20:04:26-003408" - if timestr != expected { - t.Errorf("Got %s, want %s", timestr, expected) - } -} diff --git a/src/pkg/time/genzabbrs.go b/src/pkg/time/genzabbrs.go deleted file mode 100644 index 7c637cb43..000000000 --- a/src/pkg/time/genzabbrs.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2013 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. - -// +build ignore - -// -// usage: -// -// go run genzabbrs.go | gofmt > $GOROOT/src/pkg/time/zoneinfo_abbrs_windows.go -// - -package main - -import ( - "encoding/xml" - "io/ioutil" - "log" - "net/http" - "os" - "sort" - "text/template" - "time" -) - -// getAbbrs finds timezone abbreviations (standard and daylight saving time) -// for location l. -func getAbbrs(l *time.Location) (st, dt string) { - t := time.Date(time.Now().Year(), 0, 0, 0, 0, 0, 0, l) - abbr1, off1 := t.Zone() - for i := 0; i < 12; i++ { - t = t.AddDate(0, 1, 0) - abbr2, off2 := t.Zone() - if abbr1 != abbr2 { - if off2-off1 < 0 { // southern hemisphere - abbr1, abbr2 = abbr2, abbr1 - } - return abbr1, abbr2 - } - } - return abbr1, abbr1 -} - -type zone struct { - WinName string - UnixName string - StTime string - DSTime string -} - -type zones []*zone - -func (zs zones) Len() int { return len(zs) } -func (zs zones) Swap(i, j int) { zs[i], zs[j] = zs[j], zs[i] } -func (zs zones) Less(i, j int) bool { return zs[i].UnixName < zs[j].UnixName } - -const wzURL = "http://unicode.org/cldr/data/common/supplemental/windowsZones.xml" - -type MapZone struct { - Other string `xml:"other,attr"` - Territory string `xml:"territory,attr"` - Type string `xml:"type,attr"` -} - -type SupplementalData struct { - Zones []MapZone `xml:"windowsZones>mapTimezones>mapZone"` -} - -func readWindowsZones() (zones, error) { - r, err := http.Get(wzURL) - if err != nil { - return nil, err - } - defer r.Body.Close() - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, err - } - - var sd SupplementalData - err = xml.Unmarshal(data, &sd) - if err != nil { - return nil, err - } - zs := make(zones, 0) - for _, z := range sd.Zones { - if z.Territory != "001" { - // to avoid dups. I don't know why. - continue - } - l, err := time.LoadLocation(z.Type) - if err != nil { - return nil, err - } - st, dt := getAbbrs(l) - zs = append(zs, &zone{ - WinName: z.Other, - UnixName: z.Type, - StTime: st, - DSTime: dt, - }) - } - return zs, nil -} - -func main() { - zs, err := readWindowsZones() - if err != nil { - log.Fatal(err) - } - sort.Sort(zs) - var v = struct { - URL string - Zs zones - }{ - wzURL, - zs, - } - err = template.Must(template.New("prog").Parse(prog)).Execute(os.Stdout, v) - if err != nil { - log.Fatal(err) - } -} - -const prog = ` -// Copyright 2013 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. - -// generated by genzabbrs.go from -// {{.URL}} - -package time - -type abbr struct { - std string - dst string -} - -var abbrs = map[string]abbr{ -{{range .Zs}} "{{.WinName}}": {"{{.StTime}}", "{{.DSTime}}"}, // {{.UnixName}} -{{end}}} - -` diff --git a/src/pkg/time/internal_test.go b/src/pkg/time/internal_test.go deleted file mode 100644 index 2243d3668..000000000 --- a/src/pkg/time/internal_test.go +++ /dev/null @@ -1,92 +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 ( - "errors" - "runtime" -) - -func init() { - // force US/Pacific for time zone tests - ForceUSPacificForTesting() -} - -var Interrupt = interrupt -var DaysIn = daysIn - -func empty(now int64, arg interface{}) {} - -// Test that a runtimeTimer with a duration so large it overflows -// does not cause other timers to hang. -// -// This test has to be in internal_test.go since it fiddles with -// unexported data structures. -func CheckRuntimeTimerOverflow() error { - // We manually create a runtimeTimer to bypass the overflow - // detection logic in NewTimer: we're testing the underlying - // runtime.addtimer function. - r := &runtimeTimer{ - when: runtimeNano() + (1<<63 - 1), - f: empty, - arg: nil, - } - startTimer(r) - - timeout := 100 * Millisecond - switch runtime.GOOS { - // Allow more time for gobuilder to succeed. - case "windows": - timeout = Second - case "plan9": - // TODO(0intro): We don't know why it is needed. - timeout = 3 * Second - } - - // Start a goroutine that should send on t.C before the timeout. - t := NewTimer(1) - - defer func() { - // Subsequent tests won't work correctly if we don't stop the - // overflow timer and kick the timer proc back into service. - // - // The timer proc is now sleeping and can only be awoken by - // adding a timer to the *beginning* of the heap. We can't - // wake it up by calling NewTimer since other tests may have - // left timers running that should have expired before ours. - // Instead we zero the overflow timer duration and start it - // once more. - stopTimer(r) - t.Stop() - r.when = 0 - startTimer(r) - }() - - // Try to receive from t.C before the timeout. It will succeed - // iff the previous sleep was able to finish. We're forced to - // spin and yield after trying to receive since we can't start - // any more timers (they might hang due to the same bug we're - // now testing). - stop := Now().Add(timeout) - for { - select { - case <-t.C: - return nil // It worked! - default: - if Now().After(stop) { - return errors.New("runtime timer stuck: overflow in addtimer") - } - // Issue 6874. This test previously called runtime.Gosched to try to yield - // to the goroutine servicing t, however the scheduler has a bias towards the - // previously running goroutine in an idle system. Combined with high load due - // to all CPUs busy running tests t's goroutine could be delayed beyond the - // timeout window. - // - // Calling runtime.GC() reduces the worst case lantency for scheduling t by 20x - // under the current Go 1.3 scheduler. - runtime.GC() - } - } -} diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go deleted file mode 100644 index 6a03f417b..000000000 --- a/src/pkg/time/sleep.go +++ /dev/null @@ -1,122 +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 - -// Sleep pauses the current goroutine for at least the duration d. -// A negative or zero duration causes Sleep to return immediately. -func Sleep(d Duration) - -// runtimeNano returns the current value of the runtime clock in nanoseconds. -func runtimeNano() int64 - -// Interface to timers implemented in package runtime. -// Must be in sync with ../runtime/runtime.h:/^struct.Timer$ -type runtimeTimer struct { - i int32 - when int64 - period int64 - f func(int64, interface{}) // NOTE: must not be closure - arg interface{} -} - -// when is a helper function for setting the 'when' field of a runtimeTimer. -// It returns what the time will be, in nanoseconds, Duration d in the future. -// If d is negative, it is ignored. If the returned value would be less than -// zero because of an overflow, MaxInt64 is returned. -func when(d Duration) int64 { - if d <= 0 { - return runtimeNano() - } - t := runtimeNano() + int64(d) - if t < 0 { - t = 1<<63 - 1 // math.MaxInt64 - } - return t -} - -func startTimer(*runtimeTimer) -func stopTimer(*runtimeTimer) bool - -// The Timer type represents a single event. -// When the Timer expires, the current time will be sent on C, -// unless the Timer was created by AfterFunc. -type Timer struct { - C <-chan Time - r runtimeTimer -} - -// Stop prevents the Timer from firing. -// It returns true if the call stops the timer, false if the timer has already -// expired or been stopped. -// Stop does not close the channel, to prevent a read from the channel succeeding -// incorrectly. -func (t *Timer) Stop() bool { - return stopTimer(&t.r) -} - -// NewTimer creates a new Timer that will send -// the current time on its channel after at least duration d. -func NewTimer(d Duration) *Timer { - c := make(chan Time, 1) - t := &Timer{ - C: c, - r: runtimeTimer{ - when: when(d), - f: sendTime, - arg: c, - }, - } - startTimer(&t.r) - return t -} - -// Reset changes the timer to expire after duration d. -// It returns true if the timer had been active, false if the timer had -// expired or been stopped. -func (t *Timer) Reset(d Duration) bool { - w := when(d) - active := stopTimer(&t.r) - t.r.when = w - startTimer(&t.r) - return active -} - -func sendTime(now int64, c interface{}) { - // Non-blocking send of time on c. - // Used in NewTimer, it cannot block anyway (buffer). - // Used in NewTicker, dropping sends on the floor is - // the desired behavior when the reader gets behind, - // because the sends are periodic. - select { - case c.(chan Time) <- Now(): - default: - } -} - -// After waits for the duration to elapse and then sends the current time -// on the returned channel. -// It is equivalent to NewTimer(d).C. -func After(d Duration) <-chan Time { - return NewTimer(d).C -} - -// AfterFunc waits for the duration to elapse and then calls f -// in its own goroutine. It returns a Timer that can -// be used to cancel the call using its Stop method. -func AfterFunc(d Duration, f func()) *Timer { - t := &Timer{ - r: runtimeTimer{ - when: when(d), - f: goFunc, - arg: f, - }, - } - startTimer(&t.r) - return t -} - -func goFunc(now int64, arg interface{}) { - go arg.(func())() -} diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go deleted file mode 100644 index 03f8e732c..000000000 --- a/src/pkg/time/sleep_test.go +++ /dev/null @@ -1,393 +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 ( - "errors" - "fmt" - "runtime" - "sort" - "sync" - "sync/atomic" - "testing" - . "time" -) - -func TestSleep(t *testing.T) { - const delay = 100 * Millisecond - go func() { - Sleep(delay / 2) - Interrupt() - }() - start := Now() - Sleep(delay) - duration := Now().Sub(start) - if duration < delay { - t.Fatalf("Sleep(%s) slept for only %s", 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(1 * Second) - } else { - c <- true - } - } - - AfterFunc(0, f) - <-c -} - -func TestAfterStress(t *testing.T) { - stop := uint32(0) - go func() { - for atomic.LoadUint32(&stop) == 0 { - runtime.GC() - // Yield so that the OS can wake up the timer thread, - // so that it can generate channel sends for the main goroutine, - // which will eventually set stop = 1 for us. - Sleep(Nanosecond) - } - }() - ticker := NewTicker(1) - for i := 0; i < 100; i++ { - <-ticker.C - } - ticker.Stop() - atomic.StoreUint32(&stop, 1) -} - -func benchmark(b *testing.B, bench func(n int)) { - garbage := make([]*Timer, 1<<17) - for i := 0; i < len(garbage); i++ { - garbage[i] = AfterFunc(Hour, nil) - } - b.ResetTimer() - - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - bench(1000) - } - }) - - b.StopTimer() - for i := 0; i < len(garbage); i++ { - garbage[i].Stop() - } -} - -func BenchmarkAfterFunc(b *testing.B) { - benchmark(b, func(n int) { - c := make(chan bool) - var f func() - f = func() { - n-- - if n >= 0 { - AfterFunc(0, f) - } else { - c <- true - } - } - - AfterFunc(0, f) - <-c - }) -} - -func BenchmarkAfter(b *testing.B) { - benchmark(b, func(n int) { - for i := 0; i < n; i++ { - <-After(1) - } - }) -} - -func BenchmarkStop(b *testing.B) { - benchmark(b, func(n int) { - for i := 0; i < n; i++ { - NewTimer(1 * Second).Stop() - } - }) -} - -func BenchmarkSimultaneousAfterFunc(b *testing.B) { - benchmark(b, func(n int) { - var wg sync.WaitGroup - wg.Add(n) - for i := 0; i < n; i++ { - AfterFunc(0, wg.Done) - } - wg.Wait() - }) -} - -func BenchmarkStartStop(b *testing.B) { - benchmark(b, func(n int) { - timers := make([]*Timer, n) - for i := 0; i < n; i++ { - timers[i] = AfterFunc(Hour, nil) - } - - for i := 0; i < n; i++ { - timers[i].Stop() - } - }) -} - -func TestAfter(t *testing.T) { - const delay = 100 * Millisecond - start := Now() - end := <-After(delay) - if duration := Now().Sub(start); duration < delay { - t.Fatalf("After(%s) slept for only %d ns", delay, duration) - } - if min := start.Add(delay); end.Before(min) { - t.Fatalf("After(%s) expect >= %s, got %s", delay, min, end) - } -} - -func TestAfterTick(t *testing.T) { - const Count = 10 - Delta := 100 * Millisecond - if testing.Short() { - Delta = 10 * Millisecond - } - t0 := Now() - for i := 0; i < Count; i++ { - <-After(Delta) - } - t1 := Now() - d := t1.Sub(t0) - target := Delta * Count - if d < target*9/10 { - t.Fatalf("%d ticks of %s too fast: took %s, expected %s", Count, Delta, d, target) - } - if !testing.Short() && d > target*30/10 { - t.Fatalf("%d ticks of %s too slow: took %s, expected %s", Count, Delta, d, target) - } -} - -func TestAfterStop(t *testing.T) { - AfterFunc(100*Millisecond, func() {}) - t0 := NewTimer(50 * Millisecond) - c1 := make(chan bool, 1) - t1 := AfterFunc(150*Millisecond, func() { c1 <- true }) - c2 := After(200 * Millisecond) - 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 := errors.New("!=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 Time -} - -func await(slot int, result chan<- afterResult, ac <-chan Time) { - result <- afterResult{slot, <-ac} -} - -func testAfterQueuing(t *testing.T) error { - Delta := 100 * Millisecond - if testing.Short() { - Delta = 20 * Millisecond - } - // 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 := Now() - for _, slot := range slots { - go await(slot, result, After(Duration(slot)*Delta)) - } - sort.Ints(slots) - for _, slot := range slots { - r := <-result - if r.slot != slot { - return fmt.Errorf("after slot %d, expected %d", r.slot, slot) - } - dt := r.t.Sub(t0) - target := Duration(slot) * Delta - if dt < target-Delta/2 || dt > target+Delta*10 { - return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-Delta/2, target+Delta*10) - } - } - return nil -} - -func TestTimerStopStress(t *testing.T) { - if testing.Short() { - return - } - for i := 0; i < 100; i++ { - go func(i int) { - timer := AfterFunc(2*Second, func() { - t.Fatalf("timer %d was not stopped", i) - }) - Sleep(1 * Second) - timer.Stop() - }(i) - } - Sleep(3 * Second) -} - -func TestSleepZeroDeadlock(t *testing.T) { - // Sleep(0) used to hang, the sequence of events was as follows. - // Sleep(0) sets G's status to Gwaiting, but then immediately returns leaving the status. - // Then the goroutine calls e.g. new and falls down into the scheduler due to pending GC. - // After the GC nobody wakes up the goroutine from Gwaiting status. - defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) - c := make(chan bool) - go func() { - for i := 0; i < 100; i++ { - runtime.GC() - } - c <- true - }() - for i := 0; i < 100; i++ { - Sleep(0) - tmp := make(chan bool, 1) - tmp <- true - <-tmp - } - <-c -} - -func testReset(d Duration) error { - t0 := NewTimer(2 * d) - Sleep(d) - if t0.Reset(3*d) != true { - return errors.New("resetting unfired timer returned false") - } - Sleep(2 * d) - select { - case <-t0.C: - return errors.New("timer fired early") - default: - } - Sleep(2 * d) - select { - case <-t0.C: - default: - return errors.New("reset timer did not fire") - } - - if t0.Reset(50*Millisecond) != false { - return errors.New("resetting expired timer returned true") - } - return nil -} - -func TestReset(t *testing.T) { - // We try to run this test with increasingly larger multiples - // until one works so slow, loaded hardware isn't as flaky, - // but without slowing down fast machines unnecessarily. - const unit = 25 * Millisecond - tries := []Duration{ - 1 * unit, - 3 * unit, - 7 * unit, - 15 * unit, - } - var err error - for _, d := range tries { - err = testReset(d) - if err == nil { - t.Logf("passed using duration %v", d) - return - } - } - t.Error(err) -} - -// Test that sleeping for an interval so large it overflows does not -// result in a short sleep duration. -func TestOverflowSleep(t *testing.T) { - const big = Duration(int64(1<<63 - 1)) - select { - case <-After(big): - t.Fatalf("big timeout fired") - case <-After(25 * Millisecond): - // OK - } - const neg = Duration(-1 << 63) - select { - case <-After(neg): - // OK - case <-After(1 * Second): - t.Fatalf("negative timeout didn't fire") - } -} - -// Test that a panic while deleting a timer does not leave -// the timers mutex held, deadlocking a ticker.Stop in a defer. -func TestIssue5745(t *testing.T) { - ticker := NewTicker(Hour) - defer func() { - // would deadlock here before the fix due to - // lock taken before the segfault. - ticker.Stop() - - if r := recover(); r == nil { - t.Error("Expected panic, but none happened.") - } - }() - - // cause a panic due to a segfault - var timer *Timer - timer.Stop() - t.Error("Should be unreachable.") -} - -func TestOverflowRuntimeTimer(t *testing.T) { - if testing.Short() { - t.Skip("skipping in short mode, see issue 6874") - } - if err := CheckRuntimeTimerOverflow(); err != nil { - t.Fatalf(err.Error()) - } -} diff --git a/src/pkg/time/sys_plan9.go b/src/pkg/time/sys_plan9.go deleted file mode 100644 index 848472944..000000000 --- a/src/pkg/time/sys_plan9.go +++ /dev/null @@ -1,76 +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. - -// +build plan9 - -package time - -import ( - "errors" - "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 open(name string) (uintptr, error) { - fd, err := syscall.Open(name, syscall.O_RDONLY) - if err != nil { - return 0, err - } - return uintptr(fd), nil -} - -func closefd(fd uintptr) { - syscall.Close(int(fd)) -} - -func preadn(fd uintptr, buf []byte, off int) error { - whence := 0 - if off < 0 { - whence = 2 - } - if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil { - return err - } - for len(buf) > 0 { - m, err := syscall.Read(int(fd), buf) - if m <= 0 { - if err == nil { - return errors.New("short read") - } - return err - } - buf = buf[m:] - } - return nil -} diff --git a/src/pkg/time/sys_unix.go b/src/pkg/time/sys_unix.go deleted file mode 100644 index 379e13d6a..000000000 --- a/src/pkg/time/sys_unix.go +++ /dev/null @@ -1,76 +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. - -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris - -package time - -import ( - "errors" - "syscall" -) - -// for testing: whatever interrupts a sleep -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 -} - -func open(name string) (uintptr, error) { - fd, err := syscall.Open(name, syscall.O_RDONLY, 0) - if err != nil { - return 0, err - } - return uintptr(fd), nil -} - -func closefd(fd uintptr) { - syscall.Close(int(fd)) -} - -func preadn(fd uintptr, buf []byte, off int) error { - whence := 0 - if off < 0 { - whence = 2 - } - if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil { - return err - } - for len(buf) > 0 { - m, err := syscall.Read(int(fd), buf) - if m <= 0 { - if err == nil { - return errors.New("short read") - } - return err - } - buf = buf[m:] - } - return nil -} diff --git a/src/pkg/time/sys_windows.go b/src/pkg/time/sys_windows.go deleted file mode 100644 index de63b4bf4..000000000 --- a/src/pkg/time/sys_windows.go +++ /dev/null @@ -1,73 +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 ( - "errors" - "syscall" -) - -// for testing: whatever interrupts a sleep -func interrupt() { -} - -// 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 -} - -func open(name string) (uintptr, error) { - fd, err := syscall.Open(name, syscall.O_RDONLY, 0) - if err != nil { - return 0, err - } - return uintptr(fd), nil -} - -func closefd(fd uintptr) { - syscall.Close(syscall.Handle(fd)) -} - -func preadn(fd uintptr, buf []byte, off int) error { - whence := 0 - if off < 0 { - whence = 2 - } - if _, err := syscall.Seek(syscall.Handle(fd), int64(off), whence); err != nil { - return err - } - for len(buf) > 0 { - m, err := syscall.Read(syscall.Handle(fd), buf) - if m <= 0 { - if err == nil { - return errors.New("short read") - } - return err - } - buf = buf[m:] - } - return nil -} diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go deleted file mode 100644 index 19007841e..000000000 --- a/src/pkg/time/tick.go +++ /dev/null @@ -1,56 +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 "errors" - -// A Ticker holds a channel that delivers `ticks' of a clock -// at intervals. -type Ticker struct { - C <-chan Time // The channel on which the ticks are delivered. - r runtimeTimer -} - -// NewTicker returns a new Ticker containing a channel that will send the -// time with a period specified by the duration argument. -// It adjusts the intervals or drops ticks to make up for slow receivers. -// The duration d must be greater than zero; if not, NewTicker will panic. -// Stop the ticker to release associated resources. -func NewTicker(d Duration) *Ticker { - if d <= 0 { - panic(errors.New("non-positive interval for NewTicker")) - } - // Give the channel a 1-element time buffer. - // If the client falls behind while reading, we drop ticks - // on the floor until the client catches up. - c := make(chan Time, 1) - t := &Ticker{ - C: c, - r: runtimeTimer{ - when: when(d), - period: int64(d), - f: sendTime, - arg: c, - }, - } - startTimer(&t.r) - return t -} - -// Stop turns off a ticker. After Stop, no more ticks will be sent. -// Stop does not close the channel, to prevent a read from the channel succeeding -// incorrectly. -func (t *Ticker) Stop() { - stopTimer(&t.r) -} - -// 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(d Duration) <-chan Time { - if d <= 0 { - return nil - } - return NewTicker(d).C -} diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go deleted file mode 100644 index 32f4740ad..000000000 --- a/src/pkg/time/tick_test.go +++ /dev/null @@ -1,78 +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 Count = 10 - Delta := 100 * Millisecond - ticker := NewTicker(Delta) - t0 := Now() - for i := 0; i < Count; i++ { - <-ticker.C - } - ticker.Stop() - t1 := Now() - dt := t1.Sub(t0) - target := Delta * Count - slop := target * 2 / 10 - if dt < target-slop || (!testing.Short() && dt > target+slop) { - t.Fatalf("%d %s ticks took %s, expected [%s,%s]", Count, Delta, dt, target-slop, target+slop) - } - // 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) { - Delta := 100 * Millisecond - if testing.Short() { - Delta = 20 * Millisecond - } - for i := 0; i < 3; i++ { - ticker := NewTicker(Delta) - <-ticker.C - ticker.Stop() - } -} - -// Test the Tick convenience wrapper. -func TestTick(t *testing.T) { - // Test that giving a negative duration returns nil. - if got := Tick(-1); got != nil { - t.Errorf("Tick(-1) = %v; want nil", got) - } -} - -// Test that NewTicker panics when given a duration less than zero. -func TestNewTickerLtZeroDuration(t *testing.T) { - defer func() { - if err := recover(); err == nil { - t.Errorf("NewTicker(-1) should have panicked") - } - }() - NewTicker(-1) -} - -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 0a2b09142..000000000 --- a/src/pkg/time/time.go +++ /dev/null @@ -1,1206 +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. -// -// The calendrical calculations always assume a Gregorian calendar. -package time - -import "errors" - -// A Time represents an instant in time with nanosecond precision. -// -// Programs using times should typically store and pass them as values, -// not pointers. That is, time variables and struct fields should be of -// type time.Time, not *time.Time. A Time value can be used by -// multiple goroutines simultaneously. -// -// Time instants can be compared using the Before, After, and Equal methods. -// The Sub method subtracts two instants, producing a Duration. -// The Add method adds a Time and a Duration, producing a Time. -// -// The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC. -// As this time is unlikely to come up in practice, the IsZero method gives -// a simple way of detecting a time that has not been initialized explicitly. -// -// Each Time has associated with it a Location, consulted when computing the -// presentation form of the time, such as in the Format, Hour, and Year methods. -// The methods Local, UTC, and In return a Time with a specific location. -// Changing the location in this way changes only the presentation; it does not -// change the instant in time being denoted and therefore does not affect the -// computations described in earlier paragraphs. -// -type Time struct { - // sec gives the number of seconds elapsed since - // January 1, year 1 00:00:00 UTC. - sec int64 - - // nsec specifies a non-negative nanosecond - // offset within the second named by Seconds. - // It must be in the range [0, 999999999]. - // - // It is declared as uintptr instead of int32 or uint32 - // to avoid garbage collector aliasing in the case where - // on a 64-bit system the int32 or uint32 field is written - // over the low half of a pointer, creating another pointer. - // TODO(rsc): When the garbage collector is completely - // precise, change back to int32. - nsec uintptr - - // loc specifies the Location that should be used to - // determine the minute, hour, month, day, and year - // that correspond to this Time. - // Only the zero Time has a nil Location. - // In that case it is interpreted to mean UTC. - loc *Location -} - -// After reports whether the time instant t is after u. -func (t Time) After(u Time) bool { - return t.sec > u.sec || t.sec == u.sec && t.nsec > u.nsec -} - -// Before reports whether the time instant t is before u. -func (t Time) Before(u Time) bool { - return t.sec < u.sec || t.sec == u.sec && t.nsec < u.nsec -} - -// Equal reports whether t and u represent the same time instant. -// Two times can be equal even if they are in different locations. -// For example, 6:00 +0200 CEST and 4:00 UTC are Equal. -// This comparison is different from using t == u, which also compares -// the locations. -func (t Time) Equal(u Time) bool { - return t.sec == u.sec && t.nsec == u.nsec -} - -// A Month specifies a month of the year (January = 1, ...). -type Month int - -const ( - January Month = 1 + iota - February - March - April - May - June - July - August - September - October - November - December -) - -var months = [...]string{ - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", -} - -// String returns the English name of the month ("January", "February", ...). -func (m Month) String() string { return months[m-1] } - -// A Weekday specifies a day of the week (Sunday = 0, ...). -type Weekday int - -const ( - Sunday Weekday = iota - Monday - Tuesday - Wednesday - Thursday - Friday - Saturday -) - -var days = [...]string{ - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", -} - -// String returns the English name of the day ("Sunday", "Monday", ...). -func (d Weekday) String() string { return days[d] } - -// Computations on time. -// -// The zero value for a Time is defined to be -// January 1, year 1, 00:00:00.000000000 UTC -// which (1) looks like a zero, or as close as you can get in a date -// (1-1-1 00:00:00 UTC), (2) is unlikely enough to arise in practice to -// be a suitable "not set" sentinel, unlike Jan 1 1970, and (3) has a -// non-negative year even in time zones west of UTC, unlike 1-1-0 -// 00:00:00 UTC, which would be 12-31-(-1) 19:00:00 in New York. -// -// The zero Time value does not force a specific epoch for the time -// representation. For example, to use the Unix epoch internally, we -// could define that to distinguish a zero value from Jan 1 1970, that -// time would be represented by sec=-1, nsec=1e9. However, it does -// suggest a representation, namely using 1-1-1 00:00:00 UTC as the -// epoch, and that's what we do. -// -// The Add and Sub computations are oblivious to the choice of epoch. -// -// The presentation computations - year, month, minute, and so on - all -// rely heavily on division and modulus by positive constants. For -// calendrical calculations we want these divisions to round down, even -// for negative values, so that the remainder is always positive, but -// Go's division (like most hardware division instructions) rounds to -// zero. We can still do those computations and then adjust the result -// for a negative numerator, but it's annoying to write the adjustment -// over and over. Instead, we can change to a different epoch so long -// ago that all the times we care about will be positive, and then round -// to zero and round down coincide. These presentation routines already -// have to add the zone offset, so adding the translation to the -// alternate epoch is cheap. For example, having a non-negative time t -// means that we can write -// -// sec = t % 60 -// -// instead of -// -// sec = t % 60 -// if sec < 0 { -// sec += 60 -// } -// -// everywhere. -// -// The calendar runs on an exact 400 year cycle: a 400-year calendar -// printed for 1970-2469 will apply as well to 2470-2869. Even the days -// of the week match up. It simplifies the computations to choose the -// cycle boundaries so that the exceptional years are always delayed as -// long as possible. That means choosing a year equal to 1 mod 400, so -// that the first leap year is the 4th year, the first missed leap year -// is the 100th year, and the missed missed leap year is the 400th year. -// So we'd prefer instead to print a calendar for 2001-2400 and reuse it -// for 2401-2800. -// -// Finally, it's convenient if the delta between the Unix epoch and -// long-ago epoch is representable by an int64 constant. -// -// These three considerations—choose an epoch as early as possible, that -// uses a year equal to 1 mod 400, and that is no more than 2⁶³ seconds -// earlier than 1970—bring us to the year -292277022399. We refer to -// this year as the absolute zero year, and to times measured as a uint64 -// seconds since this year as absolute times. -// -// Times measured as an int64 seconds since the year 1—the representation -// used for Time's sec field—are called internal times. -// -// Times measured as an int64 seconds since the year 1970 are called Unix -// times. -// -// It is tempting to just use the year 1 as the absolute epoch, defining -// that the routines are only valid for years >= 1. However, the -// routines would then be invalid when displaying the epoch in time zones -// west of UTC, since it is year 0. It doesn't seem tenable to say that -// printing the zero time correctly isn't supported in half the time -// zones. By comparison, it's reasonable to mishandle some times in -// the year -292277022399. -// -// All this is opaque to clients of the API and can be changed if a -// better implementation presents itself. - -const ( - // The unsigned zero year for internal calculations. - // Must be 1 mod 400, and times before it will not compute correctly, - // but otherwise can be changed at will. - absoluteZeroYear = -292277022399 - - // The year of the zero Time. - // Assumed by the unixToInternal computation below. - internalYear = 1 - - // The year of the zero Unix time. - unixYear = 1970 - - // Offsets to convert between internal and absolute or Unix times. - absoluteToInternal int64 = (absoluteZeroYear - internalYear) * 365.2425 * secondsPerDay - internalToAbsolute = -absoluteToInternal - - unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay - internalToUnix int64 = -unixToInternal -) - -// IsZero reports whether t represents the zero time instant, -// January 1, year 1, 00:00:00 UTC. -func (t Time) IsZero() bool { - return t.sec == 0 && t.nsec == 0 -} - -// abs returns the time t as an absolute time, adjusted by the zone offset. -// It is called when computing a presentation property like Month or Hour. -func (t Time) abs() uint64 { - l := t.loc - // Avoid function calls when possible. - if l == nil || l == &localLoc { - l = l.get() - } - sec := t.sec + internalToUnix - if l != &utcLoc { - if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd { - sec += int64(l.cacheZone.offset) - } else { - _, offset, _, _, _ := l.lookup(sec) - sec += int64(offset) - } - } - return uint64(sec + (unixToInternal + internalToAbsolute)) -} - -// locabs is a combination of the Zone and abs methods, -// extracting both return values from a single zone lookup. -func (t Time) locabs() (name string, offset int, abs uint64) { - l := t.loc - if l == nil || l == &localLoc { - l = l.get() - } - // Avoid function call if we hit the local time cache. - sec := t.sec + internalToUnix - if l != &utcLoc { - if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd { - name = l.cacheZone.name - offset = l.cacheZone.offset - } else { - name, offset, _, _, _ = l.lookup(sec) - } - sec += int64(offset) - } else { - name = "UTC" - } - abs = uint64(sec + (unixToInternal + internalToAbsolute)) - return -} - -// Date returns the year, month, and day in which t occurs. -func (t Time) Date() (year int, month Month, day int) { - year, month, day, _ = t.date(true) - return -} - -// Year returns the year in which t occurs. -func (t Time) Year() int { - year, _, _, _ := t.date(false) - return year -} - -// Month returns the month of the year specified by t. -func (t Time) Month() Month { - _, month, _, _ := t.date(true) - return month -} - -// Day returns the day of the month specified by t. -func (t Time) Day() int { - _, _, day, _ := t.date(true) - return day -} - -// Weekday returns the day of the week specified by t. -func (t Time) Weekday() Weekday { - return absWeekday(t.abs()) -} - -// absWeekday is like Weekday but operates on an absolute time. -func absWeekday(abs uint64) Weekday { - // January 1 of the absolute year, like January 1 of 2001, was a Monday. - sec := (abs + uint64(Monday)*secondsPerDay) % secondsPerWeek - return Weekday(int(sec) / secondsPerDay) -} - -// ISOWeek returns the ISO 8601 year and week number in which t occurs. -// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to -// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1 -// of year n+1. -func (t Time) ISOWeek() (year, week int) { - year, month, day, yday := t.date(true) - wday := int(t.Weekday()+6) % 7 // weekday but Monday = 0. - const ( - Mon int = iota - Tue - Wed - Thu - Fri - Sat - Sun - ) - - // Calculate week as number of Mondays in year up to - // and including today, plus 1 because the first week is week 0. - // Putting the + 1 inside the numerator as a + 7 keeps the - // numerator from being negative, which would cause it to - // round incorrectly. - week = (yday - wday + 7) / 7 - - // The week number is now correct under the assumption - // that the first Monday of the year is in week 1. - // If Jan 1 is a Tuesday, Wednesday, or Thursday, the first Monday - // is actually in week 2. - jan1wday := (wday - yday + 7*53) % 7 - if Tue <= jan1wday && jan1wday <= Thu { - week++ - } - - // If the week number is still 0, we're in early January but in - // the last week of last year. - if week == 0 { - year-- - week = 52 - // A year has 53 weeks when Jan 1 or Dec 31 is a Thursday, - // meaning Jan 1 of the next year is a Friday - // or it was a leap year and Jan 1 of the next year is a Saturday. - if jan1wday == Fri || (jan1wday == Sat && isLeap(year)) { - week++ - } - } - - // December 29 to 31 are in week 1 of next year if - // they are after the last Thursday of the year and - // December 31 is a Monday, Tuesday, or Wednesday. - if month == December && day >= 29 && wday < Thu { - if dec31wday := (wday + 31 - day) % 7; Mon <= dec31wday && dec31wday <= Wed { - year++ - week = 1 - } - } - - return -} - -// Clock returns the hour, minute, and second within the day specified by t. -func (t Time) Clock() (hour, min, sec int) { - return absClock(t.abs()) -} - -// absClock is like clock but operates on an absolute time. -func absClock(abs uint64) (hour, min, sec int) { - sec = int(abs % secondsPerDay) - hour = sec / secondsPerHour - sec -= hour * secondsPerHour - min = sec / secondsPerMinute - sec -= min * secondsPerMinute - return -} - -// Hour returns the hour within the day specified by t, in the range [0, 23]. -func (t Time) Hour() int { - return int(t.abs()%secondsPerDay) / secondsPerHour -} - -// Minute returns the minute offset within the hour specified by t, in the range [0, 59]. -func (t Time) Minute() int { - return int(t.abs()%secondsPerHour) / secondsPerMinute -} - -// Second returns the second offset within the minute specified by t, in the range [0, 59]. -func (t Time) Second() int { - return int(t.abs() % secondsPerMinute) -} - -// Nanosecond returns the nanosecond offset within the second specified by t, -// in the range [0, 999999999]. -func (t Time) Nanosecond() int { - return int(t.nsec) -} - -// YearDay returns the day of the year specified by t, in the range [1,365] for non-leap years, -// and [1,366] in leap years. -func (t Time) YearDay() int { - _, _, _, yday := t.date(false) - return yday + 1 -} - -// A Duration represents the elapsed time between two instants -// as an int64 nanosecond count. The representation limits the -// largest representable duration to approximately 290 years. -type Duration int64 - -const ( - minDuration Duration = -1 << 63 - maxDuration Duration = 1<<63 - 1 -) - -// Common durations. There is no definition for units of Day or larger -// to avoid confusion across daylight savings time zone transitions. -// -// To count the number of units in a Duration, divide: -// second := time.Second -// fmt.Print(int64(second/time.Millisecond)) // prints 1000 -// -// To convert an integer number of units to a Duration, multiply: -// seconds := 10 -// fmt.Print(time.Duration(seconds)*time.Second) // prints 10s -// -const ( - Nanosecond Duration = 1 - Microsecond = 1000 * Nanosecond - Millisecond = 1000 * Microsecond - Second = 1000 * Millisecond - Minute = 60 * Second - Hour = 60 * Minute -) - -// String returns a string representing the duration in the form "72h3m0.5s". -// Leading zero units are omitted. As a special case, durations less than one -// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure -// that the leading digit is non-zero. The zero duration formats as 0, -// with no unit. -func (d Duration) String() string { - // Largest time is 2540400h10m10.000000000s - var buf [32]byte - w := len(buf) - - u := uint64(d) - neg := d < 0 - if neg { - u = -u - } - - if u < uint64(Second) { - // Special case: if duration is smaller than a second, - // use smaller units, like 1.2ms - var ( - prec int - unit byte - ) - switch { - case u == 0: - return "0" - case u < uint64(Microsecond): - // print nanoseconds - prec = 0 - unit = 'n' - case u < uint64(Millisecond): - // print microseconds - prec = 3 - unit = 'u' - default: - // print milliseconds - prec = 6 - unit = 'm' - } - w -= 2 - buf[w] = unit - buf[w+1] = 's' - w, u = fmtFrac(buf[:w], u, prec) - w = fmtInt(buf[:w], u) - } else { - w-- - buf[w] = 's' - - w, u = fmtFrac(buf[:w], u, 9) - - // u is now integer seconds - w = fmtInt(buf[:w], u%60) - u /= 60 - - // u is now integer minutes - if u > 0 { - w-- - buf[w] = 'm' - w = fmtInt(buf[:w], u%60) - u /= 60 - - // u is now integer hours - // Stop at hours because days can be different lengths. - if u > 0 { - w-- - buf[w] = 'h' - w = fmtInt(buf[:w], u) - } - } - } - - if neg { - w-- - buf[w] = '-' - } - - return string(buf[w:]) -} - -// fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the -// tail of buf, omitting trailing zeros. it omits the decimal -// point too when the fraction is 0. It returns the index where the -// output bytes begin and the value v/10**prec. -func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) { - // Omit trailing zeros up to and including decimal point. - w := len(buf) - print := false - for i := 0; i < prec; i++ { - digit := v % 10 - print = print || digit != 0 - if print { - w-- - buf[w] = byte(digit) + '0' - } - v /= 10 - } - if print { - w-- - buf[w] = '.' - } - return w, v -} - -// fmtInt formats v into the tail of buf. -// It returns the index where the output begins. -func fmtInt(buf []byte, v uint64) int { - w := len(buf) - if v == 0 { - w-- - buf[w] = '0' - } else { - for v > 0 { - w-- - buf[w] = byte(v%10) + '0' - v /= 10 - } - } - return w -} - -// Nanoseconds returns the duration as an integer nanosecond count. -func (d Duration) Nanoseconds() int64 { return int64(d) } - -// These methods return float64 because the dominant -// use case is for printing a floating point number like 1.5s, and -// a truncation to integer would make them not useful in those cases. -// Splitting the integer and fraction ourselves guarantees that -// converting the returned float64 to an integer rounds the same -// way that a pure integer conversion would have, even in cases -// where, say, float64(d.Nanoseconds())/1e9 would have rounded -// differently. - -// Seconds returns the duration as a floating point number of seconds. -func (d Duration) Seconds() float64 { - sec := d / Second - nsec := d % Second - return float64(sec) + float64(nsec)*1e-9 -} - -// Minutes returns the duration as a floating point number of minutes. -func (d Duration) Minutes() float64 { - min := d / Minute - nsec := d % Minute - return float64(min) + float64(nsec)*(1e-9/60) -} - -// Hours returns the duration as a floating point number of hours. -func (d Duration) Hours() float64 { - hour := d / Hour - nsec := d % Hour - return float64(hour) + float64(nsec)*(1e-9/60/60) -} - -// Add returns the time t+d. -func (t Time) Add(d Duration) Time { - t.sec += int64(d / 1e9) - nsec := int32(t.nsec) + int32(d%1e9) - if nsec >= 1e9 { - t.sec++ - nsec -= 1e9 - } else if nsec < 0 { - t.sec-- - nsec += 1e9 - } - t.nsec = uintptr(nsec) - return t -} - -// Sub returns the duration t-u. If the result exceeds the maximum (or minimum) -// value that can be stored in a Duration, the maximum (or minimum) duration -// will be returned. -// To compute t-d for a duration d, use t.Add(-d). -func (t Time) Sub(u Time) Duration { - d := Duration(t.sec-u.sec)*Second + Duration(int32(t.nsec)-int32(u.nsec)) - // Check for overflow or underflow. - switch { - case u.Add(d).Equal(t): - return d // d is correct - case t.Before(u): - return minDuration // t - u is negative out of range - default: - return maxDuration // t - u is positive out of range - } -} - -// Since returns the time elapsed since t. -// It is shorthand for time.Now().Sub(t). -func Since(t Time) Duration { - return Now().Sub(t) -} - -// AddDate returns the time corresponding to adding the -// given number of years, months, and days to t. -// For example, AddDate(-1, 2, 3) applied to January 1, 2011 -// returns March 4, 2010. -// -// AddDate normalizes its result in the same way that Date does, -// so, for example, adding one month to October 31 yields -// December 1, the normalized form for November 31. -func (t Time) AddDate(years int, months int, days int) Time { - year, month, day := t.Date() - hour, min, sec := t.Clock() - return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.loc) -} - -const ( - secondsPerMinute = 60 - secondsPerHour = 60 * 60 - secondsPerDay = 24 * secondsPerHour - secondsPerWeek = 7 * secondsPerDay - daysPer400Years = 365*400 + 97 - daysPer100Years = 365*100 + 24 - daysPer4Years = 365*4 + 1 -) - -// date computes the year, day of year, and when full=true, -// the month and day in which t occurs. -func (t Time) date(full bool) (year int, month Month, day int, yday int) { - return absDate(t.abs(), full) -} - -// absDate is like date but operates on an absolute time. -func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) { - // Split into time and day. - d := abs / secondsPerDay - - // Account for 400 year cycles. - n := d / daysPer400Years - y := 400 * n - d -= daysPer400Years * n - - // Cut off 100-year cycles. - // The last cycle has one extra leap year, so on the last day - // of that year, day / daysPer100Years will be 4 instead of 3. - // Cut it back down to 3 by subtracting n>>2. - n = d / daysPer100Years - n -= n >> 2 - y += 100 * n - d -= daysPer100Years * n - - // Cut off 4-year cycles. - // The last cycle has a missing leap year, which does not - // affect the computation. - n = d / daysPer4Years - y += 4 * n - d -= daysPer4Years * n - - // Cut off years within a 4-year cycle. - // The last year is a leap year, so on the last day of that year, - // day / 365 will be 4 instead of 3. Cut it back down to 3 - // by subtracting n>>2. - n = d / 365 - n -= n >> 2 - y += n - d -= 365 * n - - year = int(int64(y) + absoluteZeroYear) - yday = int(d) - - if !full { - return - } - - day = yday - if isLeap(year) { - // Leap year - switch { - case day > 31+29-1: - // After leap day; pretend it wasn't there. - day-- - case day == 31+29-1: - // Leap day. - month = February - day = 29 - return - } - } - - // Estimate month on assumption that every month has 31 days. - // The estimate may be too low by at most one month, so adjust. - month = Month(day / 31) - end := int(daysBefore[month+1]) - var begin int - if day >= end { - month++ - begin = end - } else { - begin = int(daysBefore[month]) - } - - month++ // because January is 1 - day = day - begin + 1 - return -} - -// daysBefore[m] counts the number of days in a non-leap year -// before month m begins. There is an entry for m=12, counting -// the number of days before January of next year (365). -var daysBefore = [...]int32{ - 0, - 31, - 31 + 28, - 31 + 28 + 31, - 31 + 28 + 31 + 30, - 31 + 28 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31, -} - -func daysIn(m Month, year int) int { - if m == February && isLeap(year) { - return 29 - } - return int(daysBefore[m] - daysBefore[m-1]) -} - -// Provided by package runtime. -func now() (sec int64, nsec int32) - -// Now returns the current local time. -func Now() Time { - sec, nsec := now() - return Time{sec + unixToInternal, uintptr(nsec), Local} -} - -// UTC returns t with the location set to UTC. -func (t Time) UTC() Time { - t.loc = UTC - return t -} - -// Local returns t with the location set to local time. -func (t Time) Local() Time { - t.loc = Local - return t -} - -// In returns t with the location information set to loc. -// -// In panics if loc is nil. -func (t Time) In(loc *Location) Time { - if loc == nil { - panic("time: missing Location in call to Time.In") - } - t.loc = loc - return t -} - -// Location returns the time zone information associated with t. -func (t Time) Location() *Location { - l := t.loc - if l == nil { - l = UTC - } - return l -} - -// Zone computes the time zone in effect at time t, returning the abbreviated -// name of the zone (such as "CET") and its offset in seconds east of UTC. -func (t Time) Zone() (name string, offset int) { - name, offset, _, _, _ = t.loc.lookup(t.sec + internalToUnix) - return -} - -// Unix returns t as a Unix time, the number of seconds elapsed -// since January 1, 1970 UTC. -func (t Time) Unix() int64 { - return t.sec + internalToUnix -} - -// UnixNano returns t as a Unix time, the number of nanoseconds elapsed -// since January 1, 1970 UTC. The result is undefined if the Unix time -// in nanoseconds cannot be represented by an int64. Note that this -// means the result of calling UnixNano on the zero Time is undefined. -func (t Time) UnixNano() int64 { - return (t.sec+internalToUnix)*1e9 + int64(t.nsec) -} - -const timeBinaryVersion byte = 1 - -// MarshalBinary implements the encoding.BinaryMarshaler interface. -func (t Time) MarshalBinary() ([]byte, error) { - var offsetMin int16 // minutes east of UTC. -1 is UTC. - - if t.Location() == &utcLoc { - offsetMin = -1 - } else { - _, offset := t.Zone() - if offset%60 != 0 { - return nil, errors.New("Time.MarshalBinary: zone offset has fractional minute") - } - offset /= 60 - if offset < -32768 || offset == -1 || offset > 32767 { - return nil, errors.New("Time.MarshalBinary: unexpected zone offset") - } - offsetMin = int16(offset) - } - - enc := []byte{ - timeBinaryVersion, // byte 0 : version - byte(t.sec >> 56), // bytes 1-8: seconds - byte(t.sec >> 48), - byte(t.sec >> 40), - byte(t.sec >> 32), - byte(t.sec >> 24), - byte(t.sec >> 16), - byte(t.sec >> 8), - byte(t.sec), - byte(t.nsec >> 24), // bytes 9-12: nanoseconds - byte(t.nsec >> 16), - byte(t.nsec >> 8), - byte(t.nsec), - byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes - byte(offsetMin), - } - - return enc, nil -} - -// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. -func (t *Time) UnmarshalBinary(data []byte) error { - buf := data - if len(buf) == 0 { - return errors.New("Time.UnmarshalBinary: no data") - } - - if buf[0] != timeBinaryVersion { - return errors.New("Time.UnmarshalBinary: unsupported version") - } - - if len(buf) != /*version*/ 1+ /*sec*/ 8+ /*nsec*/ 4+ /*zone offset*/ 2 { - return errors.New("Time.UnmarshalBinary: invalid length") - } - - buf = buf[1:] - t.sec = int64(buf[7]) | int64(buf[6])<<8 | int64(buf[5])<<16 | int64(buf[4])<<24 | - int64(buf[3])<<32 | int64(buf[2])<<40 | int64(buf[1])<<48 | int64(buf[0])<<56 - - buf = buf[8:] - t.nsec = uintptr(int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24) - - buf = buf[4:] - offset := int(int16(buf[1])|int16(buf[0])<<8) * 60 - - if offset == -1*60 { - t.loc = &utcLoc - } else if _, localoff, _, _, _ := Local.lookup(t.sec + internalToUnix); offset == localoff { - t.loc = Local - } else { - t.loc = FixedZone("", offset) - } - - return nil -} - -// TODO(rsc): Remove GobEncoder, GobDecoder, MarshalJSON, UnmarshalJSON in Go 2. -// The same semantics will be provided by the generic MarshalBinary, MarshalText, -// UnmarshalBinary, UnmarshalText. - -// GobEncode implements the gob.GobEncoder interface. -func (t Time) GobEncode() ([]byte, error) { - return t.MarshalBinary() -} - -// GobDecode implements the gob.GobDecoder interface. -func (t *Time) GobDecode(data []byte) error { - return t.UnmarshalBinary(data) -} - -// MarshalJSON implements the json.Marshaler interface. -// The time is a quoted string in RFC 3339 format, with sub-second precision added if present. -func (t Time) MarshalJSON() ([]byte, error) { - if y := t.Year(); y < 0 || y >= 10000 { - // RFC 3339 is clear that years are 4 digits exactly. - // See golang.org/issue/4556#c15 for more discussion. - return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]") - } - return []byte(t.Format(`"` + RFC3339Nano + `"`)), nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -// The time is expected to be a quoted string in RFC 3339 format. -func (t *Time) UnmarshalJSON(data []byte) (err error) { - // Fractional seconds are handled implicitly by Parse. - *t, err = Parse(`"`+RFC3339+`"`, string(data)) - return -} - -// MarshalText implements the encoding.TextMarshaler interface. -// The time is formatted in RFC 3339 format, with sub-second precision added if present. -func (t Time) MarshalText() ([]byte, error) { - if y := t.Year(); y < 0 || y >= 10000 { - return nil, errors.New("Time.MarshalText: year outside of range [0,9999]") - } - return []byte(t.Format(RFC3339Nano)), nil -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -// The time is expected to be in RFC 3339 format. -func (t *Time) UnmarshalText(data []byte) (err error) { - // Fractional seconds are handled implicitly by Parse. - *t, err = Parse(RFC3339, string(data)) - return -} - -// Unix returns the local Time corresponding to the given Unix time, -// sec seconds and nsec nanoseconds since January 1, 1970 UTC. -// It is valid to pass nsec outside the range [0, 999999999]. -func Unix(sec int64, nsec int64) Time { - if nsec < 0 || nsec >= 1e9 { - n := nsec / 1e9 - sec += n - nsec -= n * 1e9 - if nsec < 0 { - nsec += 1e9 - sec-- - } - } - return Time{sec + unixToInternal, uintptr(nsec), Local} -} - -func isLeap(year int) bool { - return year%4 == 0 && (year%100 != 0 || year%400 == 0) -} - -// norm returns nhi, nlo such that -// hi * base + lo == nhi * base + nlo -// 0 <= nlo < base -func norm(hi, lo, base int) (nhi, nlo int) { - if lo < 0 { - n := (-lo-1)/base + 1 - hi -= n - lo += n * base - } - if lo >= base { - n := lo / base - hi += n - lo -= n * base - } - return hi, lo -} - -// Date returns the Time corresponding to -// yyyy-mm-dd hh:mm:ss + nsec nanoseconds -// in the appropriate zone for that time in the given location. -// -// The month, day, hour, min, sec, and nsec values may be outside -// their usual ranges and will be normalized during the conversion. -// For example, October 32 converts to November 1. -// -// A daylight savings time transition skips or repeats times. -// For example, in the United States, March 13, 2011 2:15am never occurred, -// while November 6, 2011 1:15am occurred twice. In such cases, the -// choice of time zone, and therefore the time, is not well-defined. -// Date returns a time that is correct in one of the two zones involved -// in the transition, but it does not guarantee which. -// -// Date panics if loc is nil. -func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time { - if loc == nil { - panic("time: missing Location in call to Date") - } - - // Normalize month, overflowing into year. - m := int(month) - 1 - year, m = norm(year, m, 12) - month = Month(m) + 1 - - // Normalize nsec, sec, min, hour, overflowing into day. - sec, nsec = norm(sec, nsec, 1e9) - min, sec = norm(min, sec, 60) - hour, min = norm(hour, min, 60) - day, hour = norm(day, hour, 24) - - y := uint64(int64(year) - absoluteZeroYear) - - // Compute days since the absolute epoch. - - // Add in days from 400-year cycles. - n := y / 400 - y -= 400 * n - d := daysPer400Years * n - - // Add in 100-year cycles. - n = y / 100 - y -= 100 * n - d += daysPer100Years * n - - // Add in 4-year cycles. - n = y / 4 - y -= 4 * n - d += daysPer4Years * n - - // Add in non-leap years. - n = y - d += 365 * n - - // Add in days before this month. - d += uint64(daysBefore[month-1]) - if isLeap(year) && month >= March { - d++ // February 29 - } - - // Add in days before today. - d += uint64(day - 1) - - // Add in time elapsed today. - abs := d * secondsPerDay - abs += uint64(hour*secondsPerHour + min*secondsPerMinute + sec) - - unix := int64(abs) + (absoluteToInternal + internalToUnix) - - // Look for zone offset for t, so we can adjust to UTC. - // The lookup function expects UTC, so we pass t in the - // hope that it will not be too close to a zone transition, - // and then adjust if it is. - _, offset, _, start, end := loc.lookup(unix) - if offset != 0 { - switch utc := unix - int64(offset); { - case utc < start: - _, offset, _, _, _ = loc.lookup(start - 1) - case utc >= end: - _, offset, _, _, _ = loc.lookup(end) - } - unix -= int64(offset) - } - - return Time{unix + unixToInternal, uintptr(nsec), loc} -} - -// Truncate returns the result of rounding t down to a multiple of d (since the zero time). -// If d <= 0, Truncate returns t unchanged. -func (t Time) Truncate(d Duration) Time { - if d <= 0 { - return t - } - _, r := div(t, d) - return t.Add(-r) -} - -// Round returns the result of rounding t to the nearest multiple of d (since the zero time). -// The rounding behavior for halfway values is to round up. -// If d <= 0, Round returns t unchanged. -func (t Time) Round(d Duration) Time { - if d <= 0 { - return t - } - _, r := div(t, d) - if r+r < d { - return t.Add(-r) - } - return t.Add(d - r) -} - -// div divides t by d and returns the quotient parity and remainder. -// We don't use the quotient parity anymore (round half up instead of round to even) -// but it's still here in case we change our minds. -func div(t Time, d Duration) (qmod2 int, r Duration) { - neg := false - nsec := int32(t.nsec) - if t.sec < 0 { - // Operate on absolute value. - neg = true - t.sec = -t.sec - nsec = -nsec - if nsec < 0 { - nsec += 1e9 - t.sec-- // t.sec >= 1 before the -- so safe - } - } - - switch { - // Special case: 2d divides 1 second. - case d < Second && Second%(d+d) == 0: - qmod2 = int(nsec/int32(d)) & 1 - r = Duration(nsec % int32(d)) - - // Special case: d is a multiple of 1 second. - case d%Second == 0: - d1 := int64(d / Second) - qmod2 = int(t.sec/d1) & 1 - r = Duration(t.sec%d1)*Second + Duration(nsec) - - // General case. - // This could be faster if more cleverness were applied, - // but it's really only here to avoid special case restrictions in the API. - // No one will care about these cases. - default: - // Compute nanoseconds as 128-bit number. - sec := uint64(t.sec) - tmp := (sec >> 32) * 1e9 - u1 := tmp >> 32 - u0 := tmp << 32 - tmp = uint64(sec&0xFFFFFFFF) * 1e9 - u0x, u0 := u0, u0+tmp - if u0 < u0x { - u1++ - } - u0x, u0 = u0, u0+uint64(nsec) - if u0 < u0x { - u1++ - } - - // Compute remainder by subtracting r<<k for decreasing k. - // Quotient parity is whether we subtract on last round. - d1 := uint64(d) - for d1>>63 != 1 { - d1 <<= 1 - } - d0 := uint64(0) - for { - qmod2 = 0 - if u1 > d1 || u1 == d1 && u0 >= d0 { - // subtract - qmod2 = 1 - u0x, u0 = u0, u0-d0 - if u0 > u0x { - u1-- - } - u1 -= d1 - } - if d1 == 0 && d0 == uint64(d) { - break - } - d0 >>= 1 - d0 |= (d1 & 1) << 63 - d1 >>= 1 - } - r = Duration(u0) - } - - if neg && r != 0 { - // If input was negative and not an exact multiple of d, we computed q, r such that - // q*d + r = -t - // But the right answers are given by -(q-1), d-r: - // q*d + r = -t - // -q*d - r = t - // -(q-1)*d + (d - r) = t - qmod2 ^= 1 - r = d - r - } - return -} diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go deleted file mode 100644 index 4ae7da5a4..000000000 --- a/src/pkg/time/time_test.go +++ /dev/null @@ -1,1081 +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 ( - "bytes" - "encoding/gob" - "encoding/json" - "fmt" - "math/big" - "math/rand" - "runtime" - "testing" - "testing/quick" - . "time" -) - -// 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 := Now() - // PST is 8 hours west, PDT is 7 hours west. We could use the name but it's not unique. - if name, off := lt.Zone(); 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", name, off) - t.Error("Likely problem: the time zone files have not been installed.") - } -} - -// parsedTime is the struct representing a parsed time value. -type parsedTime struct { - Year int - Month Month - Day int - Hour, Minute, Second int // 15:04:05 is 15, 4, 5. - Nanosecond int // Fractional second. - Weekday Weekday - ZoneOffset int // seconds east of UTC, e.g. -7*60*60 for -0700 - Zone string // e.g., "MST" -} - -type TimeTest struct { - seconds int64 - golden parsedTime -} - -var utctests = []TimeTest{ - {0, parsedTime{1970, January, 1, 0, 0, 0, 0, Thursday, 0, "UTC"}}, - {1221681866, parsedTime{2008, September, 17, 20, 4, 26, 0, Wednesday, 0, "UTC"}}, - {-1221681866, parsedTime{1931, April, 16, 3, 55, 34, 0, Thursday, 0, "UTC"}}, - {-11644473600, parsedTime{1601, January, 1, 0, 0, 0, 0, Monday, 0, "UTC"}}, - {599529660, parsedTime{1988, December, 31, 0, 1, 0, 0, Saturday, 0, "UTC"}}, - {978220860, parsedTime{2000, December, 31, 0, 1, 0, 0, Sunday, 0, "UTC"}}, -} - -var nanoutctests = []TimeTest{ - {0, parsedTime{1970, January, 1, 0, 0, 0, 1e8, Thursday, 0, "UTC"}}, - {1221681866, parsedTime{2008, September, 17, 20, 4, 26, 2e8, Wednesday, 0, "UTC"}}, -} - -var localtests = []TimeTest{ - {0, parsedTime{1969, December, 31, 16, 0, 0, 0, Wednesday, -8 * 60 * 60, "PST"}}, - {1221681866, parsedTime{2008, September, 17, 13, 4, 26, 0, Wednesday, -7 * 60 * 60, "PDT"}}, -} - -var nanolocaltests = []TimeTest{ - {0, parsedTime{1969, December, 31, 16, 0, 0, 1e8, Wednesday, -8 * 60 * 60, "PST"}}, - {1221681866, parsedTime{2008, September, 17, 13, 4, 26, 3e8, Wednesday, -7 * 60 * 60, "PDT"}}, -} - -func same(t Time, u *parsedTime) bool { - // Check aggregates. - year, month, day := t.Date() - hour, min, sec := t.Clock() - name, offset := t.Zone() - if year != u.Year || month != u.Month || day != u.Day || - hour != u.Hour || min != u.Minute || sec != u.Second || - name != u.Zone || offset != u.ZoneOffset { - return false - } - // Check individual entries. - 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.Nanosecond() == u.Nanosecond && - t.Weekday() == u.Weekday -} - -func TestSecondsToUTC(t *testing.T) { - for _, test := range utctests { - sec := test.seconds - golden := &test.golden - tm := Unix(sec, 0).UTC() - newsec := tm.Unix() - if newsec != sec { - t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec) - } - if !same(tm, golden) { - t.Errorf("SecondsToUTC(%d): // %#v", sec, tm) - t.Errorf(" want=%+v", *golden) - t.Errorf(" have=%v", tm.Format(RFC3339+" MST")) - } - } -} - -func TestNanosecondsToUTC(t *testing.T) { - for _, test := range nanoutctests { - golden := &test.golden - nsec := test.seconds*1e9 + int64(golden.Nanosecond) - tm := Unix(0, nsec).UTC() - newnsec := tm.Unix()*1e9 + int64(tm.Nanosecond()) - if newnsec != nsec { - t.Errorf("NanosecondsToUTC(%d).Nanoseconds() = %d", nsec, newnsec) - } - if !same(tm, golden) { - t.Errorf("NanosecondsToUTC(%d):", nsec) - t.Errorf(" want=%+v", *golden) - t.Errorf(" have=%+v", tm.Format(RFC3339+" MST")) - } - } -} - -func TestSecondsToLocalTime(t *testing.T) { - for _, test := range localtests { - sec := test.seconds - golden := &test.golden - tm := Unix(sec, 0) - newsec := tm.Unix() - 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.Format(RFC3339+" MST")) - } - } -} - -func TestNanosecondsToLocalTime(t *testing.T) { - for _, test := range nanolocaltests { - golden := &test.golden - nsec := test.seconds*1e9 + int64(golden.Nanosecond) - tm := Unix(0, nsec) - newnsec := tm.Unix()*1e9 + int64(tm.Nanosecond()) - if newnsec != nsec { - t.Errorf("NanosecondsToLocalTime(%d).Seconds() = %d", nsec, newnsec) - } - if !same(tm, golden) { - t.Errorf("NanosecondsToLocalTime(%d):", nsec) - t.Errorf(" want=%+v", *golden) - t.Errorf(" have=%+v", tm.Format(RFC3339+" MST")) - } - } -} - -func TestSecondsToUTCAndBack(t *testing.T) { - f := func(sec int64) bool { return Unix(sec, 0).UTC().Unix() == 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) - } -} - -func TestNanosecondsToUTCAndBack(t *testing.T) { - f := func(nsec int64) bool { - t := Unix(0, nsec).UTC() - ns := t.Unix()*1e9 + int64(t.Nanosecond()) - return ns == nsec - } - f32 := func(nsec int32) bool { return f(int64(nsec)) } - cfg := &quick.Config{MaxCount: 10000} - - // Try a small date first, then the large ones. (The span is only a few hundred years - // for nanoseconds in an int64.) - if err := quick.Check(f32, cfg); err != nil { - t.Fatal(err) - } - if err := quick.Check(f, cfg); err != nil { - t.Fatal(err) - } -} - -// The time routines provide no way to get absolute time -// (seconds since zero), but we need it to compute the right -// answer for bizarre roundings like "to the nearest 3 ns". -// Compute as t - year1 = (t - 1970) + (1970 - 2001) + (2001 - 1). -// t - 1970 is returned by Unix and Nanosecond. -// 1970 - 2001 is -(31*365+8)*86400 = -978307200 seconds. -// 2001 - 1 is 2000*365.2425*86400 = 63113904000 seconds. -const unixToZero = -978307200 + 63113904000 - -// abs returns the absolute time stored in t, as seconds and nanoseconds. -func abs(t Time) (sec, nsec int64) { - unix := t.Unix() - nano := t.Nanosecond() - return unix + unixToZero, int64(nano) -} - -// absString returns abs as a decimal string. -func absString(t Time) string { - sec, nsec := abs(t) - if sec < 0 { - sec = -sec - nsec = -nsec - if nsec < 0 { - nsec += 1e9 - sec-- - } - return fmt.Sprintf("-%d%09d", sec, nsec) - } - return fmt.Sprintf("%d%09d", sec, nsec) -} - -var truncateRoundTests = []struct { - t Time - d Duration -}{ - {Date(-1, January, 1, 12, 15, 30, 5e8, UTC), 3}, - {Date(-1, January, 1, 12, 15, 31, 5e8, UTC), 3}, - {Date(2012, January, 1, 12, 15, 30, 5e8, UTC), Second}, - {Date(2012, January, 1, 12, 15, 31, 5e8, UTC), Second}, -} - -func TestTruncateRound(t *testing.T) { - var ( - bsec = new(big.Int) - bnsec = new(big.Int) - bd = new(big.Int) - bt = new(big.Int) - br = new(big.Int) - bq = new(big.Int) - b1e9 = new(big.Int) - ) - - b1e9.SetInt64(1e9) - - testOne := func(ti, tns, di int64) bool { - t0 := Unix(ti, int64(tns)).UTC() - d := Duration(di) - if d < 0 { - d = -d - } - if d <= 0 { - d = 1 - } - - // Compute bt = absolute nanoseconds. - sec, nsec := abs(t0) - bsec.SetInt64(sec) - bnsec.SetInt64(nsec) - bt.Mul(bsec, b1e9) - bt.Add(bt, bnsec) - - // Compute quotient and remainder mod d. - bd.SetInt64(int64(d)) - bq.DivMod(bt, bd, br) - - // To truncate, subtract remainder. - // br is < d, so it fits in an int64. - r := br.Int64() - t1 := t0.Add(-Duration(r)) - - // Check that time.Truncate works. - if trunc := t0.Truncate(d); trunc != t1 { - t.Errorf("Time.Truncate(%s, %s) = %s, want %s\n"+ - "%v trunc %v =\n%v want\n%v", - t0.Format(RFC3339Nano), d, trunc, t1.Format(RFC3339Nano), - absString(t0), int64(d), absString(trunc), absString(t1)) - return false - } - - // To round, add d back if remainder r > d/2 or r == exactly d/2. - // The commented out code would round half to even instead of up, - // but that makes it time-zone dependent, which is a bit strange. - if r > int64(d)/2 || r+r == int64(d) /*&& bq.Bit(0) == 1*/ { - t1 = t1.Add(Duration(d)) - } - - // Check that time.Round works. - if rnd := t0.Round(d); rnd != t1 { - t.Errorf("Time.Round(%s, %s) = %s, want %s\n"+ - "%v round %v =\n%v want\n%v", - t0.Format(RFC3339Nano), d, rnd, t1.Format(RFC3339Nano), - absString(t0), int64(d), absString(rnd), absString(t1)) - return false - } - return true - } - - // manual test cases - for _, tt := range truncateRoundTests { - testOne(tt.t.Unix(), int64(tt.t.Nanosecond()), int64(tt.d)) - } - - // exhaustive near 0 - for i := 0; i < 100; i++ { - for j := 1; j < 100; j++ { - testOne(unixToZero, int64(i), int64(j)) - testOne(unixToZero, -int64(i), int64(j)) - if t.Failed() { - return - } - } - } - - if t.Failed() { - return - } - - // randomly generated test cases - cfg := &quick.Config{MaxCount: 100000} - if testing.Short() { - cfg.MaxCount = 1000 - } - - // divisors of Second - f1 := func(ti int64, tns int32, logdi int32) bool { - d := Duration(1) - a, b := uint(logdi%9), (logdi>>16)%9 - d <<= a - for i := 0; i < int(b); i++ { - d *= 5 - } - return testOne(ti, int64(tns), int64(d)) - } - quick.Check(f1, cfg) - - // multiples of Second - f2 := func(ti int64, tns int32, di int32) bool { - d := Duration(di) * Second - if d < 0 { - d = -d - } - return testOne(ti, int64(tns), int64(d)) - } - quick.Check(f2, cfg) - - // halfway cases - f3 := func(tns, di int64) bool { - di &= 0xfffffffe - if di == 0 { - di = 2 - } - tns -= tns % di - if tns < 0 { - tns += di / 2 - } else { - tns -= di / 2 - } - return testOne(0, tns, di) - } - quick.Check(f3, cfg) - - // full generality - f4 := func(ti int64, tns int32, di int64) bool { - return testOne(ti, int64(tns), di) - } - quick.Check(f4, cfg) -} - -type ISOWeekTest struct { - year int // year - month, day int // month and day - yex int // expected year - wex int // expected week -} - -var isoWeekTests = []ISOWeekTest{ - {1981, 1, 1, 1981, 1}, {1982, 1, 1, 1981, 53}, {1983, 1, 1, 1982, 52}, - {1984, 1, 1, 1983, 52}, {1985, 1, 1, 1985, 1}, {1986, 1, 1, 1986, 1}, - {1987, 1, 1, 1987, 1}, {1988, 1, 1, 1987, 53}, {1989, 1, 1, 1988, 52}, - {1990, 1, 1, 1990, 1}, {1991, 1, 1, 1991, 1}, {1992, 1, 1, 1992, 1}, - {1993, 1, 1, 1992, 53}, {1994, 1, 1, 1993, 52}, {1995, 1, 2, 1995, 1}, - {1996, 1, 1, 1996, 1}, {1996, 1, 7, 1996, 1}, {1996, 1, 8, 1996, 2}, - {1997, 1, 1, 1997, 1}, {1998, 1, 1, 1998, 1}, {1999, 1, 1, 1998, 53}, - {2000, 1, 1, 1999, 52}, {2001, 1, 1, 2001, 1}, {2002, 1, 1, 2002, 1}, - {2003, 1, 1, 2003, 1}, {2004, 1, 1, 2004, 1}, {2005, 1, 1, 2004, 53}, - {2006, 1, 1, 2005, 52}, {2007, 1, 1, 2007, 1}, {2008, 1, 1, 2008, 1}, - {2009, 1, 1, 2009, 1}, {2010, 1, 1, 2009, 53}, {2010, 1, 1, 2009, 53}, - {2011, 1, 1, 2010, 52}, {2011, 1, 2, 2010, 52}, {2011, 1, 3, 2011, 1}, - {2011, 1, 4, 2011, 1}, {2011, 1, 5, 2011, 1}, {2011, 1, 6, 2011, 1}, - {2011, 1, 7, 2011, 1}, {2011, 1, 8, 2011, 1}, {2011, 1, 9, 2011, 1}, - {2011, 1, 10, 2011, 2}, {2011, 1, 11, 2011, 2}, {2011, 6, 12, 2011, 23}, - {2011, 6, 13, 2011, 24}, {2011, 12, 25, 2011, 51}, {2011, 12, 26, 2011, 52}, - {2011, 12, 27, 2011, 52}, {2011, 12, 28, 2011, 52}, {2011, 12, 29, 2011, 52}, - {2011, 12, 30, 2011, 52}, {2011, 12, 31, 2011, 52}, {1995, 1, 1, 1994, 52}, - {2012, 1, 1, 2011, 52}, {2012, 1, 2, 2012, 1}, {2012, 1, 8, 2012, 1}, - {2012, 1, 9, 2012, 2}, {2012, 12, 23, 2012, 51}, {2012, 12, 24, 2012, 52}, - {2012, 12, 30, 2012, 52}, {2012, 12, 31, 2013, 1}, {2013, 1, 1, 2013, 1}, - {2013, 1, 6, 2013, 1}, {2013, 1, 7, 2013, 2}, {2013, 12, 22, 2013, 51}, - {2013, 12, 23, 2013, 52}, {2013, 12, 29, 2013, 52}, {2013, 12, 30, 2014, 1}, - {2014, 1, 1, 2014, 1}, {2014, 1, 5, 2014, 1}, {2014, 1, 6, 2014, 2}, - {2015, 1, 1, 2015, 1}, {2016, 1, 1, 2015, 53}, {2017, 1, 1, 2016, 52}, - {2018, 1, 1, 2018, 1}, {2019, 1, 1, 2019, 1}, {2020, 1, 1, 2020, 1}, - {2021, 1, 1, 2020, 53}, {2022, 1, 1, 2021, 52}, {2023, 1, 1, 2022, 52}, - {2024, 1, 1, 2024, 1}, {2025, 1, 1, 2025, 1}, {2026, 1, 1, 2026, 1}, - {2027, 1, 1, 2026, 53}, {2028, 1, 1, 2027, 52}, {2029, 1, 1, 2029, 1}, - {2030, 1, 1, 2030, 1}, {2031, 1, 1, 2031, 1}, {2032, 1, 1, 2032, 1}, - {2033, 1, 1, 2032, 53}, {2034, 1, 1, 2033, 52}, {2035, 1, 1, 2035, 1}, - {2036, 1, 1, 2036, 1}, {2037, 1, 1, 2037, 1}, {2038, 1, 1, 2037, 53}, - {2039, 1, 1, 2038, 52}, {2040, 1, 1, 2039, 52}, -} - -func TestISOWeek(t *testing.T) { - // Selected dates and corner cases - for _, wt := range isoWeekTests { - dt := Date(wt.year, Month(wt.month), wt.day, 0, 0, 0, 0, UTC) - y, w := dt.ISOWeek() - if w != wt.wex || y != wt.yex { - t.Errorf("got %d/%d; expected %d/%d for %d-%02d-%02d", - y, w, wt.yex, wt.wex, wt.year, wt.month, wt.day) - } - } - - // The only real invariant: Jan 04 is in week 1 - for year := 1950; year < 2100; year++ { - if y, w := Date(year, January, 4, 0, 0, 0, 0, UTC).ISOWeek(); y != year || w != 1 { - t.Errorf("got %d/%d; expected %d/1 for Jan 04", y, w, year) - } - } -} - -type YearDayTest struct { - year, month, day int - yday int -} - -// Test YearDay in several different scenarios -// and corner cases -var yearDayTests = []YearDayTest{ - // Non-leap-year tests - {2007, 1, 1, 1}, - {2007, 1, 15, 15}, - {2007, 2, 1, 32}, - {2007, 2, 15, 46}, - {2007, 3, 1, 60}, - {2007, 3, 15, 74}, - {2007, 4, 1, 91}, - {2007, 12, 31, 365}, - - // Leap-year tests - {2008, 1, 1, 1}, - {2008, 1, 15, 15}, - {2008, 2, 1, 32}, - {2008, 2, 15, 46}, - {2008, 3, 1, 61}, - {2008, 3, 15, 75}, - {2008, 4, 1, 92}, - {2008, 12, 31, 366}, - - // Looks like leap-year (but isn't) tests - {1900, 1, 1, 1}, - {1900, 1, 15, 15}, - {1900, 2, 1, 32}, - {1900, 2, 15, 46}, - {1900, 3, 1, 60}, - {1900, 3, 15, 74}, - {1900, 4, 1, 91}, - {1900, 12, 31, 365}, - - // Year one tests (non-leap) - {1, 1, 1, 1}, - {1, 1, 15, 15}, - {1, 2, 1, 32}, - {1, 2, 15, 46}, - {1, 3, 1, 60}, - {1, 3, 15, 74}, - {1, 4, 1, 91}, - {1, 12, 31, 365}, - - // Year minus one tests (non-leap) - {-1, 1, 1, 1}, - {-1, 1, 15, 15}, - {-1, 2, 1, 32}, - {-1, 2, 15, 46}, - {-1, 3, 1, 60}, - {-1, 3, 15, 74}, - {-1, 4, 1, 91}, - {-1, 12, 31, 365}, - - // 400 BC tests (leap-year) - {-400, 1, 1, 1}, - {-400, 1, 15, 15}, - {-400, 2, 1, 32}, - {-400, 2, 15, 46}, - {-400, 3, 1, 61}, - {-400, 3, 15, 75}, - {-400, 4, 1, 92}, - {-400, 12, 31, 366}, - - // Special Cases - - // Gregorian calendar change (no effect) - {1582, 10, 4, 277}, - {1582, 10, 15, 288}, -} - -// Check to see if YearDay is location sensitive -var yearDayLocations = []*Location{ - FixedZone("UTC-8", -8*60*60), - FixedZone("UTC-4", -4*60*60), - UTC, - FixedZone("UTC+4", 4*60*60), - FixedZone("UTC+8", 8*60*60), -} - -func TestYearDay(t *testing.T) { - for _, loc := range yearDayLocations { - for _, ydt := range yearDayTests { - dt := Date(ydt.year, Month(ydt.month), ydt.day, 0, 0, 0, 0, loc) - yday := dt.YearDay() - if yday != ydt.yday { - t.Errorf("got %d, expected %d for %d-%02d-%02d in %v", - yday, ydt.yday, ydt.year, ydt.month, ydt.day, loc) - } - } - } -} - -var durationTests = []struct { - str string - d Duration -}{ - {"0", 0}, - {"1ns", 1 * Nanosecond}, - {"1.1us", 1100 * Nanosecond}, - {"2.2ms", 2200 * Microsecond}, - {"3.3s", 3300 * Millisecond}, - {"4m5s", 4*Minute + 5*Second}, - {"4m5.001s", 4*Minute + 5001*Millisecond}, - {"5h6m7.001s", 5*Hour + 6*Minute + 7001*Millisecond}, - {"8m0.000000001s", 8*Minute + 1*Nanosecond}, - {"2562047h47m16.854775807s", 1<<63 - 1}, - {"-2562047h47m16.854775808s", -1 << 63}, -} - -func TestDurationString(t *testing.T) { - for _, tt := range durationTests { - if str := tt.d.String(); str != tt.str { - t.Errorf("Duration(%d).String() = %s, want %s", int64(tt.d), str, tt.str) - } - if tt.d > 0 { - if str := (-tt.d).String(); str != "-"+tt.str { - t.Errorf("Duration(%d).String() = %s, want %s", int64(-tt.d), str, "-"+tt.str) - } - } - } -} - -var dateTests = []struct { - year, month, day, hour, min, sec, nsec int - z *Location - unix int64 -}{ - {2011, 11, 6, 1, 0, 0, 0, Local, 1320566400}, // 1:00:00 PDT - {2011, 11, 6, 1, 59, 59, 0, Local, 1320569999}, // 1:59:59 PDT - {2011, 11, 6, 2, 0, 0, 0, Local, 1320573600}, // 2:00:00 PST - - {2011, 3, 13, 1, 0, 0, 0, Local, 1300006800}, // 1:00:00 PST - {2011, 3, 13, 1, 59, 59, 0, Local, 1300010399}, // 1:59:59 PST - {2011, 3, 13, 3, 0, 0, 0, Local, 1300010400}, // 3:00:00 PDT - {2011, 3, 13, 2, 30, 0, 0, Local, 1300008600}, // 2:30:00 PDT ≡ 1:30 PST - - // Many names for Fri Nov 18 7:56:35 PST 2011 - {2011, 11, 18, 7, 56, 35, 0, Local, 1321631795}, // Nov 18 7:56:35 - {2011, 11, 19, -17, 56, 35, 0, Local, 1321631795}, // Nov 19 -17:56:35 - {2011, 11, 17, 31, 56, 35, 0, Local, 1321631795}, // Nov 17 31:56:35 - {2011, 11, 18, 6, 116, 35, 0, Local, 1321631795}, // Nov 18 6:116:35 - {2011, 10, 49, 7, 56, 35, 0, Local, 1321631795}, // Oct 49 7:56:35 - {2011, 11, 18, 7, 55, 95, 0, Local, 1321631795}, // Nov 18 7:55:95 - {2011, 11, 18, 7, 56, 34, 1e9, Local, 1321631795}, // Nov 18 7:56:34 + 10⁹ns - {2011, 12, -12, 7, 56, 35, 0, Local, 1321631795}, // Dec -21 7:56:35 - {2012, 1, -43, 7, 56, 35, 0, Local, 1321631795}, // Jan -52 7:56:35 2012 - {2012, int(January - 2), 18, 7, 56, 35, 0, Local, 1321631795}, // (Jan-2) 18 7:56:35 2012 - {2010, int(December + 11), 18, 7, 56, 35, 0, Local, 1321631795}, // (Dec+11) 18 7:56:35 2010 -} - -func TestDate(t *testing.T) { - for _, tt := range dateTests { - time := Date(tt.year, Month(tt.month), tt.day, tt.hour, tt.min, tt.sec, tt.nsec, tt.z) - want := Unix(tt.unix, 0) - if !time.Equal(want) { - t.Errorf("Date(%d, %d, %d, %d, %d, %d, %d, %s) = %v, want %v", - tt.year, tt.month, tt.day, tt.hour, tt.min, tt.sec, tt.nsec, tt.z, - time, want) - } - } -} - -// Several ways of getting from -// Fri Nov 18 7:56:35 PST 2011 -// to -// Thu Mar 19 7:56:35 PST 2016 -var addDateTests = []struct { - years, months, days int -}{ - {4, 4, 1}, - {3, 16, 1}, - {3, 15, 30}, - {5, -6, -18 - 30 - 12}, -} - -func TestAddDate(t *testing.T) { - t0 := Date(2011, 11, 18, 7, 56, 35, 0, UTC) - t1 := Date(2016, 3, 19, 7, 56, 35, 0, UTC) - for _, at := range addDateTests { - time := t0.AddDate(at.years, at.months, at.days) - if !time.Equal(t1) { - t.Errorf("AddDate(%d, %d, %d) = %v, want %v", - at.years, at.months, at.days, - time, t1) - } - } -} - -var daysInTests = []struct { - year, month, di int -}{ - {2011, 1, 31}, // January, first month, 31 days - {2011, 2, 28}, // February, non-leap year, 28 days - {2012, 2, 29}, // February, leap year, 29 days - {2011, 6, 30}, // June, 30 days - {2011, 12, 31}, // December, last month, 31 days -} - -func TestDaysIn(t *testing.T) { - // The daysIn function is not exported. - // Test the daysIn function via the `var DaysIn = daysIn` - // statement in the internal_test.go file. - for _, tt := range daysInTests { - di := DaysIn(Month(tt.month), tt.year) - if di != tt.di { - t.Errorf("got %d; expected %d for %d-%02d", - di, tt.di, tt.year, tt.month) - } - } -} - -func TestAddToExactSecond(t *testing.T) { - // Add an amount to the current time to round it up to the next exact second. - // This test checks that the nsec field still lies within the range [0, 999999999]. - t1 := Now() - t2 := t1.Add(Second - Duration(t1.Nanosecond())) - sec := (t1.Second() + 1) % 60 - if t2.Second() != sec || t2.Nanosecond() != 0 { - t.Errorf("sec = %d, nsec = %d, want sec = %d, nsec = 0", t2.Second(), t2.Nanosecond(), sec) - } -} - -func equalTimeAndZone(a, b Time) bool { - aname, aoffset := a.Zone() - bname, boffset := b.Zone() - return a.Equal(b) && aoffset == boffset && aname == bname -} - -var gobTests = []Time{ - Date(0, 1, 2, 3, 4, 5, 6, UTC), - Date(7, 8, 9, 10, 11, 12, 13, FixedZone("", 0)), - Unix(81985467080890095, 0x76543210), // Time.sec: 0x0123456789ABCDEF - {}, // nil location - Date(1, 2, 3, 4, 5, 6, 7, FixedZone("", 32767*60)), - Date(1, 2, 3, 4, 5, 6, 7, FixedZone("", -32768*60)), -} - -func TestTimeGob(t *testing.T) { - var b bytes.Buffer - enc := gob.NewEncoder(&b) - dec := gob.NewDecoder(&b) - for _, tt := range gobTests { - var gobtt Time - if err := enc.Encode(&tt); err != nil { - t.Errorf("%v gob Encode error = %q, want nil", tt, err) - } else if err := dec.Decode(&gobtt); err != nil { - t.Errorf("%v gob Decode error = %q, want nil", tt, err) - } else if !equalTimeAndZone(gobtt, tt) { - t.Errorf("Decoded time = %v, want %v", gobtt, tt) - } - b.Reset() - } -} - -var invalidEncodingTests = []struct { - bytes []byte - want string -}{ - {[]byte{}, "Time.UnmarshalBinary: no data"}, - {[]byte{0, 2, 3}, "Time.UnmarshalBinary: unsupported version"}, - {[]byte{1, 2, 3}, "Time.UnmarshalBinary: invalid length"}, -} - -func TestInvalidTimeGob(t *testing.T) { - for _, tt := range invalidEncodingTests { - var ignored Time - err := ignored.GobDecode(tt.bytes) - if err == nil || err.Error() != tt.want { - t.Errorf("time.GobDecode(%#v) error = %v, want %v", tt.bytes, err, tt.want) - } - err = ignored.UnmarshalBinary(tt.bytes) - if err == nil || err.Error() != tt.want { - t.Errorf("time.UnmarshalBinary(%#v) error = %v, want %v", tt.bytes, err, tt.want) - } - } -} - -var notEncodableTimes = []struct { - time Time - want string -}{ - {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", 1)), "Time.MarshalBinary: zone offset has fractional minute"}, - {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", -1*60)), "Time.MarshalBinary: unexpected zone offset"}, - {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", -32769*60)), "Time.MarshalBinary: unexpected zone offset"}, - {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", 32768*60)), "Time.MarshalBinary: unexpected zone offset"}, -} - -func TestNotGobEncodableTime(t *testing.T) { - for _, tt := range notEncodableTimes { - _, err := tt.time.GobEncode() - if err == nil || err.Error() != tt.want { - t.Errorf("%v GobEncode error = %v, want %v", tt.time, err, tt.want) - } - _, err = tt.time.MarshalBinary() - if err == nil || err.Error() != tt.want { - t.Errorf("%v MarshalBinary error = %v, want %v", tt.time, err, tt.want) - } - } -} - -var jsonTests = []struct { - time Time - json string -}{ - {Date(9999, 4, 12, 23, 20, 50, 520*1e6, UTC), `"9999-04-12T23:20:50.52Z"`}, - {Date(1996, 12, 19, 16, 39, 57, 0, Local), `"1996-12-19T16:39:57-08:00"`}, - {Date(0, 1, 1, 0, 0, 0, 1, FixedZone("", 1*60)), `"0000-01-01T00:00:00.000000001+00:01"`}, -} - -func TestTimeJSON(t *testing.T) { - for _, tt := range jsonTests { - var jsonTime Time - - if jsonBytes, err := json.Marshal(tt.time); err != nil { - t.Errorf("%v json.Marshal error = %v, want nil", tt.time, err) - } else if string(jsonBytes) != tt.json { - t.Errorf("%v JSON = %#q, want %#q", tt.time, string(jsonBytes), tt.json) - } else if err = json.Unmarshal(jsonBytes, &jsonTime); err != nil { - t.Errorf("%v json.Unmarshal error = %v, want nil", tt.time, err) - } else if !equalTimeAndZone(jsonTime, tt.time) { - t.Errorf("Unmarshaled time = %v, want %v", jsonTime, tt.time) - } - } -} - -func TestInvalidTimeJSON(t *testing.T) { - var tt Time - err := json.Unmarshal([]byte(`{"now is the time":"buddy"}`), &tt) - _, isParseErr := err.(*ParseError) - if !isParseErr { - t.Errorf("expected *time.ParseError unmarshaling JSON, got %v", err) - } -} - -var notJSONEncodableTimes = []struct { - time Time - want string -}{ - {Date(10000, 1, 1, 0, 0, 0, 0, UTC), "Time.MarshalJSON: year outside of range [0,9999]"}, - {Date(-1, 1, 1, 0, 0, 0, 0, UTC), "Time.MarshalJSON: year outside of range [0,9999]"}, -} - -func TestNotJSONEncodableTime(t *testing.T) { - for _, tt := range notJSONEncodableTimes { - _, err := tt.time.MarshalJSON() - if err == nil || err.Error() != tt.want { - t.Errorf("%v MarshalJSON error = %v, want %v", tt.time, err, tt.want) - } - } -} - -var parseDurationTests = []struct { - in string - ok bool - want Duration -}{ - // simple - {"0", true, 0}, - {"5s", true, 5 * Second}, - {"30s", true, 30 * Second}, - {"1478s", true, 1478 * Second}, - // sign - {"-5s", true, -5 * Second}, - {"+5s", true, 5 * Second}, - {"-0", true, 0}, - {"+0", true, 0}, - // decimal - {"5.0s", true, 5 * Second}, - {"5.6s", true, 5*Second + 600*Millisecond}, - {"5.s", true, 5 * Second}, - {".5s", true, 500 * Millisecond}, - {"1.0s", true, 1 * Second}, - {"1.00s", true, 1 * Second}, - {"1.004s", true, 1*Second + 4*Millisecond}, - {"1.0040s", true, 1*Second + 4*Millisecond}, - {"100.00100s", true, 100*Second + 1*Millisecond}, - // different units - {"10ns", true, 10 * Nanosecond}, - {"11us", true, 11 * Microsecond}, - {"12µs", true, 12 * Microsecond}, // U+00B5 - {"12μs", true, 12 * Microsecond}, // U+03BC - {"13ms", true, 13 * Millisecond}, - {"14s", true, 14 * Second}, - {"15m", true, 15 * Minute}, - {"16h", true, 16 * Hour}, - // composite durations - {"3h30m", true, 3*Hour + 30*Minute}, - {"10.5s4m", true, 4*Minute + 10*Second + 500*Millisecond}, - {"-2m3.4s", true, -(2*Minute + 3*Second + 400*Millisecond)}, - {"1h2m3s4ms5us6ns", true, 1*Hour + 2*Minute + 3*Second + 4*Millisecond + 5*Microsecond + 6*Nanosecond}, - {"39h9m14.425s", true, 39*Hour + 9*Minute + 14*Second + 425*Millisecond}, - // large value - {"52763797000ns", true, 52763797000 * Nanosecond}, - // more than 9 digits after decimal point, see http://golang.org/issue/6617 - {"0.3333333333333333333h", true, 20 * Minute}, - - // errors - {"", false, 0}, - {"3", false, 0}, - {"-", false, 0}, - {"s", false, 0}, - {".", false, 0}, - {"-.", false, 0}, - {".s", false, 0}, - {"+.s", false, 0}, - {"3000000h", false, 0}, // overflow -} - -func TestParseDuration(t *testing.T) { - for _, tc := range parseDurationTests { - d, err := ParseDuration(tc.in) - if tc.ok && (err != nil || d != tc.want) { - t.Errorf("ParseDuration(%q) = %v, %v, want %v, nil", tc.in, d, err, tc.want) - } else if !tc.ok && err == nil { - t.Errorf("ParseDuration(%q) = _, nil, want _, non-nil", tc.in) - } - } -} - -func TestParseDurationRoundTrip(t *testing.T) { - for i := 0; i < 100; i++ { - // Resolutions finer than milliseconds will result in - // imprecise round-trips. - d0 := Duration(rand.Int31()) * Millisecond - s := d0.String() - d1, err := ParseDuration(s) - if err != nil || d0 != d1 { - t.Errorf("round-trip failed: %d => %q => %d, %v", d0, s, d1, err) - } - } -} - -// golang.org/issue/4622 -func TestLocationRace(t *testing.T) { - ResetLocalOnceForTest() // reset the Once to trigger the race - - c := make(chan string, 1) - go func() { - c <- Now().String() - }() - Now().String() - <-c - Sleep(100 * Millisecond) - - // Back to Los Angeles for subsequent tests: - ForceUSPacificForTesting() -} - -var ( - t Time - u int64 -) - -var mallocTest = []struct { - count int - desc string - fn func() -}{ - {0, `time.Now()`, func() { t = Now() }}, - {0, `time.Now().UnixNano()`, func() { u = Now().UnixNano() }}, -} - -func TestCountMallocs(t *testing.T) { - if testing.Short() { - t.Skip("skipping malloc count in short mode") - } - if runtime.GOMAXPROCS(0) > 1 { - t.Skip("skipping; GOMAXPROCS>1") - } - for _, mt := range mallocTest { - allocs := int(testing.AllocsPerRun(100, mt.fn)) - if allocs > mt.count { - t.Errorf("%s: %d allocs, want %d", mt.desc, allocs, mt.count) - } - } -} - -func TestLoadFixed(t *testing.T) { - // Issue 4064: handle locations without any zone transitions. - loc, err := LoadLocation("Etc/GMT+1") - if err != nil { - t.Fatal(err) - } - - // The tzdata name Etc/GMT+1 uses "east is negative", - // but Go and most other systems use "east is positive". - // So GMT+1 corresponds to -3600 in the Go zone, not +3600. - name, offset := Now().In(loc).Zone() - if name != "GMT+1" || offset != -1*60*60 { - t.Errorf("Now().In(loc).Zone() = %q, %d, want %q, %d", name, offset, "GMT+1", -1*60*60) - } -} - -const ( - minDuration Duration = -1 << 63 - maxDuration Duration = 1<<63 - 1 -) - -var subTests = []struct { - t Time - u Time - d Duration -}{ - {Time{}, Time{}, Duration(0)}, - {Date(2009, 11, 23, 0, 0, 0, 1, UTC), Date(2009, 11, 23, 0, 0, 0, 0, UTC), Duration(1)}, - {Date(2009, 11, 23, 0, 0, 0, 0, UTC), Date(2009, 11, 24, 0, 0, 0, 0, UTC), -24 * Hour}, - {Date(2009, 11, 24, 0, 0, 0, 0, UTC), Date(2009, 11, 23, 0, 0, 0, 0, UTC), 24 * Hour}, - {Date(-2009, 11, 24, 0, 0, 0, 0, UTC), Date(-2009, 11, 23, 0, 0, 0, 0, UTC), 24 * Hour}, - {Time{}, Date(2109, 11, 23, 0, 0, 0, 0, UTC), Duration(minDuration)}, - {Date(2109, 11, 23, 0, 0, 0, 0, UTC), Time{}, Duration(maxDuration)}, - {Time{}, Date(-2109, 11, 23, 0, 0, 0, 0, UTC), Duration(maxDuration)}, - {Date(-2109, 11, 23, 0, 0, 0, 0, UTC), Time{}, Duration(minDuration)}, - {Date(2290, 1, 1, 0, 0, 0, 0, UTC), Date(2000, 1, 1, 0, 0, 0, 0, UTC), 290*365*24*Hour + 71*24*Hour}, - {Date(2300, 1, 1, 0, 0, 0, 0, UTC), Date(2000, 1, 1, 0, 0, 0, 0, UTC), Duration(maxDuration)}, - {Date(2000, 1, 1, 0, 0, 0, 0, UTC), Date(2290, 1, 1, 0, 0, 0, 0, UTC), -290*365*24*Hour - 71*24*Hour}, - {Date(2000, 1, 1, 0, 0, 0, 0, UTC), Date(2300, 1, 1, 0, 0, 0, 0, UTC), Duration(minDuration)}, -} - -func TestSub(t *testing.T) { - for i, st := range subTests { - got := st.t.Sub(st.u) - if got != st.d { - t.Errorf("#%d: Sub(%v, %v): got %v; want %v", i, st.t, st.u, got, st.d) - } - } -} - -var nsDurationTests = []struct { - d Duration - want int64 -}{ - {Duration(-1000), -1000}, - {Duration(-1), -1}, - {Duration(1), 1}, - {Duration(1000), 1000}, -} - -func TestDurationNanoseconds(t *testing.T) { - for _, tt := range nsDurationTests { - if got := tt.d.Nanoseconds(); got != tt.want { - t.Errorf("d.Nanoseconds() = %d; want: %d", got, tt.want) - } - } -} - -var minDurationTests = []struct { - d Duration - want float64 -}{ - {Duration(-60000000000), -1}, - {Duration(-1), -1 / 60e9}, - {Duration(1), 1 / 60e9}, - {Duration(60000000000), 1}, -} - -func TestDurationMinutes(t *testing.T) { - for _, tt := range minDurationTests { - if got := tt.d.Minutes(); got != tt.want { - t.Errorf("d.Minutes() = %g; want: %g", got, tt.want) - } - } -} - -var hourDurationTests = []struct { - d Duration - want float64 -}{ - {Duration(-3600000000000), -1}, - {Duration(-1), -1 / 3600e9}, - {Duration(1), 1 / 3600e9}, - {Duration(3600000000000), 1}, -} - -func TestDurationHours(t *testing.T) { - for _, tt := range hourDurationTests { - if got := tt.d.Hours(); got != tt.want { - t.Errorf("d.Hours() = %g; want: %g", got, tt.want) - } - } -} - -func BenchmarkNow(b *testing.B) { - for i := 0; i < b.N; i++ { - t = Now() - } -} - -func BenchmarkNowUnixNano(b *testing.B) { - for i := 0; i < b.N; i++ { - u = Now().UnixNano() - } -} - -func BenchmarkFormat(b *testing.B) { - t := Unix(1265346057, 0) - for i := 0; i < b.N; i++ { - t.Format("Mon Jan 2 15:04:05 2006") - } -} - -func BenchmarkFormatNow(b *testing.B) { - // Like BenchmarkFormat, but easier, because the time zone - // lookup cache is optimized for the present. - t := Now() - for i := 0; i < b.N; i++ { - t.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") - } -} - -func BenchmarkHour(b *testing.B) { - t := Now() - for i := 0; i < b.N; i++ { - _ = t.Hour() - } -} - -func BenchmarkSecond(b *testing.B) { - t := Now() - for i := 0; i < b.N; i++ { - _ = t.Second() - } -} - -func BenchmarkYear(b *testing.B) { - t := Now() - for i := 0; i < b.N; i++ { - _ = t.Year() - } -} - -func BenchmarkDay(b *testing.B) { - t := Now() - for i := 0; i < b.N; i++ { - _ = t.Day() - } -} diff --git a/src/pkg/time/zoneinfo.go b/src/pkg/time/zoneinfo.go deleted file mode 100644 index c8e53a27c..000000000 --- a/src/pkg/time/zoneinfo.go +++ /dev/null @@ -1,287 +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" - "syscall" -) - -// A Location maps time instants to the zone in use at that time. -// Typically, the Location represents the collection of time offsets -// in use in a geographical area, such as CEST and CET for central Europe. -type Location struct { - name string - zone []zone - tx []zoneTrans - - // Most lookups will be for the current time. - // To avoid the binary search through tx, keep a - // static one-element cache that gives the correct - // zone for the time when the Location was created. - // if cacheStart <= t <= cacheEnd, - // lookup can return cacheZone. - // The units for cacheStart and cacheEnd are seconds - // since January 1, 1970 UTC, to match the argument - // to lookup. - cacheStart int64 - cacheEnd int64 - cacheZone *zone -} - -// A zone represents a single time zone such as CEST or CET. -type zone struct { - name string // abbreviated name, "CET" - offset int // seconds east of UTC - isDST bool // is this zone Daylight Savings Time? -} - -// A zoneTrans represents a single time zone transition. -type zoneTrans struct { - when int64 // transition time, in seconds since 1970 GMT - index uint8 // the index of the zone that goes into effect at that time - isstd, isutc bool // ignored - no idea what these mean -} - -// alpha and omega are the beginning and end of time for zone -// transitions. -const ( - alpha = -1 << 63 // math.MinInt64 - omega = 1<<63 - 1 // math.MaxInt64 -) - -// UTC represents Universal Coordinated Time (UTC). -var UTC *Location = &utcLoc - -// utcLoc is separate so that get can refer to &utcLoc -// and ensure that it never returns a nil *Location, -// even if a badly behaved client has changed UTC. -var utcLoc = Location{name: "UTC"} - -// Local represents the system's local time zone. -var Local *Location = &localLoc - -// localLoc is separate so that initLocal can initialize -// it even if a client has changed Local. -var localLoc Location -var localOnce sync.Once - -func (l *Location) get() *Location { - if l == nil { - return &utcLoc - } - if l == &localLoc { - localOnce.Do(initLocal) - } - return l -} - -// String returns a descriptive name for the time zone information, -// corresponding to the argument to LoadLocation. -func (l *Location) String() string { - return l.get().name -} - -// FixedZone returns a Location that always uses -// the given zone name and offset (seconds east of UTC). -func FixedZone(name string, offset int) *Location { - l := &Location{ - name: name, - zone: []zone{{name, offset, false}}, - tx: []zoneTrans{{alpha, 0, false, false}}, - cacheStart: alpha, - cacheEnd: omega, - } - l.cacheZone = &l.zone[0] - return l -} - -// lookup returns information about the time zone in use at an -// instant in time expressed as seconds since January 1, 1970 00:00:00 UTC. -// -// The returned information gives the name of the zone (such as "CET"), -// the start and end times bracketing sec when that zone is in effect, -// the offset in seconds east of UTC (such as -5*60*60), and whether -// the daylight savings is being observed at that time. -func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start, end int64) { - l = l.get() - - if len(l.zone) == 0 { - name = "UTC" - offset = 0 - isDST = false - start = alpha - end = omega - return - } - - if zone := l.cacheZone; zone != nil && l.cacheStart <= sec && sec < l.cacheEnd { - name = zone.name - offset = zone.offset - isDST = zone.isDST - start = l.cacheStart - end = l.cacheEnd - return - } - - if len(l.tx) == 0 || sec < l.tx[0].when { - zone := &l.zone[l.lookupFirstZone()] - name = zone.name - offset = zone.offset - isDST = zone.isDST - start = alpha - if len(l.tx) > 0 { - end = l.tx[0].when - } else { - end = omega - } - return - } - - // Binary search for entry with largest time <= sec. - // Not using sort.Search to avoid dependencies. - tx := l.tx - end = omega - lo := 0 - hi := len(tx) - for hi-lo > 1 { - m := lo + (hi-lo)/2 - lim := tx[m].when - if sec < lim { - end = lim - hi = m - } else { - lo = m - } - } - zone := &l.zone[tx[lo].index] - name = zone.name - offset = zone.offset - isDST = zone.isDST - start = tx[lo].when - // end = maintained during the search - return -} - -// lookupFirstZone returns the index of the time zone to use for times -// before the first transition time, or when there are no transition -// times. -// -// The reference implementation in localtime.c from -// http://www.iana.org/time-zones/repository/releases/tzcode2013g.tar.gz -// implements the following algorithm for these cases: -// 1) If the first zone is unused by the transitions, use it. -// 2) Otherwise, if there are transition times, and the first -// transition is to a zone in daylight time, find the first -// non-daylight-time zone before and closest to the first transition -// zone. -// 3) Otherwise, use the first zone that is not daylight time, if -// there is one. -// 4) Otherwise, use the first zone. -func (l *Location) lookupFirstZone() int { - // Case 1. - if !l.firstZoneUsed() { - return 0 - } - - // Case 2. - if len(l.tx) > 0 && l.zone[l.tx[0].index].isDST { - for zi := int(l.tx[0].index) - 1; zi >= 0; zi-- { - if !l.zone[zi].isDST { - return zi - } - } - } - - // Case 3. - for zi := range l.zone { - if !l.zone[zi].isDST { - return zi - } - } - - // Case 4. - return 0 -} - -// firstZoneUsed returns whether the first zone is used by some -// transition. -func (l *Location) firstZoneUsed() bool { - for _, tx := range l.tx { - if tx.index == 0 { - return true - } - } - return false -} - -// lookupName returns information about the time zone with -// the given name (such as "EST") at the given pseudo-Unix time -// (what the given time of day would be in UTC). -func (l *Location) lookupName(name string, unix int64) (offset int, isDST bool, ok bool) { - l = l.get() - - // First try for a zone with the right name that was actually - // in effect at the given time. (In Sydney, Australia, both standard - // and daylight-savings time are abbreviated "EST". Using the - // offset helps us pick the right one for the given time. - // It's not perfect: during the backward transition we might pick - // either one.) - for i := range l.zone { - zone := &l.zone[i] - if zone.name == name { - nam, offset, isDST, _, _ := l.lookup(unix - int64(zone.offset)) - if nam == zone.name { - return offset, isDST, true - } - } - } - - // Otherwise fall back to an ordinary name match. - for i := range l.zone { - zone := &l.zone[i] - if zone.name == name { - return zone.offset, zone.isDST, true - } - } - - // Otherwise, give up. - return -} - -// NOTE(rsc): Eventually we will need to accept the POSIX TZ environment -// syntax too, but I don't feel like implementing it today. - -var zoneinfo, _ = syscall.Getenv("ZONEINFO") - -// LoadLocation returns the Location with the given name. -// -// If the name is "" or "UTC", LoadLocation returns UTC. -// If the name is "Local", LoadLocation returns Local. -// -// Otherwise, the name is taken to be a location name corresponding to a file -// in the IANA Time Zone database, such as "America/New_York". -// -// The time zone database needed by LoadLocation may not be -// present on all systems, especially non-Unix systems. -// LoadLocation looks in the directory or uncompressed zip file -// named by the ZONEINFO environment variable, if any, then looks in -// known installation locations on Unix systems, -// and finally looks in $GOROOT/lib/time/zoneinfo.zip. -func LoadLocation(name string) (*Location, error) { - if name == "" || name == "UTC" { - return UTC, nil - } - if name == "Local" { - return Local, nil - } - if zoneinfo != "" { - if z, err := loadZoneFile(zoneinfo, name); err == nil { - z.name = name - return z, nil - } - } - return loadLocation(name) -} diff --git a/src/pkg/time/zoneinfo_abbrs_windows.go b/src/pkg/time/zoneinfo_abbrs_windows.go deleted file mode 100644 index 80334371f..000000000 --- a/src/pkg/time/zoneinfo_abbrs_windows.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2013 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. - -// generated by genzabbrs.go from -// http://unicode.org/cldr/data/common/supplemental/windowsZones.xml - -package time - -type abbr struct { - std string - dst string -} - -var abbrs = map[string]abbr{ - "Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo - "Morocco Standard Time": {"WET", "WEST"}, // Africa/Casablanca - "South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg - "W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos - "E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi - "Namibia Standard Time": {"WAT", "WAST"}, // Africa/Windhoek - "Alaskan Standard Time": {"AKST", "AKDT"}, // America/Anchorage - "Paraguay Standard Time": {"PYT", "PYST"}, // America/Asuncion - "Bahia Standard Time": {"BRT", "BRST"}, // America/Bahia - "SA Pacific Standard Time": {"COT", "COT"}, // America/Bogota - "Argentina Standard Time": {"ART", "ART"}, // America/Buenos_Aires - "Venezuela Standard Time": {"VET", "VET"}, // America/Caracas - "SA Eastern Standard Time": {"GFT", "GFT"}, // America/Cayenne - "Central Standard Time": {"CST", "CDT"}, // America/Chicago - "Mountain Standard Time (Mexico)": {"MST", "MDT"}, // America/Chihuahua - "Central Brazilian Standard Time": {"AMT", "AMST"}, // America/Cuiaba - "Mountain Standard Time": {"MST", "MDT"}, // America/Denver - "Greenland Standard Time": {"WGT", "WGST"}, // America/Godthab - "Central America Standard Time": {"CST", "CST"}, // America/Guatemala - "Atlantic Standard Time": {"AST", "ADT"}, // America/Halifax - "US Eastern Standard Time": {"EST", "EDT"}, // America/Indianapolis - "SA Western Standard Time": {"BOT", "BOT"}, // America/La_Paz - "Pacific Standard Time": {"PST", "PDT"}, // America/Los_Angeles - "Central Standard Time (Mexico)": {"CST", "CDT"}, // America/Mexico_City - "Montevideo Standard Time": {"UYT", "UYST"}, // America/Montevideo - "Eastern Standard Time": {"EST", "EDT"}, // America/New_York - "US Mountain Standard Time": {"MST", "MST"}, // America/Phoenix - "Canada Central Standard Time": {"CST", "CST"}, // America/Regina - "Pacific Standard Time (Mexico)": {"PST", "PDT"}, // America/Santa_Isabel - "Pacific SA Standard Time": {"CLT", "CLST"}, // America/Santiago - "E. South America Standard Time": {"BRT", "BRST"}, // America/Sao_Paulo - "Newfoundland Standard Time": {"NST", "NDT"}, // America/St_Johns - "Central Asia Standard Time": {"ALMT", "ALMT"}, // Asia/Almaty - "Jordan Standard Time": {"EET", "EEST"}, // Asia/Amman - "Arabic Standard Time": {"AST", "AST"}, // Asia/Baghdad - "Azerbaijan Standard Time": {"AZT", "AZST"}, // Asia/Baku - "SE Asia Standard Time": {"ICT", "ICT"}, // Asia/Bangkok - "Middle East Standard Time": {"EET", "EEST"}, // Asia/Beirut - "India Standard Time": {"IST", "IST"}, // Asia/Calcutta - "Sri Lanka Standard Time": {"IST", "IST"}, // Asia/Colombo - "Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus - "Bangladesh Standard Time": {"BDT", "BDT"}, // Asia/Dhaka - "Arabian Standard Time": {"GST", "GST"}, // Asia/Dubai - "North Asia East Standard Time": {"IRKT", "IRKT"}, // Asia/Irkutsk - "Israel Standard Time": {"IST", "IDT"}, // Asia/Jerusalem - "Afghanistan Standard Time": {"AFT", "AFT"}, // Asia/Kabul - "Pakistan Standard Time": {"PKT", "PKT"}, // Asia/Karachi - "Nepal Standard Time": {"NPT", "NPT"}, // Asia/Katmandu - "North Asia Standard Time": {"KRAT", "KRAT"}, // Asia/Krasnoyarsk - "Magadan Standard Time": {"MAGT", "MAGT"}, // Asia/Magadan - "E. Europe Standard Time": {"EET", "EEST"}, // Asia/Nicosia - "N. Central Asia Standard Time": {"NOVT", "NOVT"}, // Asia/Novosibirsk - "Myanmar Standard Time": {"MMT", "MMT"}, // Asia/Rangoon - "Arab Standard Time": {"AST", "AST"}, // Asia/Riyadh - "Korea Standard Time": {"KST", "KST"}, // Asia/Seoul - "China Standard Time": {"CST", "CST"}, // Asia/Shanghai - "Singapore Standard Time": {"SGT", "SGT"}, // Asia/Singapore - "Taipei Standard Time": {"CST", "CST"}, // Asia/Taipei - "West Asia Standard Time": {"UZT", "UZT"}, // Asia/Tashkent - "Georgian Standard Time": {"GET", "GET"}, // Asia/Tbilisi - "Iran Standard Time": {"IRST", "IRDT"}, // Asia/Tehran - "Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo - "Ulaanbaatar Standard Time": {"ULAT", "ULAT"}, // Asia/Ulaanbaatar - "Vladivostok Standard Time": {"VLAT", "VLAT"}, // Asia/Vladivostok - "Yakutsk Standard Time": {"YAKT", "YAKT"}, // Asia/Yakutsk - "Ekaterinburg Standard Time": {"YEKT", "YEKT"}, // Asia/Yekaterinburg - "Caucasus Standard Time": {"AMT", "AMT"}, // Asia/Yerevan - "Azores Standard Time": {"AZOT", "AZOST"}, // Atlantic/Azores - "Cape Verde Standard Time": {"CVT", "CVT"}, // Atlantic/Cape_Verde - "Greenwich Standard Time": {"GMT", "GMT"}, // Atlantic/Reykjavik - "Cen. Australia Standard Time": {"CST", "CST"}, // Australia/Adelaide - "E. Australia Standard Time": {"EST", "EST"}, // Australia/Brisbane - "AUS Central Standard Time": {"CST", "CST"}, // Australia/Darwin - "Tasmania Standard Time": {"EST", "EST"}, // Australia/Hobart - "W. Australia Standard Time": {"WST", "WST"}, // Australia/Perth - "AUS Eastern Standard Time": {"EST", "EST"}, // Australia/Sydney - "UTC": {"GMT", "GMT"}, // Etc/GMT - "UTC-11": {"GMT+11", "GMT+11"}, // Etc/GMT+11 - "Dateline Standard Time": {"GMT+12", "GMT+12"}, // Etc/GMT+12 - "UTC-02": {"GMT+2", "GMT+2"}, // Etc/GMT+2 - "UTC+12": {"GMT-12", "GMT-12"}, // Etc/GMT-12 - "W. Europe Standard Time": {"CET", "CEST"}, // Europe/Berlin - "GTB Standard Time": {"EET", "EEST"}, // Europe/Bucharest - "Central Europe Standard Time": {"CET", "CEST"}, // Europe/Budapest - "Turkey Standard Time": {"EET", "EEST"}, // Europe/Istanbul - "Kaliningrad Standard Time": {"FET", "FET"}, // Europe/Kaliningrad - "FLE Standard Time": {"EET", "EEST"}, // Europe/Kiev - "GMT Standard Time": {"GMT", "BST"}, // Europe/London - "Russian Standard Time": {"MSK", "MSK"}, // Europe/Moscow - "Romance Standard Time": {"CET", "CEST"}, // Europe/Paris - "Central European Standard Time": {"CET", "CEST"}, // Europe/Warsaw - "Mauritius Standard Time": {"MUT", "MUT"}, // Indian/Mauritius - "Samoa Standard Time": {"WST", "WST"}, // Pacific/Apia - "New Zealand Standard Time": {"NZST", "NZDT"}, // Pacific/Auckland - "Fiji Standard Time": {"FJT", "FJT"}, // Pacific/Fiji - "Central Pacific Standard Time": {"SBT", "SBT"}, // Pacific/Guadalcanal - "Hawaiian Standard Time": {"HST", "HST"}, // Pacific/Honolulu - "West Pacific Standard Time": {"PGT", "PGT"}, // Pacific/Port_Moresby - "Tonga Standard Time": {"TOT", "TOT"}, // Pacific/Tongatapu -} diff --git a/src/pkg/time/zoneinfo_plan9.go b/src/pkg/time/zoneinfo_plan9.go deleted file mode 100644 index 4bb0cb390..000000000 --- a/src/pkg/time/zoneinfo_plan9.go +++ /dev/null @@ -1,160 +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 ( - "errors" - "runtime" - "syscall" -) - -func isSpace(r rune) bool { - return r == ' ' || r == '\t' || r == '\n' -} - -// Copied from strings to avoid a dependency. -func fields(s string) []string { - // First count the fields. - n := 0 - inField := false - for _, rune := range s { - wasInField := inField - inField = !isSpace(rune) - if inField && !wasInField { - n++ - } - } - - // Now create them. - a := make([]string, n) - na := 0 - fieldStart := -1 // Set to -1 when looking for start of field. - for i, rune := range s { - if isSpace(rune) { - if fieldStart >= 0 { - a[na] = s[fieldStart:i] - na++ - fieldStart = -1 - } - } else if fieldStart == -1 { - fieldStart = i - } - } - if fieldStart >= 0 { // Last field might end at EOF. - a[na] = s[fieldStart:] - } - return a -} - -func loadZoneDataPlan9(s string) (l *Location, err error) { - f := fields(s) - if len(f) < 4 { - if len(f) == 2 && f[0] == "GMT" { - return UTC, nil - } - return nil, badData - } - - var zones [2]zone - - // standard timezone offset - o, err := atoi(f[1]) - if err != nil { - return nil, badData - } - zones[0] = zone{name: f[0], offset: o, isDST: false} - - // alternate timezone offset - o, err = atoi(f[3]) - if err != nil { - return nil, badData - } - zones[1] = zone{name: f[2], offset: o, isDST: true} - - // transition time pairs - var tx []zoneTrans - f = f[4:] - for i := 0; i < len(f); i++ { - zi := 0 - if i%2 == 0 { - zi = 1 - } - t, err := atoi(f[i]) - if err != nil { - return nil, badData - } - t -= zones[0].offset - tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)}) - } - - // Committed to succeed. - l = &Location{zone: zones[:], tx: tx} - - // Fill in the cache with information about right now, - // since that will be the most common lookup. - sec, _ := now() - for i := range tx { - if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) { - l.cacheStart = tx[i].when - l.cacheEnd = omega - if i+1 < len(tx) { - l.cacheEnd = tx[i+1].when - } - l.cacheZone = &l.zone[tx[i].index] - } - } - - return l, nil -} - -func loadZoneFilePlan9(name string) (*Location, error) { - b, err := readFile(name) - if err != nil { - return nil, err - } - return loadZoneDataPlan9(string(b)) -} - -func initTestingZone() { - z, err := loadLocation("America/Los_Angeles") - if err != nil { - panic("cannot load America/Los_Angeles for testing: " + err.Error()) - } - z.name = "Local" - localLoc = *z -} - -func initLocal() { - t, ok := syscall.Getenv("timezone") - if ok { - if z, err := loadZoneDataPlan9(t); err == nil { - localLoc = *z - return - } - } else { - if z, err := loadZoneFilePlan9("/adm/timezone/local"); err == nil { - localLoc = *z - localLoc.name = "Local" - return - } - } - - // Fall back to UTC. - localLoc.name = "UTC" -} - -func loadLocation(name string) (*Location, error) { - if z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name); err == nil { - z.name = name - return z, nil - } - return nil, errors.New("unknown time zone " + name) -} - -func forceZipFileForTesting(zipOnly bool) { - // We only use the zip file anyway. -} diff --git a/src/pkg/time/zoneinfo_read.go b/src/pkg/time/zoneinfo_read.go deleted file mode 100644 index de9ebb41c..000000000 --- a/src/pkg/time/zoneinfo_read.go +++ /dev/null @@ -1,343 +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 "errors" - -// 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) -} - -var badData = errors.New("malformed time zone information") - -func loadZoneData(bytes []byte) (l *Location, err error) { - d := data{bytes, false} - - // 4-byte magic "TZif" - if magic := d.read(4); string(magic) != "TZif" { - return nil, badData - } - - // 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' && p[0] != '3' { - return nil, badData - } - - // 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, badData - } - 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, badData - } - - // If version == 2 or 3, 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] - zone := make([]zone, n[NZone]) - for i := range zone { - var ok bool - var n uint32 - if n, ok = zonedata.big4(); !ok { - return nil, badData - } - zone[i].offset = int(int32(n)) - var b byte - if b, ok = zonedata.byte(); !ok { - return nil, badData - } - zone[i].isDST = b != 0 - if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) { - return nil, badData - } - zone[i].name = byteString(abbrev[b:]) - } - - // Now the transition time info. - tx := make([]zoneTrans, n[NTime]) - for i := range tx { - var ok bool - var n uint32 - if n, ok = txtimes.big4(); !ok { - return nil, badData - } - tx[i].when = int64(int32(n)) - if int(txzones[i]) >= len(zone) { - return nil, badData - } - tx[i].index = txzones[i] - if i < len(isstd) { - tx[i].isstd = isstd[i] != 0 - } - if i < len(isutc) { - tx[i].isutc = isutc[i] != 0 - } - } - - if len(tx) == 0 { - // Build fake transition to cover all time. - // This happens in fixed locations like "Etc/GMT0". - tx = append(tx, zoneTrans{when: alpha, index: 0}) - } - - // Committed to succeed. - l = &Location{zone: zone, tx: tx} - - // Fill in the cache with information about right now, - // since that will be the most common lookup. - sec, _ := now() - for i := range tx { - if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) { - l.cacheStart = tx[i].when - l.cacheEnd = omega - if i+1 < len(tx) { - l.cacheEnd = tx[i+1].when - } - l.cacheZone = &l.zone[tx[i].index] - } - } - - return l, nil -} - -func loadZoneFile(dir, name string) (l *Location, err error) { - if len(dir) > 4 && dir[len(dir)-4:] == ".zip" { - return loadZoneZip(dir, name) - } - if dir != "" { - name = dir + "/" + name - } - buf, err := readFile(name) - if err != nil { - return - } - return loadZoneData(buf) -} - -// There are 500+ zoneinfo files. Rather than distribute them all -// individually, we ship them in an uncompressed zip file. -// Used this way, the zip file format serves as a commonly readable -// container for the individual small files. We choose zip over tar -// because zip files have a contiguous table of contents, making -// individual file lookups faster, and because the per-file overhead -// in a zip file is considerably less than tar's 512 bytes. - -// get4 returns the little-endian 32-bit value in b. -func get4(b []byte) int { - if len(b) < 4 { - return 0 - } - return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24 -} - -// get2 returns the little-endian 16-bit value in b. -func get2(b []byte) int { - if len(b) < 2 { - return 0 - } - return int(b[0]) | int(b[1])<<8 -} - -func loadZoneZip(zipfile, name string) (l *Location, err error) { - fd, err := open(zipfile) - if err != nil { - return nil, errors.New("open " + zipfile + ": " + err.Error()) - } - defer closefd(fd) - - const ( - zecheader = 0x06054b50 - zcheader = 0x02014b50 - ztailsize = 22 - - zheadersize = 30 - zheader = 0x04034b50 - ) - - buf := make([]byte, ztailsize) - if err := preadn(fd, buf, -ztailsize); err != nil || get4(buf) != zecheader { - return nil, errors.New("corrupt zip file " + zipfile) - } - n := get2(buf[10:]) - size := get4(buf[12:]) - off := get4(buf[16:]) - - buf = make([]byte, size) - if err := preadn(fd, buf, off); err != nil { - return nil, errors.New("corrupt zip file " + zipfile) - } - - for i := 0; i < n; i++ { - // zip entry layout: - // 0 magic[4] - // 4 madevers[1] - // 5 madeos[1] - // 6 extvers[1] - // 7 extos[1] - // 8 flags[2] - // 10 meth[2] - // 12 modtime[2] - // 14 moddate[2] - // 16 crc[4] - // 20 csize[4] - // 24 uncsize[4] - // 28 namelen[2] - // 30 xlen[2] - // 32 fclen[2] - // 34 disknum[2] - // 36 iattr[2] - // 38 eattr[4] - // 42 off[4] - // 46 name[namelen] - // 46+namelen+xlen+fclen - next header - // - if get4(buf) != zcheader { - break - } - meth := get2(buf[10:]) - size := get4(buf[24:]) - namelen := get2(buf[28:]) - xlen := get2(buf[30:]) - fclen := get2(buf[32:]) - off := get4(buf[42:]) - zname := buf[46 : 46+namelen] - buf = buf[46+namelen+xlen+fclen:] - if string(zname) != name { - continue - } - if meth != 0 { - return nil, errors.New("unsupported compression for " + name + " in " + zipfile) - } - - // zip per-file header layout: - // 0 magic[4] - // 4 extvers[1] - // 5 extos[1] - // 6 flags[2] - // 8 meth[2] - // 10 modtime[2] - // 12 moddate[2] - // 14 crc[4] - // 18 csize[4] - // 22 uncsize[4] - // 26 namelen[2] - // 28 xlen[2] - // 30 name[namelen] - // 30+namelen+xlen - file data - // - buf = make([]byte, zheadersize+namelen) - if err := preadn(fd, buf, off); err != nil || - get4(buf) != zheader || - get2(buf[8:]) != meth || - get2(buf[26:]) != namelen || - string(buf[30:30+namelen]) != name { - return nil, errors.New("corrupt zip file " + zipfile) - } - xlen = get2(buf[28:]) - - buf = make([]byte, size) - if err := preadn(fd, buf, off+30+namelen+xlen); err != nil { - return nil, errors.New("corrupt zip file " + zipfile) - } - - return loadZoneData(buf) - } - - return nil, errors.New("cannot find " + name + " in zip file " + zipfile) -} diff --git a/src/pkg/time/zoneinfo_test.go b/src/pkg/time/zoneinfo_test.go deleted file mode 100644 index 4ca7fad93..000000000 --- a/src/pkg/time/zoneinfo_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2014 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 TestVersion3(t *testing.T) { - time.ForceZipFileForTesting(true) - defer time.ForceZipFileForTesting(false) - _, err := time.LoadLocation("Asia/Jerusalem") - if err != nil { - t.Fatal(err) - } -} - -// Test that we get the correct results for times before the first -// transition time. To do this we explicitly check early dates in a -// couple of specific timezones. -func TestFirstZone(t *testing.T) { - time.ForceZipFileForTesting(true) - defer time.ForceZipFileForTesting(false) - - const format = "Mon, 02 Jan 2006 15:04:05 -0700 (MST)" - var tests = []struct { - zone string - unix int64 - want1 string - want2 string - }{ - { - "PST8PDT", - -1633269601, - "Sun, 31 Mar 1918 01:59:59 -0800 (PST)", - "Sun, 31 Mar 1918 03:00:00 -0700 (PDT)", - }, - { - "Pacific/Fakaofo", - 1325242799, - "Thu, 29 Dec 2011 23:59:59 -1100 (TKT)", - "Sat, 31 Dec 2011 00:00:00 +1300 (TKT)", - }, - } - - for _, test := range tests { - z, err := time.LoadLocation(test.zone) - if err != nil { - t.Fatal(err) - } - s := time.Unix(test.unix, 0).In(z).Format(format) - if s != test.want1 { - t.Errorf("for %s %d got %q want %q", test.zone, test.unix, s, test.want1) - } - s = time.Unix(test.unix+1, 0).In(z).Format(format) - if s != test.want2 { - t.Errorf("for %s %d got %q want %q", test.zone, test.unix, s, test.want2) - } - } -} diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go deleted file mode 100644 index ab7e4612e..000000000 --- a/src/pkg/time/zoneinfo_unix.go +++ /dev/null @@ -1,84 +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. - -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris - -// 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 ( - "errors" - "runtime" - "syscall" -) - -func initTestingZone() { - z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", "America/Los_Angeles") - if err != nil { - panic("cannot load America/Los_Angeles for testing: " + err.Error()) - } - z.name = "Local" - localLoc = *z -} - -// Many systems use /usr/share/zoneinfo, Solaris 2 has -// /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ. -var zoneDirs = []string{ - "/usr/share/zoneinfo/", - "/usr/share/lib/zoneinfo/", - "/usr/lib/locale/TZ/", - runtime.GOROOT() + "/lib/time/zoneinfo.zip", -} - -var origZoneDirs = zoneDirs - -func forceZipFileForTesting(zipOnly bool) { - zoneDirs = make([]string, len(origZoneDirs)) - copy(zoneDirs, origZoneDirs) - if zipOnly { - for i := 0; i < len(zoneDirs)-1; i++ { - zoneDirs[i] = "/XXXNOEXIST" - } - } -} - -func initLocal() { - // 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, ok := syscall.Getenv("TZ") - switch { - case !ok: - z, err := loadZoneFile("", "/etc/localtime") - if err == nil { - localLoc = *z - localLoc.name = "Local" - return - } - case tz != "" && tz != "UTC": - if z, err := loadLocation(tz); err == nil { - localLoc = *z - return - } - } - - // Fall back to UTC. - localLoc.name = "UTC" -} - -func loadLocation(name string) (*Location, error) { - for _, zoneDir := range zoneDirs { - if z, err := loadZoneFile(zoneDir, name); err == nil { - z.name = name - return z, nil - } - } - return nil, errors.New("unknown time zone " + name) -} diff --git a/src/pkg/time/zoneinfo_windows.go b/src/pkg/time/zoneinfo_windows.go deleted file mode 100644 index 6046743e6..000000000 --- a/src/pkg/time/zoneinfo_windows.go +++ /dev/null @@ -1,270 +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 ( - "errors" - "runtime" - "syscall" - "unsafe" -) - -// TODO(rsc): Fall back to copy of zoneinfo files. - -// BUG(brainman,rsc): On Windows, the operating system does not provide complete -// time zone information. -// The implementation assumes that this year's rules for daylight savings -// time apply to all previous and future years as well. - -// getKeyValue retrieves the string value kname associated with the open registry key kh. -func getKeyValue(kh syscall.Handle, kname string) (string, error) { - var buf [50]uint16 // buf needs to be large enough to fit zone descriptions - var typ uint32 - n := uint32(len(buf) * 2) // RegQueryValueEx's signature expects array of bytes, not uint16 - p, _ := syscall.UTF16PtrFromString(kname) - if err := syscall.RegQueryValueEx(kh, p, nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n); err != nil { - return "", err - } - if typ != syscall.REG_SZ { // null terminated strings only - return "", errors.New("Key is not string") - } - return syscall.UTF16ToString(buf[:]), nil -} - -// matchZoneKey checks if stdname and dstname match the corresponding "Std" -// and "Dlt" key values in the kname key stored under the open registry key zones. -func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) (matched bool, err2 error) { - var h syscall.Handle - p, _ := syscall.UTF16PtrFromString(kname) - if err := syscall.RegOpenKeyEx(zones, p, 0, syscall.KEY_READ, &h); err != nil { - return false, err - } - defer syscall.RegCloseKey(h) - - s, err := getKeyValue(h, "Std") - if err != nil { - return false, err - } - if s != stdname { - return false, nil - } - s, err = getKeyValue(h, "Dlt") - if err != nil { - return false, err - } - if s != dstname && dstname != stdname { - return false, nil - } - return true, nil -} - -// toEnglishName searches the registry for an English name of a time zone -// whose zone names are stdname and dstname and returns the English name. -func toEnglishName(stdname, dstname string) (string, error) { - var zones syscall.Handle - p, _ := syscall.UTF16PtrFromString(`SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`) - if err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, p, 0, syscall.KEY_READ, &zones); err != nil { - return "", err - } - defer syscall.RegCloseKey(zones) - - var count uint32 - if err := syscall.RegQueryInfoKey(zones, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil); err != nil { - return "", err - } - - var buf [50]uint16 // buf needs to be large enough to fit zone descriptions - for i := uint32(0); i < count; i++ { - n := uint32(len(buf)) - if syscall.RegEnumKeyEx(zones, i, &buf[0], &n, nil, nil, nil, nil) != nil { - continue - } - kname := syscall.UTF16ToString(buf[:]) - matched, err := matchZoneKey(zones, kname, stdname, dstname) - if err == nil && matched { - return kname, nil - } - } - return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`) -} - -// extractCAPS extracts capital letters from description desc. -func extractCAPS(desc string) string { - var short []rune - for _, c := range desc { - if 'A' <= c && c <= 'Z' { - short = append(short, rune(c)) - } - } - return string(short) -} - -// abbrev returns the abbreviations to use for the given zone z. -func abbrev(z *syscall.Timezoneinformation) (std, dst string) { - stdName := syscall.UTF16ToString(z.StandardName[:]) - a, ok := abbrs[stdName] - if !ok { - dstName := syscall.UTF16ToString(z.DaylightName[:]) - // Perhaps stdName is not English. Try to convert it. - englishName, err := toEnglishName(stdName, dstName) - if err == nil { - a, ok = abbrs[englishName] - if ok { - return a.std, a.dst - } - } - // fallback to using capital letters - return extractCAPS(stdName), extractCAPS(dstName) - } - return a.std, a.dst -} - -// pseudoUnix returns the pseudo-Unix time (seconds since Jan 1 1970 *LOCAL TIME*) -// denoted by the system date+time d in the given year. -// It is up to the caller to convert this local time into a UTC-based time. -func pseudoUnix(year int, d *syscall.Systemtime) int64 { - // Windows specifies daylight savings information in "day in month" format: - // d.Month is month number (1-12) - // d.DayOfWeek is appropriate weekday (Sunday=0 to Saturday=6) - // d.Day is week within the month (1 to 5, where 5 is last week of the month) - // d.Hour, d.Minute and d.Second are absolute time - day := 1 - t := Date(year, Month(d.Month), day, int(d.Hour), int(d.Minute), int(d.Second), 0, UTC) - i := int(d.DayOfWeek) - int(t.Weekday()) - if i < 0 { - i += 7 - } - day += i - if week := int(d.Day) - 1; week < 4 { - day += week * 7 - } else { - // "Last" instance of the day. - day += 4 * 7 - if day > daysIn(Month(d.Month), year) { - day -= 7 - } - } - return t.sec + int64(day-1)*secondsPerDay + internalToUnix -} - -func initLocalFromTZI(i *syscall.Timezoneinformation) { - l := &localLoc - - nzone := 1 - if i.StandardDate.Month > 0 { - nzone++ - } - l.zone = make([]zone, nzone) - - stdname, dstname := abbrev(i) - - std := &l.zone[0] - std.name = stdname - if nzone == 1 { - // No daylight savings. - std.offset = -int(i.Bias) * 60 - l.cacheStart = alpha - l.cacheEnd = omega - l.cacheZone = std - l.tx = make([]zoneTrans, 1) - l.tx[0].when = l.cacheStart - l.tx[0].index = 0 - return - } - - // StandardBias must be ignored if StandardDate is not set, - // so this computation is delayed until after the nzone==1 - // return above. - std.offset = -int(i.Bias+i.StandardBias) * 60 - - dst := &l.zone[1] - dst.name = dstname - dst.offset = -int(i.Bias+i.DaylightBias) * 60 - dst.isDST = true - - // Arrange so that d0 is first transition date, d1 second, - // i0 is index of zone after first transition, i1 second. - d0 := &i.StandardDate - d1 := &i.DaylightDate - i0 := 0 - i1 := 1 - if d0.Month > d1.Month { - d0, d1 = d1, d0 - i0, i1 = i1, i0 - } - - // 2 tx per year, 100 years on each side of this year - l.tx = make([]zoneTrans, 400) - - t := Now().UTC() - year := t.Year() - txi := 0 - for y := year - 100; y < year+100; y++ { - tx := &l.tx[txi] - tx.when = pseudoUnix(y, d0) - int64(l.zone[i1].offset) - tx.index = uint8(i0) - txi++ - - tx = &l.tx[txi] - tx.when = pseudoUnix(y, d1) - int64(l.zone[i0].offset) - tx.index = uint8(i1) - txi++ - } -} - -var usPacific = syscall.Timezoneinformation{ - Bias: 8 * 60, - StandardName: [32]uint16{ - 'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'S', 't', 'a', 'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e', - }, - StandardDate: syscall.Systemtime{Month: 11, Day: 1, Hour: 2}, - DaylightName: [32]uint16{ - 'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'D', 'a', 'y', 'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e', - }, - DaylightDate: syscall.Systemtime{Month: 3, Day: 2, Hour: 2}, - DaylightBias: -60, -} - -var aus = syscall.Timezoneinformation{ - Bias: -10 * 60, - StandardName: [32]uint16{ - 'A', 'U', 'S', ' ', 'E', 'a', 's', 't', 'e', 'r', 'n', ' ', 'S', 't', 'a', 'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e', - }, - StandardDate: syscall.Systemtime{Month: 4, Day: 1, Hour: 3}, - DaylightName: [32]uint16{ - 'A', 'U', 'S', ' ', 'E', 'a', 's', 't', 'e', 'r', 'n', ' ', 'D', 'a', 'y', 'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e', - }, - DaylightDate: syscall.Systemtime{Month: 10, Day: 1, Hour: 2}, - DaylightBias: -60, -} - -func initTestingZone() { - initLocalFromTZI(&usPacific) -} - -func initAusTestingZone() { - initLocalFromTZI(&aus) -} - -func initLocal() { - var i syscall.Timezoneinformation - if _, err := syscall.GetTimeZoneInformation(&i); err != nil { - localLoc.name = "UTC" - return - } - initLocalFromTZI(&i) -} - -func loadLocation(name string) (*Location, error) { - if z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name); err == nil { - z.name = name - return z, nil - } - return nil, errors.New("unknown time zone " + name) -} - -func forceZipFileForTesting(zipOnly bool) { - // We only use the zip file anyway. -} diff --git a/src/pkg/time/zoneinfo_windows_test.go b/src/pkg/time/zoneinfo_windows_test.go deleted file mode 100644 index 9db81b7cf..000000000 --- a/src/pkg/time/zoneinfo_windows_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2013 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 testZoneAbbr(t *testing.T) { - t1 := Now() - // discard nsec - t1 = Date(t1.Year(), t1.Month(), t1.Day(), t1.Hour(), t1.Minute(), t1.Second(), 0, t1.Location()) - t2, err := Parse(RFC1123, t1.Format(RFC1123)) - if err != nil { - t.Fatalf("Parse failed: %v", err) - } - if t1 != t2 { - t.Fatalf("t1 (%v) is not equal to t2 (%v)", t1, t2) - } -} - -func TestLocalZoneAbbr(t *testing.T) { - ResetLocalOnceForTest() // reset the Once to trigger the race - defer ForceUSPacificForTesting() - testZoneAbbr(t) -} - -func TestAusZoneAbbr(t *testing.T) { - ForceAusForTesting() - defer ForceUSPacificForTesting() - testZoneAbbr(t) -} |