summaryrefslogtreecommitdiff
path: root/libgo/go/time
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2015-10-31 00:59:47 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2015-10-31 00:59:47 +0000
commitaf146490bb04205107cb23e301ec7a8ff927b5fc (patch)
tree13beeaed3698c61903fe93fb1ce70bd9b18d4e7f /libgo/go/time
parent725e1be3406315d9bcc8195d7eef0a7082b3c7cc (diff)
downloadgcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.gz
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.go124
-rw-r--r--libgo/go/time/format.go225
-rw-r--r--libgo/go/time/sleep_test.go41
-rw-r--r--libgo/go/time/sys_unix.go2
-rw-r--r--libgo/go/time/tick.go4
-rw-r--r--libgo/go/time/time.go2
-rw-r--r--libgo/go/time/time_test.go25
-rw-r--r--libgo/go/time/zoneinfo_ios.go51
-rw-r--r--libgo/go/time/zoneinfo_plan9.go10
-rw-r--r--libgo/go/time/zoneinfo_unix.go8
-rw-r--r--libgo/go/time/zoneinfo_windows.go63
11 files changed, 373 insertions, 182 deletions
diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go
index a37e8b86ddc..f76fdcd4d03 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 04e79f32dcd..873d3ffde91 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 c21eb997dc4..c286bd00273 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 379e13d6a53..e592415daa5 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 19007841e1a..196e8ac61a6 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 0300e846a4b..294cc77f417 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 7e31dd78a92..2d16ea59ae3 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 00000000000..f09166c89e9
--- /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 4bb0cb39096..0694f0a9904 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 3fe8e55795c..5fc669e478d 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 02d8e0edcc8..d04ebec614e 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) {