diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-10-31 00:59:47 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-10-31 00:59:47 +0000 |
commit | af146490bb04205107cb23e301ec7a8ff927b5fc (patch) | |
tree | 13beeaed3698c61903fe93fb1ce70bd9b18d4e7f /libgo/go/time | |
parent | 725e1be3406315d9bcc8195d7eef0a7082b3c7cc (diff) | |
download | gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.zip gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.gz gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.bz2 |
runtime: Remove now unnecessary pad field from ParFor.
It is not needed due to the removal of the ctx field.
Reviewed-on: https://go-review.googlesource.com/16525
From-SVN: r229616
Diffstat (limited to 'libgo/go/time')
-rw-r--r-- | libgo/go/time/example_test.go | 124 | ||||
-rw-r--r-- | libgo/go/time/format.go | 225 | ||||
-rw-r--r-- | libgo/go/time/sleep_test.go | 41 | ||||
-rw-r--r-- | libgo/go/time/sys_unix.go | 2 | ||||
-rw-r--r-- | libgo/go/time/tick.go | 4 | ||||
-rw-r--r-- | libgo/go/time/time.go | 2 | ||||
-rw-r--r-- | libgo/go/time/time_test.go | 25 | ||||
-rw-r--r-- | libgo/go/time/zoneinfo_ios.go | 51 | ||||
-rw-r--r-- | libgo/go/time/zoneinfo_plan9.go | 10 | ||||
-rw-r--r-- | libgo/go/time/zoneinfo_unix.go | 8 | ||||
-rw-r--r-- | libgo/go/time/zoneinfo_windows.go | 63 |
11 files changed, 373 insertions, 182 deletions
diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go index a37e8b8..f76fdcd4 100644 --- a/libgo/go/time/example_test.go +++ b/libgo/go/time/example_test.go @@ -58,17 +58,127 @@ func ExampleDate() { } 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)) + // Parse a time value from a string in the standard Unix format. + t, err := time.Parse(time.UnixDate, "Sat Mar 7 11:06:39 PST 2015") + if err != nil { // Always check errors even if they should not happen. + panic(err) + } + + // time.Time's Stringer method is useful without any format. + fmt.Println("default format:", t) + + // Predefined constants in the package implement common layouts. + fmt.Println("Unix format:", t.Format(time.UnixDate)) + + // The time zone attached to the time value affects its output. + fmt.Println("Same, in UTC:", t.UTC().Format(time.UnixDate)) + + // The rest of this function demonstrates the properties of the + // layout string used in the format. + + // The layout string used by the Parse function and Format method + // shows by example how the reference time should be represented. + // We stress that one must show how the reference time is formatted, + // not a time of the user's choosing. Thus each layout string is a + // representation of the time stamp, + // Jan 2 15:04:05 2006 MST + // An easy way to remember this value is that it holds, when presented + // in this order, the values (lined up with the elements above): + // 1 2 3 4 5 6 -7 + // There are some wrinkles illustrated below. + + // Most uses of Format and Parse use constant layout strings such as + // the ones defined in this package, but the interface is flexible, + // as these examples show. + + // Define a helper function to make the examples' output look nice. + do := func(name, layout, want string) { + got := t.Format(layout) + if want != got { + fmt.Printf("error: for %q got %q; expected %q\n", layout, got, want) + return + } + fmt.Printf("%-15s %q gives %q\n", name, layout, got) + } + + // Print a header in our output. + fmt.Printf("\nFormats:\n\n") + + // A simple starter example. + do("Basic", "Mon Jan 2 15:04:05 MST 2006", "Sat Mar 7 11:06:39 PST 2015") + + // For fixed-width printing of values, such as the date, that may be one or + // two characters (7 vs. 07), use an _ instead of a space in the layout string. + // Here we print just the day, which is 2 in our layout string and 7 in our + // value. + do("No pad", "<2>", "<7>") + + // An underscore represents a zero pad, if required. + do("Spaces", "<_2>", "< 7>") + + // Similarly, a 0 indicates zero padding. + do("Zeros", "<02>", "<07>") + + // If the value is already the right width, padding is not used. + // For instance, the second (05 in the reference time) in our value is 39, + // so it doesn't need padding, but the minutes (04, 06) does. + do("Suppressed pad", "04:05", "06:39") + + // The predefined constant Unix uses an underscore to pad the day. + // Compare with our simple starter example. + do("Unix", time.UnixDate, "Sat Mar 7 11:06:39 PST 2015") + + // The hour of the reference time is 15, or 3PM. The layout can express + // it either way, and since our value is the morning we should see it as + // an AM time. We show both in one format string. Lower case too. + do("AM/PM", "3PM==3pm==15h", "11AM==11am==11h") + + // When parsing, if the seconds value is followed by a decimal point + // and some digits, that is taken as a fraction of a second even if + // the layout string does not represent the fractional second. + // Here we add a fractional second to our time value used above. + t, err = time.Parse(time.UnixDate, "Sat Mar 7 11:06:39.1234 PST 2015") + if err != nil { + panic(err) + } + // It does not appear in the output if the layout string does not contain + // a representation of the fractional second. + do("No fraction", time.UnixDate, "Sat Mar 7 11:06:39 PST 2015") + + // Fractional seconds can be printed by adding a run of 0s or 9s after + // a decimal point in the seconds value in the layout string. + // If the layout digits are 0s, the fractional second is of the specified + // width. Note that the output has a trailing zero. + do("0s for fraction", "15:04:05.00000", "11:06:39.12340") + + // If the fraction in the layout is 9s, trailing zeros are dropped. + do("9s for fraction", "15:04:05.99999999", "11:06:39.1234") + // Output: - // Nov 10, 2009 at 3:00pm (PST) - // Nov 10, 2009 at 11:00pm (UTC) + // default format: 2015-03-07 11:06:39 -0800 PST + // Unix format: Sat Mar 7 11:06:39 PST 2015 + // Same, in UTC: Sat Mar 7 19:06:39 UTC 2015 + // + // Formats: + // + // Basic "Mon Jan 2 15:04:05 MST 2006" gives "Sat Mar 7 11:06:39 PST 2015" + // No pad "<2>" gives "<7>" + // Spaces "<_2>" gives "< 7>" + // Zeros "<02>" gives "<07>" + // Suppressed pad "04:05" gives "06:39" + // Unix "Mon Jan _2 15:04:05 MST 2006" gives "Sat Mar 7 11:06:39 PST 2015" + // AM/PM "3PM==3pm==15h" gives "11AM==11am==11h" + // No fraction "Mon Jan _2 15:04:05 MST 2006" gives "Sat Mar 7 11:06:39 PST 2015" + // 0s for fraction "15:04:05.00000" gives "11:06:39.12340" + // 9s for fraction "15:04:05.99999999" gives "11:06:39.1234" + } func ExampleParse() { + // See the example for time.Format for a thorough description of how + // to define the layout string to parse a time.Time value; Parse and + // Format use the same model to describe their input and output. + // longForm shows by example how the reference time would be represented in // the desired layout. const longForm = "Jan 2, 2006 at 3:04pm (MST)" diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go index 04e79f3..873d3ff 100644 --- a/libgo/go/time/format.go +++ b/libgo/go/time/format.go @@ -39,6 +39,9 @@ import "errors" // offset for the UTC zone. Thus: // Z0700 Z or ±hhmm // Z07:00 Z or ±hh:mm +// +// The executable example for time.Format demonstrates the working +// of the layout string in detail and is a good reference. const ( ANSIC = "Mon Jan _2 15:04:05 2006" UnixDate = "Mon Jan _2 15:04:05 MST 2006" @@ -288,7 +291,7 @@ var longMonthNames = []string{ "December", } -// match returns true if s1 and s2 match ignoring case. +// match reports whether 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++ { @@ -315,36 +318,34 @@ func lookup(tab []string, val string) (int, string, error) { 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. +// appendInt appends the decimal form of x to b and returns the result. +// If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's. // 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 +func appendInt(b []byte, x int, width int) []byte { + u := uint(x) + if x < 0 { + b = append(b, '-') + u = uint(-x) } - var buf [32]byte - n := len(buf) - if x == 0 { - return append(b, '0') + // Assemble decimal in reverse order. + var buf [20]byte + i := len(buf) + for u >= 10 { + i-- + q := u / 10 + buf[i] = byte('0' + u - q*10) + u = q } - for x >= 10 { - n-- - buf[n] = byte(x%10 + '0') - x /= 10 + i-- + buf[i] = byte('0' + u) + + // Add 0-padding. + for w := len(buf) - i; w < width; w++ { + b = append(b, '0') } - n-- - buf[n] = byte(x + '0') - return append(b, buf[n:]...) + + return append(b, buf[i:]...) } // Never printed, just needs to be non-nil for return by atoi. @@ -407,11 +408,32 @@ func (t Time) String() string { // 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. +// +// A fractional second is represented by adding a period and zeros +// to the end of the seconds section of layout string, as in "15:04:05.000" +// to format a time stamp with millisecond precision. +// // 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 { + const bufSize = 64 + var b []byte + max := len(layout) + 10 + if max < bufSize { + var buf [bufSize]byte + b = buf[:0] + } else { + b = make([]byte, 0, max) + } + b = t.AppendFormat(b, layout) + return string(b) +} + +// AppendFormat is like Format but appends the textual +// representation to b and returns the extended buffer. +func (t Time) AppendFormat(b []byte, layout string) []byte { var ( name, offset, abs = t.locabs() @@ -421,16 +443,7 @@ func (t Time) Format(layout string) string { 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) @@ -458,75 +471,56 @@ func (t Time) Format(layout string) string { if y < 0 { y = -y } - b = appendUint(b, uint(y%100), '0') + b = appendInt(b, y%100, 2) 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) + b = appendInt(b, year, 4) 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) + b = appendInt(b, int(month), 0) case stdZeroMonth: - b = appendUint(b, uint(month), '0') + b = appendInt(b, int(month), 2) 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) + b = appendInt(b, day, 0) case stdUnderDay: - b = appendUint(b, uint(day), ' ') + if day < 10 { + b = append(b, ' ') + } + b = appendInt(b, day, 0) case stdZeroDay: - b = appendUint(b, uint(day), '0') + b = appendInt(b, day, 2) case stdHour: - b = appendUint(b, uint(hour), '0') + b = appendInt(b, hour, 2) case stdHour12: // Noon is 12PM, midnight is 12AM. hr := hour % 12 if hr == 0 { hr = 12 } - b = appendUint(b, uint(hr), 0) + b = appendInt(b, hr, 0) case stdZeroHour12: // Noon is 12PM, midnight is 12AM. hr := hour % 12 if hr == 0 { hr = 12 } - b = appendUint(b, uint(hr), '0') + b = appendInt(b, hr, 2) case stdMinute: - b = appendUint(b, uint(min), 0) + b = appendInt(b, min, 0) case stdZeroMinute: - b = appendUint(b, uint(min), '0') + b = appendInt(b, min, 2) case stdSecond: - b = appendUint(b, uint(sec), 0) + b = appendInt(b, sec, 2) case stdZeroSecond: - b = appendUint(b, uint(sec), '0') + b = appendInt(b, sec, 2) case stdPM: if hour >= 12 { b = append(b, "PM"...) @@ -555,18 +549,18 @@ func (t Time) Format(layout string) string { } else { b = append(b, '+') } - b = appendUint(b, uint(zone/60), '0') + b = appendInt(b, zone/60, 2) if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { b = append(b, ':') } - b = appendUint(b, uint(zone%60), '0') + b = appendInt(b, zone%60, 2) // 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') + b = appendInt(b, absoffset%60, 2) } case stdTZ: @@ -583,13 +577,13 @@ func (t Time) Format(layout string) string { } else { b = append(b, '+') } - b = appendUint(b, uint(zone/60), '0') - b = appendUint(b, uint(zone%60), '0') + b = appendInt(b, zone/60, 2) + b = appendInt(b, zone%60, 2) case stdFracSecond0, stdFracSecond9: b = formatNano(b, uint(t.Nanosecond()), std>>stdArgShift, std&stdMask == stdFracSecond9) } } - return string(b) + return b } var errBad = errors.New("bad value for field") // placeholder not passed to user @@ -620,8 +614,7 @@ func (e *ParseError) Error() string { 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. +// isDigit reports whether s[i] is in range and is a decimal digit. func isDigit(s string, i int) bool { if len(s) <= i { return false @@ -681,10 +674,13 @@ func skip(value, prefix string) (string, error) { // 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. +// Also, the executable example for time.Format demonstrates the working +// of the layout string in detail and is a good reference. // // Elements omitted from the value are assumed to be zero or, when // zero is impossible, one, so parsing "3:04pm" returns the time @@ -1131,24 +1127,28 @@ func leadingInt(s string) (x int64, rem string, err error) { if c < '0' || c > '9' { break } - if x >= (1<<63-10)/10 { + if x > (1<<63-1)/10 { // overflow return 0, "", errLeadingInt } x = x*10 + int64(c) - '0' + if x < 0 { + // overflow + return 0, "", errLeadingInt + } } 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), +var unitMap = map[string]int64{ + "ns": int64(Nanosecond), + "us": int64(Microsecond), + "µs": int64(Microsecond), // U+00B5 = micro symbol + "μs": int64(Microsecond), // U+03BC = Greek letter mu + "ms": int64(Millisecond), + "s": int64(Second), + "m": int64(Minute), + "h": int64(Hour), } // ParseDuration parses a duration string. @@ -1159,7 +1159,7 @@ var unitMap = map[string]float64{ func ParseDuration(s string) (Duration, error) { // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ orig := s - f := float64(0) + var d int64 neg := false // Consume [-+]? @@ -1178,22 +1178,23 @@ func ParseDuration(s string) (Duration, error) { return 0, errors.New("time: invalid duration " + orig) } for s != "" { - g := float64(0) // this element of the sequence + var ( + v, f int64 // integers before, after decimal point + scale float64 = 1 // value = v + f/scale + ) - var x int64 var err error // The next character must be [0-9.] - if !(s[0] == '.' || ('0' <= s[0] && s[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) + v, 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]*)? @@ -1201,15 +1202,13 @@ func ParseDuration(s string) (Duration, error) { if s != "" && s[0] == '.' { s = s[1:] pl := len(s) - x, s, err = leadingInt(s) + f, 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 { @@ -1221,7 +1220,7 @@ func ParseDuration(s string) (Duration, error) { i := 0 for ; i < len(s); i++ { c := s[i] - if c == '.' || ('0' <= c && c <= '9') { + if c == '.' || '0' <= c && c <= '9' { break } } @@ -1234,15 +1233,29 @@ func ParseDuration(s string) (Duration, error) { if !ok { return 0, errors.New("time: unknown unit " + u + " in duration " + orig) } - - f += g * unit + if v > (1<<63-1)/unit { + // overflow + return 0, errors.New("time: invalid duration " + orig) + } + v *= unit + if f > 0 { + // float64 is needed to be nanosecond accurate for fractions of hours. + // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit) + v += int64(float64(f) * (float64(unit) / scale)) + if v < 0 { + // overflow + return 0, errors.New("time: invalid duration " + orig) + } + } + d += v + if d < 0 { + // overflow + return 0, errors.New("time: invalid duration " + orig) + } } if neg { - f = -f - } - if f < float64(-1<<63) || f > float64(1<<63-1) { - return 0, errors.New("time: overflow parsing duration") + d = -d } - return Duration(f), nil + return Duration(d), nil } diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go index c21eb99..c286bd0 100644 --- a/libgo/go/time/sleep_test.go +++ b/libgo/go/time/sleep_test.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "runtime" - "sort" "strings" "sync" "sync/atomic" @@ -224,10 +223,11 @@ func TestAfterStop(t *testing.T) { 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 + const attempts = 5 err := errors.New("!=nil") for i := 0; i < attempts && err != nil; i++ { - if err = testAfterQueuing(t); err != nil { + delta := Duration(20+i*50) * Millisecond + if err = testAfterQueuing(t, delta); err != nil { t.Logf("attempt %v failed: %v", i, err) } } @@ -248,11 +248,7 @@ 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 - } +func testAfterQueuing(t *testing.T, delta Duration) error { // make the result channel buffered because we don't want // to depend on channel queueing semantics that might // possibly change in the future. @@ -260,18 +256,25 @@ func testAfterQueuing(t *testing.T) error { t0 := Now() for _, slot := range slots { - go await(slot, result, After(Duration(slot)*Delta)) + go await(slot, result, After(Duration(slot)*delta)) } - sort.Ints(slots) - for _, slot := range slots { + var order []int + var times []Time + for range slots { r := <-result - if r.slot != slot { - return fmt.Errorf("after slot %d, expected %d", r.slot, slot) + order = append(order, r.slot) + times = append(times, r.t) + } + for i := range order { + if i > 0 && order[i] < order[i-1] { + return fmt.Errorf("After calls returned out of order: %v", order) } - 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) + } + for i, t := range times { + dt := t.Sub(t0) + target := Duration(order[i]) * 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 @@ -384,6 +387,10 @@ func TestOverflowSleep(t *testing.T) { // 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) { + if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" { + t.Skipf("skipping on %s/%s, see issue 10043", runtime.GOOS, runtime.GOARCH) + } + ticker := NewTicker(Hour) defer func() { // would deadlock here before the fix due to diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go index 379e13d..e592415 100644 --- a/libgo/go/time/sys_unix.go +++ b/libgo/go/time/sys_unix.go @@ -74,3 +74,5 @@ func preadn(fd uintptr, buf []byte, off int) error { } return nil } + +func isNotExist(err error) bool { return err == syscall.ENOENT } diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go index 1900784..196e8ac 100644 --- a/libgo/go/time/tick.go +++ b/libgo/go/time/tick.go @@ -47,7 +47,9 @@ func (t *Ticker) Stop() { } // 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. +// channel only. While Tick is useful for clients that have no need to shut down +// the Ticker, be aware that without a way to shut it down the underlying +// Ticker cannot be recovered by the garbage collector; it "leaks". func Tick(d Duration) <-chan Time { if d <= 0 { return nil diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go index 0300e84..294cc77 100644 --- a/libgo/go/time/time.go +++ b/libgo/go/time/time.go @@ -966,6 +966,8 @@ func (t *Time) UnmarshalText(data []byte) (err error) { // 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]. +// Not all sec values have a corresponding time value. One such +// value is 1<<63-1 (the largest int64 value). func Unix(sec int64, nsec int64) Time { if nsec < 0 || nsec >= 1e9 { n := nsec / 1e9 diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go index 7e31dd7..2d16ea5 100644 --- a/libgo/go/time/time_test.go +++ b/libgo/go/time/time_test.go @@ -830,8 +830,16 @@ var parseDurationTests = []struct { {"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 + // more than 9 digits after decimal point, see https://golang.org/issue/6617 {"0.3333333333333333333h", true, 20 * Minute}, + // 9007199254740993 = 1<<53+1 cannot be stored precisely in a float64 + {"9007199254740993ns", true, (1<<53 + 1) * Nanosecond}, + // largest duration that can be represented by int64 in nanoseconds + {"9223372036854775807ns", true, (1<<63 - 1) * Nanosecond}, + {"9223372036854775.807us", true, (1<<63 - 1) * Nanosecond}, + {"9223372036s854ms775us807ns", true, (1<<63 - 1) * Nanosecond}, + // large negative value + {"-9223372036854775807ns", true, -1<<63 + 1*Nanosecond}, // errors {"", false, 0}, @@ -842,7 +850,13 @@ var parseDurationTests = []struct { {"-.", false, 0}, {".s", false, 0}, {"+.s", false, 0}, - {"3000000h", false, 0}, // overflow + {"3000000h", false, 0}, // overflow + {"9223372036854775808ns", false, 0}, // overflow + {"9223372036854775.808us", false, 0}, // overflow + {"9223372036854ms775us808ns", false, 0}, // overflow + // largest negative value of type int64 in nanoseconds should fail + // see https://go-review.googlesource.com/#/c/2461/ + {"-9223372036854775808ns", false, 0}, } func TestParseDuration(t *testing.T) { @@ -1052,6 +1066,13 @@ func BenchmarkParse(b *testing.B) { } } +func BenchmarkParseDuration(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseDuration("9007199254.740993ms") + ParseDuration("9007199254740993ns") + } +} + func BenchmarkHour(b *testing.B) { t := Now() for i := 0; i < b.N; i++ { diff --git a/libgo/go/time/zoneinfo_ios.go b/libgo/go/time/zoneinfo_ios.go new file mode 100644 index 0000000..f09166c --- /dev/null +++ b/libgo/go/time/zoneinfo_ios.go @@ -0,0 +1,51 @@ +// Copyright 2015 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 +// +build arm arm64 + +package time + +import "syscall" + +var zoneFile string + +func init() { + wd, err := syscall.Getwd() + if err != nil { + return + } + + // The working directory at initialization is the root of the + // app bundle: "/private/.../bundlename.app". That's where we + // keep zoneinfo.zip. + zoneFile = wd + "/zoneinfo.zip" +} + +func forceZipFileForTesting(zipOnly bool) { + // On iOS we only have the zip file. +} + +func initTestingZone() { + z, err := loadZoneFile(zoneFile, "America/Los_Angeles") + if err != nil { + panic("cannot load America/Los_Angeles for testing: " + err.Error()) + } + z.name = "Local" + localLoc = *z +} + +func initLocal() { + // TODO(crawshaw): [NSTimeZone localTimeZone] + localLoc = *UTC +} + +func loadLocation(name string) (*Location, error) { + z, err := loadZoneFile(zoneFile, name) + if err != nil { + return nil, err + } + z.name = name + return z, nil +} diff --git a/libgo/go/time/zoneinfo_plan9.go b/libgo/go/time/zoneinfo_plan9.go index 4bb0cb3..0694f0a 100644 --- a/libgo/go/time/zoneinfo_plan9.go +++ b/libgo/go/time/zoneinfo_plan9.go @@ -7,7 +7,6 @@ package time import ( - "errors" "runtime" "syscall" ) @@ -148,11 +147,12 @@ func initLocal() { } 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 + z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name) + if err != nil { + return nil, err } - return nil, errors.New("unknown time zone " + name) + z.name = name + return z, nil } func forceZipFileForTesting(zipOnly bool) { diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go index 3fe8e55..5fc669e 100644 --- a/libgo/go/time/zoneinfo_unix.go +++ b/libgo/go/time/zoneinfo_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin,386 darwin,amd64 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. @@ -70,11 +70,17 @@ func initLocal() { } func loadLocation(name string) (*Location, error) { + var firstErr error for _, zoneDir := range zoneDirs { if z, err := loadZoneFile(zoneDir, name); err == nil { z.name = name return z, nil + } else if firstErr == nil && !isNotExist(err) { + firstErr = err } } + if firstErr != nil { + return nil, firstErr + } return nil, errors.New("unknown time zone " + name) } diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go index 02d8e0e..d04ebec 100644 --- a/libgo/go/time/zoneinfo_windows.go +++ b/libgo/go/time/zoneinfo_windows.go @@ -6,9 +6,9 @@ package time import ( "errors" + "internal/syscall/windows/registry" "runtime" "syscall" - "unsafe" ) //go:generate go run genzabbrs.go -output zoneinfo_abbrs_windows.go @@ -20,39 +20,23 @@ import ( // 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 { +func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (matched bool, err2 error) { + k, err := registry.OpenKey(zones, kname, registry.READ) + if err != nil { return false, err } - defer syscall.RegCloseKey(h) + defer k.Close() - s, err := getKeyValue(h, "Std") + s, _, err := k.GetStringValue("Std") if err != nil { return false, err } if s != stdname { return false, nil } - s, err = getKeyValue(h, "Dlt") + s, _, err = k.GetStringValue("Dlt") if err != nil { return false, err } @@ -65,28 +49,20 @@ func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) ( // 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 { + k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE) + if err != nil { return "", err } - defer syscall.RegCloseKey(zones) + defer k.Close() - var count uint32 - if err := syscall.RegQueryInfoKey(zones, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil); err != nil { + names, err := k.ReadSubKeyNames(-1) + if 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) + for _, name := range names { + matched, err := matchZoneKey(k, name, stdname, dstname) if err == nil && matched { - return kname, nil + return name, nil } } return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`) @@ -260,11 +236,12 @@ func initLocal() { } 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 + z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name) + if err != nil { + return nil, err } - return nil, errors.New("unknown time zone " + name) + z.name = name + return z, nil } func forceZipFileForTesting(zipOnly bool) { |