aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/time
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2017-09-14 17:11:35 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-09-14 17:11:35 +0000
commitbc998d034f45d1828a8663b2eed928faf22a7d01 (patch)
tree8d262a22ca7318f4bcd64269fe8fe9e45bcf8d0f /libgo/go/time
parenta41a6142df74219f596e612d3a7775f68ca6e96f (diff)
downloadgcc-bc998d034f45d1828a8663b2eed928faf22a7d01.zip
gcc-bc998d034f45d1828a8663b2eed928faf22a7d01.tar.gz
gcc-bc998d034f45d1828a8663b2eed928faf22a7d01.tar.bz2
libgo: update to go1.9
Reviewed-on: https://go-review.googlesource.com/63753 From-SVN: r252767
Diffstat (limited to 'libgo/go/time')
-rw-r--r--libgo/go/time/example_test.go3
-rw-r--r--libgo/go/time/export_test.go13
-rw-r--r--libgo/go/time/format.go50
-rw-r--r--libgo/go/time/format_test.go4
-rw-r--r--libgo/go/time/genzabbrs.go4
-rw-r--r--libgo/go/time/mono_test.go261
-rw-r--r--libgo/go/time/sleep_test.go4
-rw-r--r--libgo/go/time/sys_plan9.go4
-rw-r--r--libgo/go/time/sys_unix.go4
-rw-r--r--libgo/go/time/sys_windows.go4
-rw-r--r--libgo/go/time/time.go397
-rw-r--r--libgo/go/time/time_test.go74
-rw-r--r--libgo/go/time/zoneinfo.go34
-rw-r--r--libgo/go/time/zoneinfo_abbrs_windows.go176
-rw-r--r--libgo/go/time/zoneinfo_plan9.go2
-rw-r--r--libgo/go/time/zoneinfo_read.go13
-rw-r--r--libgo/go/time/zoneinfo_test.go50
-rw-r--r--libgo/go/time/zoneinfo_windows.go2
18 files changed, 921 insertions, 178 deletions
diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go
index 7dc2bb5..aeb63ca 100644
--- a/libgo/go/time/example_test.go
+++ b/libgo/go/time/example_test.go
@@ -256,6 +256,9 @@ func ExampleTime_Truncate() {
for _, d := range trunc {
fmt.Printf("t.Truncate(%5s) = %s\n", d, t.Truncate(d).Format("15:04:05.999999999"))
}
+ // To round to the last midnight in the local timezone, create a new Date.
+ midnight := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
+ _ = midnight
// Output:
// t.Truncate( 1ns) = 12:15:30.918273645
diff --git a/libgo/go/time/export_test.go b/libgo/go/time/export_test.go
index 6cd535f..4c08ab1 100644
--- a/libgo/go/time/export_test.go
+++ b/libgo/go/time/export_test.go
@@ -18,7 +18,20 @@ func ForceUSPacificForTesting() {
localOnce.Do(initTestingZone)
}
+func ZoneinfoForTesting() *string {
+ return zoneinfo
+}
+
+func ResetZoneinfoForTesting() {
+ zoneinfo = nil
+ zoneinfoOnce = sync.Once{}
+}
+
var (
ForceZipFileForTesting = forceZipFileForTesting
ParseTimeZone = parseTimeZone
+ SetMono = (*Time).setMono
+ GetMono = (*Time).mono
+ ErrLocation = errLocation
+ ReadFile = readFile
)
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
index b903e14..8c16e87 100644
--- a/libgo/go/time/format.go
+++ b/libgo/go/time/format.go
@@ -61,6 +61,8 @@ import "errors"
// RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting;
// when used with time.Parse they do not accept all the time formats
// permitted by the RFCs.
+// The RFC3339Nano format removes trailing zeros from the seconds field
+// and thus may not sort correctly once formatted.
const (
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
@@ -424,8 +426,41 @@ func formatNano(b []byte, nanosec uint, n int, trim bool) []byte {
// String returns the time formatted using the format string
// "2006-01-02 15:04:05.999999999 -0700 MST"
+//
+// If the time has a monotonic clock reading, the returned string
+// includes a final field "m=±<value>", where value is the monotonic
+// clock reading formatted as a decimal number of seconds.
+//
+// The returned string is meant for debugging; for a stable serialized
+// representation, use t.MarshalText, t.MarshalBinary, or t.Format
+// with an explicit format string.
func (t Time) String() string {
- return t.Format("2006-01-02 15:04:05.999999999 -0700 MST")
+ s := t.Format("2006-01-02 15:04:05.999999999 -0700 MST")
+
+ // Format monotonic clock reading as m=±ddd.nnnnnnnnn.
+ if t.wall&hasMonotonic != 0 {
+ m2 := uint64(t.ext)
+ sign := byte('+')
+ if t.ext < 0 {
+ sign = '-'
+ m2 = -m2
+ }
+ m1, m2 := m2/1e9, m2%1e9
+ m0, m1 := m1/1e9, m1%1e9
+ var buf []byte
+ buf = append(buf, " m="...)
+ buf = append(buf, sign)
+ wid := 0
+ if m0 != 0 {
+ buf = appendInt(buf, int(m0), 0)
+ wid = 9
+ }
+ buf = appendInt(buf, int(m1), wid)
+ buf = append(buf, '.')
+ buf = appendInt(buf, int(m2), 9)
+ s += string(buf)
+ }
+ return s
}
// Format returns a textual representation of the time value formatted
@@ -725,11 +760,6 @@ func skip(value, prefix string) (string, error) {
// 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.
//
-// No checking is done that the day of the month is within the month's
-// valid dates; any one- or two-digit value is accepted. For example
-// February 31 and even February 99 are valid dates, specifying dates
-// in March and May. This behavior is consistent with time.Date.
-//
// 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.
@@ -1022,11 +1052,11 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
if zoneOffset != -1 {
t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
- t.sec -= int64(zoneOffset)
+ t.addSec(-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)
+ name, offset, _, _, _ := local.lookup(t.unixSec())
if offset == zoneOffset && (zoneName == "" || name == zoneName) {
t.setLoc(local)
return t, nil
@@ -1041,9 +1071,9 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
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)
+ offset, _, ok := local.lookupName(zoneName, t.unixSec())
if ok {
- t.sec -= int64(offset)
+ t.addSec(-int64(offset))
t.setLoc(local)
return t, nil
}
diff --git a/libgo/go/time/format_test.go b/libgo/go/time/format_test.go
index 0e4a417..abaeb50 100644
--- a/libgo/go/time/format_test.go
+++ b/libgo/go/time/format_test.go
@@ -380,8 +380,8 @@ func checkTime(time Time, test *ParseTest, t *testing.T) {
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 {
+ t1 := Unix(sec/2, 0)
+ if t1.Year() < 1000 || t1.Year() > 9999 || t1.Unix() != sec {
// not required to work
return true
}
diff --git a/libgo/go/time/genzabbrs.go b/libgo/go/time/genzabbrs.go
index 6281f73..824a67f 100644
--- a/libgo/go/time/genzabbrs.go
+++ b/libgo/go/time/genzabbrs.go
@@ -142,8 +142,8 @@ const prog = `
// 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}}
+// Code generated by genzabbrs.go; DO NOT EDIT.
+// Based on information from {{.URL}}
package time
diff --git a/libgo/go/time/mono_test.go b/libgo/go/time/mono_test.go
new file mode 100644
index 0000000..8778ab7
--- /dev/null
+++ b/libgo/go/time/mono_test.go
@@ -0,0 +1,261 @@
+// Copyright 2017 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 (
+ "strings"
+ "testing"
+ . "time"
+)
+
+func TestHasMonotonicClock(t *testing.T) {
+ yes := func(expr string, tt Time) {
+ if GetMono(&tt) == 0 {
+ t.Errorf("%s: missing monotonic clock reading", expr)
+ }
+ }
+ no := func(expr string, tt Time) {
+ if GetMono(&tt) != 0 {
+ t.Errorf("%s: unexpected monotonic clock reading", expr)
+ }
+ }
+
+ yes("<-After(1)", <-After(1))
+ ticker := NewTicker(1)
+ yes("<-Tick(1)", <-ticker.C)
+ ticker.Stop()
+ no("Date(2009, 11, 23, 0, 0, 0, 0, UTC)", Date(2009, 11, 23, 0, 0, 0, 0, UTC))
+ tp, _ := Parse(UnixDate, "Sat Mar 7 11:06:39 PST 2015")
+ no(`Parse(UnixDate, "Sat Mar 7 11:06:39 PST 2015")`, tp)
+ no("Unix(1486057371, 0)", Unix(1486057371, 0))
+
+ yes("Now()", Now())
+
+ tu := Unix(1486057371, 0)
+ tm := tu
+ SetMono(&tm, 123456)
+ no("tu", tu)
+ yes("tm", tm)
+
+ no("tu.Add(1)", tu.Add(1))
+ no("tu.In(UTC)", tu.In(UTC))
+ no("tu.AddDate(1, 1, 1)", tu.AddDate(1, 1, 1))
+ no("tu.AddDate(0, 0, 0)", tu.AddDate(0, 0, 0))
+ no("tu.Local()", tu.Local())
+ no("tu.UTC()", tu.UTC())
+ no("tu.Round(2)", tu.Round(2))
+ no("tu.Truncate(2)", tu.Truncate(2))
+
+ yes("tm.Add(1)", tm.Add(1))
+ no("tm.AddDate(1, 1, 1)", tm.AddDate(1, 1, 1))
+ no("tm.AddDate(0, 0, 0)", tm.AddDate(0, 0, 0))
+ no("tm.In(UTC)", tm.In(UTC))
+ no("tm.Local()", tm.Local())
+ no("tm.UTC()", tm.UTC())
+ no("tm.Round(2)", tm.Round(2))
+ no("tm.Truncate(2)", tm.Truncate(2))
+}
+
+func TestMonotonicAdd(t *testing.T) {
+ tm := Unix(1486057371, 123456)
+ SetMono(&tm, 123456789012345)
+
+ t2 := tm.Add(1e8)
+ if t2.Nanosecond() != 100123456 {
+ t.Errorf("t2.Nanosecond() = %d, want 100123456", t2.Nanosecond())
+ }
+ if GetMono(&t2) != 123456889012345 {
+ t.Errorf("t2.mono = %d, want 123456889012345", GetMono(&t2))
+ }
+
+ t3 := tm.Add(-9e18) // wall now out of range
+ if t3.Nanosecond() != 123456 {
+ t.Errorf("t3.Nanosecond() = %d, want 123456", t3.Nanosecond())
+ }
+ if GetMono(&t3) != 0 {
+ t.Errorf("t3.mono = %d, want 0 (wall time out of range for monotonic reading)", GetMono(&t3))
+ }
+
+ t4 := tm.Add(+9e18) // wall now out of range
+ if t4.Nanosecond() != 123456 {
+ t.Errorf("t4.Nanosecond() = %d, want 123456", t4.Nanosecond())
+ }
+ if GetMono(&t4) != 0 {
+ t.Errorf("t4.mono = %d, want 0 (wall time out of range for monotonic reading)", GetMono(&t4))
+ }
+
+ tn := Now()
+ tn1 := tn.Add(1 * Hour)
+ Sleep(100 * Millisecond)
+ d := Until(tn1)
+ if d < 59*Minute {
+ t.Errorf("Until(Now().Add(1*Hour)) = %v, wanted at least 59m", d)
+ }
+ now := Now()
+ if now.After(tn1) {
+ t.Errorf("Now().After(Now().Add(1*Hour)) = true, want false")
+ }
+ if !tn1.After(now) {
+ t.Errorf("Now().Add(1*Hour).After(now) = false, want true")
+ }
+ if tn1.Before(now) {
+ t.Errorf("Now().Add(1*Hour).Before(Now()) = true, want false")
+ }
+ if !now.Before(tn1) {
+ t.Errorf("Now().Before(Now().Add(1*Hour)) = false, want true")
+ }
+}
+
+func TestMonotonicSub(t *testing.T) {
+ t1 := Unix(1483228799, 995e6)
+ SetMono(&t1, 123456789012345)
+
+ t2 := Unix(1483228799, 5e6)
+ SetMono(&t2, 123456789012345+10e6)
+
+ t3 := Unix(1483228799, 995e6)
+ SetMono(&t3, 123456789012345+1e9)
+
+ t1w := t1.AddDate(0, 0, 0)
+ if GetMono(&t1w) != 0 {
+ t.Fatalf("AddDate didn't strip monotonic clock reading")
+ }
+ t2w := t2.AddDate(0, 0, 0)
+ if GetMono(&t2w) != 0 {
+ t.Fatalf("AddDate didn't strip monotonic clock reading")
+ }
+ t3w := t3.AddDate(0, 0, 0)
+ if GetMono(&t3w) != 0 {
+ t.Fatalf("AddDate didn't strip monotonic clock reading")
+ }
+
+ sub := func(txs, tys string, tx, txw, ty, tyw Time, d, dw Duration) {
+ check := func(expr string, d, want Duration) {
+ if d != want {
+ t.Errorf("%s = %v, want %v", expr, d, want)
+ }
+ }
+ check(txs+".Sub("+tys+")", tx.Sub(ty), d)
+ check(txs+"w.Sub("+tys+")", txw.Sub(ty), dw)
+ check(txs+".Sub("+tys+"w)", tx.Sub(tyw), dw)
+ check(txs+"w.Sub("+tys+"w)", txw.Sub(tyw), dw)
+ }
+ sub("t1", "t1", t1, t1w, t1, t1w, 0, 0)
+ sub("t1", "t2", t1, t1w, t2, t2w, -10*Millisecond, 990*Millisecond)
+ sub("t1", "t3", t1, t1w, t3, t3w, -1000*Millisecond, 0)
+
+ sub("t2", "t1", t2, t2w, t1, t1w, 10*Millisecond, -990*Millisecond)
+ sub("t2", "t2", t2, t2w, t2, t2w, 0, 0)
+ sub("t2", "t3", t2, t2w, t3, t3w, -990*Millisecond, -990*Millisecond)
+
+ sub("t3", "t1", t3, t3w, t1, t1w, 1000*Millisecond, 0)
+ sub("t3", "t2", t3, t3w, t2, t2w, 990*Millisecond, 990*Millisecond)
+ sub("t3", "t3", t3, t3w, t3, t3w, 0, 0)
+
+ cmp := func(txs, tys string, tx, txw, ty, tyw Time, c, cw int) {
+ check := func(expr string, b, want bool) {
+ if b != want {
+ t.Errorf("%s = %v, want %v", expr, b, want)
+ }
+ }
+ check(txs+".After("+tys+")", tx.After(ty), c > 0)
+ check(txs+"w.After("+tys+")", txw.After(ty), cw > 0)
+ check(txs+".After("+tys+"w)", tx.After(tyw), cw > 0)
+ check(txs+"w.After("+tys+"w)", txw.After(tyw), cw > 0)
+
+ check(txs+".Before("+tys+")", tx.Before(ty), c < 0)
+ check(txs+"w.Before("+tys+")", txw.Before(ty), cw < 0)
+ check(txs+".Before("+tys+"w)", tx.Before(tyw), cw < 0)
+ check(txs+"w.Before("+tys+"w)", txw.Before(tyw), cw < 0)
+
+ check(txs+".Equal("+tys+")", tx.Equal(ty), c == 0)
+ check(txs+"w.Equal("+tys+")", txw.Equal(ty), cw == 0)
+ check(txs+".Equal("+tys+"w)", tx.Equal(tyw), cw == 0)
+ check(txs+"w.Equal("+tys+"w)", txw.Equal(tyw), cw == 0)
+ }
+
+ cmp("t1", "t1", t1, t1w, t1, t1w, 0, 0)
+ cmp("t1", "t2", t1, t1w, t2, t2w, -1, +1)
+ cmp("t1", "t3", t1, t1w, t3, t3w, -1, 0)
+
+ cmp("t2", "t1", t2, t2w, t1, t1w, +1, -1)
+ cmp("t2", "t2", t2, t2w, t2, t2w, 0, 0)
+ cmp("t2", "t3", t2, t2w, t3, t3w, -1, -1)
+
+ cmp("t3", "t1", t3, t3w, t1, t1w, +1, 0)
+ cmp("t3", "t2", t3, t3w, t2, t2w, +1, +1)
+ cmp("t3", "t3", t3, t3w, t3, t3w, 0, 0)
+}
+
+func TestMonotonicOverflow(t *testing.T) {
+ t1 := Now().Add(-30 * Second)
+ d := Until(t1)
+ if d < -35*Second || -30*Second < d {
+ t.Errorf("Until(Now().Add(-30s)) = %v, want roughly -30s (-35s to -30s)", d)
+ }
+
+ t1 = Now().Add(30 * Second)
+ d = Until(t1)
+ if d < 25*Second || 30*Second < d {
+ t.Errorf("Until(Now().Add(-30s)) = %v, want roughly 30s (25s to 30s)", d)
+ }
+
+ t0 := Now()
+ t1 = t0.Add(Duration(1<<63 - 1))
+ if GetMono(&t1) != 0 {
+ t.Errorf("Now().Add(maxDuration) has monotonic clock reading (%v => %v %d %d)", t0.String(), t1.String(), t0.Unix(), t1.Unix())
+ }
+ t2 := t1.Add(-Duration(1<<63 - 1))
+ d = Since(t2)
+ if d < -10*Second || 10*Second < d {
+ t.Errorf("Since(Now().Add(max).Add(-max)) = %v, want [-10s, 10s]", d)
+ }
+
+ t0 = Now()
+ t1 = t0.Add(1 * Hour)
+ Sleep(100 * Millisecond)
+ t2 = Now().Add(-5 * Second)
+ if !t1.After(t2) {
+ t.Errorf("Now().Add(1*Hour).After(Now().Add(-5*Second)) = false, want true\nt1=%v\nt2=%v", t1, t2)
+ }
+ if t2.After(t1) {
+ t.Errorf("Now().Add(-5*Second).After(Now().Add(1*Hour)) = true, want false\nt1=%v\nt2=%v", t1, t2)
+ }
+ if t1.Before(t2) {
+ t.Errorf("Now().Add(1*Hour).Before(Now().Add(-5*Second)) = true, want false\nt1=%v\nt2=%v", t1, t2)
+ }
+ if !t2.Before(t1) {
+ t.Errorf("Now().Add(-5*Second).Before(Now().Add(1*Hour)) = false, want true\nt1=%v\nt2=%v", t1, t2)
+ }
+}
+
+var monotonicStringTests = []struct {
+ mono int64
+ want string
+}{
+ {0, "m=+0.000000000"},
+ {123456789, "m=+0.123456789"},
+ {-123456789, "m=-0.123456789"},
+ {123456789000, "m=+123.456789000"},
+ {-123456789000, "m=-123.456789000"},
+ {9e18, "m=+9000000000.000000000"},
+ {-9e18, "m=-9000000000.000000000"},
+ {-1 << 63, "m=-9223372036.854775808"},
+}
+
+func TestMonotonicString(t *testing.T) {
+ t1 := Now()
+ t.Logf("Now() = %v", t1)
+
+ for _, tt := range monotonicStringTests {
+ t1 := Now()
+ SetMono(&t1, tt.mono)
+ s := t1.String()
+ got := s[strings.LastIndex(s, " ")+1:]
+ if got != tt.want {
+ t.Errorf("with mono=%d: got %q; want %q", tt.mono, got, tt.want)
+ }
+ }
+}
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
index c286bd0..546b28a 100644
--- a/libgo/go/time/sleep_test.go
+++ b/libgo/go/time/sleep_test.go
@@ -227,7 +227,7 @@ func TestAfterQueuing(t *testing.T) {
err := errors.New("!=nil")
for i := 0; i < attempts && err != nil; i++ {
delta := Duration(20+i*50) * Millisecond
- if err = testAfterQueuing(t, delta); err != nil {
+ if err = testAfterQueuing(delta); err != nil {
t.Logf("attempt %v failed: %v", i, err)
}
}
@@ -248,7 +248,7 @@ func await(slot int, result chan<- afterResult, ac <-chan Time) {
result <- afterResult{slot, <-ac}
}
-func testAfterQueuing(t *testing.T, delta Duration) error {
+func testAfterQueuing(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.
diff --git a/libgo/go/time/sys_plan9.go b/libgo/go/time/sys_plan9.go
index 11365a7..9086a6e 100644
--- a/libgo/go/time/sys_plan9.go
+++ b/libgo/go/time/sys_plan9.go
@@ -19,6 +19,7 @@ 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.
+// It returns an error if name exceeds maxFileSize bytes.
func readFile(name string) ([]byte, error) {
f, err := syscall.Open(name, syscall.O_RDONLY)
if err != nil {
@@ -38,6 +39,9 @@ func readFile(name string) ([]byte, error) {
if n == 0 || err != nil {
break
}
+ if len(ret) > maxFileSize {
+ return nil, fileSizeError(name)
+ }
}
return ret, err
}
diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go
index 4c68bbd..5715275 100644
--- a/libgo/go/time/sys_unix.go
+++ b/libgo/go/time/sys_unix.go
@@ -19,6 +19,7 @@ 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.
+// It returns an error if name exceeds maxFileSize bytes.
func readFile(name string) ([]byte, error) {
f, err := syscall.Open(name, syscall.O_RDONLY, 0)
if err != nil {
@@ -38,6 +39,9 @@ func readFile(name string) ([]byte, error) {
if n == 0 || err != nil {
break
}
+ if len(ret) > maxFileSize {
+ return nil, fileSizeError(name)
+ }
}
return ret, err
}
diff --git a/libgo/go/time/sys_windows.go b/libgo/go/time/sys_windows.go
index a4a068f..9e38165 100644
--- a/libgo/go/time/sys_windows.go
+++ b/libgo/go/time/sys_windows.go
@@ -16,6 +16,7 @@ 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.
+// It returns an error if name exceeds maxFileSize bytes.
func readFile(name string) ([]byte, error) {
f, err := syscall.Open(name, syscall.O_RDONLY, 0)
if err != nil {
@@ -35,6 +36,9 @@ func readFile(name string) ([]byte, error) {
if n == 0 || err != nil {
break
}
+ if len(ret) > maxFileSize {
+ return nil, fileSizeError(name)
+ }
}
return ret, err
}
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index 10b3246..8a29eef 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -6,6 +6,69 @@
//
// The calendrical calculations always assume a Gregorian calendar, with
// no leap seconds.
+//
+// Monotonic Clocks
+//
+// Operating systems provide both a “wall clock,” which is subject to
+// changes for clock synchronization, and a “monotonic clock,” which is
+// not. The general rule is that the wall clock is for telling time and
+// the monotonic clock is for measuring time. Rather than split the API,
+// in this package the Time returned by time.Now contains both a wall
+// clock reading and a monotonic clock reading; later time-telling
+// operations use the wall clock reading, but later time-measuring
+// operations, specifically comparisons and subtractions, use the
+// monotonic clock reading.
+//
+// For example, this code always computes a positive elapsed time of
+// approximately 20 milliseconds, even if the wall clock is changed during
+// the operation being timed:
+//
+// start := time.Now()
+// ... operation that takes 20 milliseconds ...
+// t := time.Now()
+// elapsed := t.Sub(start)
+//
+// Other idioms, such as time.Since(start), time.Until(deadline), and
+// time.Now().Before(deadline), are similarly robust against wall clock
+// resets.
+//
+// The rest of this section gives the precise details of how operations
+// use monotonic clocks, but understanding those details is not required
+// to use this package.
+//
+// The Time returned by time.Now contains a monotonic clock reading.
+// If Time t has a monotonic clock reading, t.Add adds the same duration to
+// both the wall clock and monotonic clock readings to compute the result.
+// Because t.AddDate(y, m, d), t.Round(d), and t.Truncate(d) are wall time
+// computations, they always strip any monotonic clock reading from their results.
+// Because t.In, t.Local, and t.UTC are used for their effect on the interpretation
+// of the wall time, they also strip any monotonic clock reading from their results.
+// The canonical way to strip a monotonic clock reading is to use t = t.Round(0).
+//
+// If Times t and u both contain monotonic clock readings, the operations
+// t.After(u), t.Before(u), t.Equal(u), and t.Sub(u) are carried out
+// using the monotonic clock readings alone, ignoring the wall clock
+// readings. If either t or u contains no monotonic clock reading, these
+// operations fall back to using the wall clock readings.
+//
+// Because the monotonic clock reading has no meaning outside
+// the current process, the serialized forms generated by t.GobEncode,
+// t.MarshalBinary, t.MarshalJSON, and t.MarshalText omit the monotonic
+// clock reading, and t.Format provides no format for it. Similarly, the
+// constructors time.Date, time.Parse, time.ParseInLocation, and time.Unix,
+// as well as the unmarshalers t.GobDecode, t.UnmarshalBinary.
+// t.UnmarshalJSON, and t.UnmarshalText always create times with
+// no monotonic clock reading.
+//
+// Note that the Go == operator compares not just the time instant but
+// also the Location and the monotonic clock reading. See the
+// documentation for the Time type for a discussion of equality
+// testing for Time values.
+//
+// For debugging, the result of t.String does include the monotonic
+// clock reading if present. If t != u because of different monotonic clock readings,
+// that difference will be visible when printing t.String() and u.String().
+//
package time
import "errors"
@@ -14,8 +77,11 @@ import "errors"
//
// 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.
+// type time.Time, not *time.Time.
+//
+// A Time value can be used by multiple goroutines simultaneously except
+// that the methods GobDecode, UnmarshalBinary, UnmarshalJSON and
+// UnmarshalText are not concurrency-safe.
//
// Time instants can be compared using the Before, After, and Equal methods.
// The Sub method subtracts two instants, producing a Duration.
@@ -33,19 +99,34 @@ import "errors"
// computations described in earlier paragraphs.
//
// Note that the Go == operator compares not just the time instant but also the
-// Location. Therefore, Time values should not be used as map or database keys
-// without first guaranteeing that the identical Location has been set for all
-// values, which can be achieved through use of the UTC or Local method.
+// Location and the monotonic clock reading. Therefore, Time values should not
+// be used as map or database keys without first guaranteeing that the
+// identical Location has been set for all values, which can be achieved
+// through use of the UTC or Local method, and that the monotonic clock reading
+// has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u)
+// to t == u, since t.Equal uses the most accurate comparison available and
+// correctly handles the case when only one of its arguments has a monotonic
+// clock reading.
+//
+// In addition to the required “wall clock” reading, a Time may contain an optional
+// reading of the current process's monotonic clock, to provide additional precision
+// for comparison or subtraction.
+// See the “Monotonic Clocks” section in the package documentation for details.
//
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].
- nsec int32
+ // wall and ext encode the wall time seconds, wall time nanoseconds,
+ // and optional monotonic clock reading in nanoseconds.
+ //
+ // From high to low bit position, wall encodes a 1-bit flag (hasMonotonic),
+ // a 33-bit seconds field, and a 30-bit wall time nanoseconds field.
+ // The nanoseconds field is in the range [0, 999999999].
+ // If the hasMonotonic bit is 0, then the 33-bit field must be zero
+ // and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext.
+ // If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit
+ // unsigned wall seconds since Jan 1 year 1885, and ext holds a
+ // signed 64-bit monotonic clock reading, nanoseconds since process start.
+ wall uint64
+ ext int64
// loc specifies the Location that should be used to
// determine the minute, hour, month, day, and year
@@ -55,29 +136,124 @@ type Time struct {
loc *Location
}
+const (
+ hasMonotonic = 1 << 63
+ maxWall = wallToInternal + (1<<33 - 1) // year 2157
+ minWall = wallToInternal // year 1885
+ nsecMask = 1<<30 - 1
+ nsecShift = 30
+)
+
+// These helpers for manipulating the wall and monotonic clock readings
+// take pointer receivers, even when they don't modify the time,
+// to make them cheaper to call.
+
+// nsec returns the time's nanoseconds.
+func (t *Time) nsec() int32 {
+ return int32(t.wall & nsecMask)
+}
+
+// sec returns the time's seconds since Jan 1 year 1.
+func (t *Time) sec() int64 {
+ if t.wall&hasMonotonic != 0 {
+ return wallToInternal + int64(t.wall<<1>>(nsecShift+1))
+ }
+ return int64(t.ext)
+}
+
+// unixSec returns the time's seconds since Jan 1 1970 (Unix time).
+func (t *Time) unixSec() int64 { return t.sec() + internalToUnix }
+
+// addSec adds d seconds to the time.
+func (t *Time) addSec(d int64) {
+ if t.wall&hasMonotonic != 0 {
+ sec := int64(t.wall << 1 >> (nsecShift + 1))
+ dsec := sec + d
+ if 0 <= dsec && dsec <= 1<<33-1 {
+ t.wall = t.wall&nsecMask | uint64(dsec)<<nsecShift | hasMonotonic
+ return
+ }
+ // Wall second now out of range for packed field.
+ // Move to ext.
+ t.stripMono()
+ }
+
+ // TODO: Check for overflow.
+ t.ext += d
+}
+
+// setLoc sets the location associated with the time.
func (t *Time) setLoc(loc *Location) {
if loc == &utcLoc {
loc = nil
}
+ t.stripMono()
t.loc = loc
}
+// stripMono strips the monotonic clock reading in t.
+func (t *Time) stripMono() {
+ if t.wall&hasMonotonic != 0 {
+ t.ext = t.sec()
+ t.wall &= nsecMask
+ }
+}
+
+// setMono sets the monotonic clock reading in t.
+// If t cannot hold a monotonic clock reading,
+// because its wall time is too large,
+// setMono is a no-op.
+func (t *Time) setMono(m int64) {
+ if t.wall&hasMonotonic == 0 {
+ sec := int64(t.ext)
+ if sec < minWall || maxWall < sec {
+ return
+ }
+ t.wall |= hasMonotonic | uint64(sec-minWall)<<nsecShift
+ }
+ t.ext = m
+}
+
+// mono returns t's monotonic clock reading.
+// It returns 0 for a missing reading.
+// This function is used only for testing,
+// so it's OK that technically 0 is a valid
+// monotonic clock reading as well.
+func (t *Time) mono() int64 {
+ if t.wall&hasMonotonic == 0 {
+ return 0
+ }
+ return t.ext
+}
+
// 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
+ if t.wall&u.wall&hasMonotonic != 0 {
+ return t.ext > u.ext
+ }
+ ts := t.sec()
+ us := u.sec()
+ return ts > us || ts == us && 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
+ if t.wall&u.wall&hasMonotonic != 0 {
+ return t.ext < u.ext
+ }
+ 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.
-// Do not use == with Time values.
+// See the documentation on the Time type for the pitfalls of using == with
+// Time values; most code should use Equal instead.
func (t Time) Equal(u Time) bool {
- return t.sec == u.sec && t.nsec == u.nsec
+ if t.wall&u.wall&hasMonotonic != 0 {
+ return t.ext == u.ext
+ }
+ return t.sec() == u.sec() && t.nsec() == u.nsec()
}
// A Month specifies a month of the year (January = 1, ...).
@@ -162,7 +338,7 @@ func (d Weekday) String() string { return days[d] }
// 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
+// 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.
//
@@ -194,7 +370,7 @@ func (d Weekday) String() string { return days[d] }
// everywhere.
//
// The calendar runs on an exact 400 year cycle: a 400-year calendar
-// printed for 1970-2469 will apply as well to 2370-2769. Even the days
+// printed for 1970-2369 will apply as well to 2370-2769. 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
@@ -208,7 +384,7 @@ func (d Weekday) String() string { return days[d] }
//
// 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
+// 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.
//
@@ -219,9 +395,9 @@ func (d Weekday) String() string { return days[d] }
// 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
+// 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
+// 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.
@@ -245,12 +421,15 @@ const (
unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay
internalToUnix int64 = -unixToInternal
+
+ wallToInternal int64 = (1884*365 + 1884/4 - 1884/100 + 1884/400) * secondsPerDay
+ internalToWall int64 = -wallToInternal
)
// 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
+ return t.sec() == 0 && t.nsec() == 0
}
// abs returns the time t as an absolute time, adjusted by the zone offset.
@@ -261,7 +440,7 @@ func (t Time) abs() uint64 {
if l == nil || l == &localLoc {
l = l.get()
}
- sec := t.sec + internalToUnix
+ sec := t.unixSec()
if l != &utcLoc {
if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd {
sec += int64(l.cacheZone.offset)
@@ -281,7 +460,7 @@ func (t Time) locabs() (name string, offset int, abs uint64) {
l = l.get()
}
// Avoid function call if we hit the local time cache.
- sec := t.sec + internalToUnix
+ sec := t.unixSec()
if l != &utcLoc {
if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd {
name = l.cacheZone.name
@@ -425,7 +604,7 @@ func (t Time) Second() int {
// 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)
+ return int(t.nsec())
}
// YearDay returns the day of the year specified by t, in the range [1,365] for non-leap years,
@@ -543,8 +722,8 @@ func (d Duration) String() string {
}
// 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
+// 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.
@@ -616,18 +795,73 @@ func (d Duration) Hours() float64 {
return float64(hour) + float64(nsec)/(60*60*1e9)
}
+// Truncate returns the result of rounding d toward zero to a multiple of m.
+// If m <= 0, Truncate returns d unchanged.
+func (d Duration) Truncate(m Duration) Duration {
+ if m <= 0 {
+ return d
+ }
+ return d - d%m
+}
+
+// lessThanHalf reports whether x+x < y but avoids overflow,
+// assuming x and y are both positive (Duration is signed).
+func lessThanHalf(x, y Duration) bool {
+ return uint64(x)+uint64(x) < uint64(y)
+}
+
+// Round returns the result of rounding d to the nearest multiple of m.
+// The rounding behavior for halfway values is to round away from zero.
+// If the result exceeds the maximum (or minimum)
+// value that can be stored in a Duration,
+// Round returns the maximum (or minimum) duration.
+// If m <= 0, Round returns d unchanged.
+func (d Duration) Round(m Duration) Duration {
+ if m <= 0 {
+ return d
+ }
+ r := d % m
+ if d < 0 {
+ r = -r
+ if lessThanHalf(r, m) {
+ return d + r
+ }
+ if d1 := d - m + r; d1 < d {
+ return d1
+ }
+ return minDuration // overflow
+ }
+ if lessThanHalf(r, m) {
+ return d - r
+ }
+ if d1 := d + m - r; d1 > d {
+ return d1
+ }
+ return maxDuration // overflow
+}
+
// Add returns the time t+d.
func (t Time) Add(d Duration) Time {
- t.sec += int64(d / 1e9)
- nsec := t.nsec + int32(d%1e9)
+ dsec := int64(d / 1e9)
+ nsec := t.nsec() + int32(d%1e9)
if nsec >= 1e9 {
- t.sec++
+ dsec++
nsec -= 1e9
} else if nsec < 0 {
- t.sec--
+ dsec--
nsec += 1e9
}
- t.nsec = nsec
+ t.wall = t.wall&^nsecMask | uint64(nsec) // update nsec
+ t.addSec(dsec)
+ if t.wall&hasMonotonic != 0 {
+ te := t.ext + int64(d)
+ if d < 0 && te > int64(t.ext) || d > 0 && te < int64(t.ext) {
+ // Monotonic clock reading now out of range; degrade to wall-only.
+ t.stripMono()
+ } else {
+ t.ext = te
+ }
+ }
return t
}
@@ -636,7 +870,19 @@ func (t Time) Add(d Duration) Time {
// 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(t.nsec-u.nsec)
+ if t.wall&u.wall&hasMonotonic != 0 {
+ te := int64(t.ext)
+ ue := int64(u.ext)
+ d := Duration(te - ue)
+ if d < 0 && te > ue {
+ return maxDuration // t - u is positive out of range
+ }
+ if d > 0 && te < ue {
+ return minDuration // t - u is negative out of range
+ }
+ return d
+ }
+ d := Duration(t.sec()-u.sec())*Second + Duration(t.nsec()-u.nsec())
// Check for overflow or underflow.
switch {
case u.Add(d).Equal(t):
@@ -671,7 +917,7 @@ func Until(t Time) Duration {
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.Location())
+ return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec()), t.Location())
}
const (
@@ -718,7 +964,7 @@ func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) {
// 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
+ // day / 365 will be 4 instead of 3. Cut it back down to 3
// by subtracting n>>2.
n = d / 365
n -= n >> 2
@@ -791,12 +1037,20 @@ func daysIn(m Month, year int) int {
}
// Provided by package runtime.
-func now() (sec int64, nsec int32)
+func now() (sec int64, nsec int32, mono int64)
// Now returns the current local time.
func Now() Time {
- sec, nsec := now()
- return Time{sec + unixToInternal, nsec, Local}
+ sec, nsec, mono := now()
+ sec += unixToInternal - minWall
+ if uint64(sec)>>33 != 0 {
+ return Time{uint64(nsec), sec + minWall, Local}
+ }
+ return Time{hasMonotonic | uint64(sec)<<nsecShift | uint64(nsec), mono, Local}
+}
+
+func unixTime(sec int64, nsec int32) Time {
+ return Time{uint64(nsec), sec + unixToInternal, Local}
}
// UTC returns t with the location set to UTC.
@@ -834,14 +1088,14 @@ func (t Time) Location() *Location {
// 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)
+ name, offset, _, _, _ = t.loc.lookup(t.unixSec())
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
+ return t.unixSec()
}
// UnixNano returns t as a Unix time, the number of nanoseconds elapsed
@@ -850,7 +1104,7 @@ func (t Time) Unix() int64 {
// 1678 or after 2262). 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)
+ return (t.unixSec())*1e9 + int64(t.nsec())
}
const timeBinaryVersion byte = 1
@@ -873,20 +1127,22 @@ func (t Time) MarshalBinary() ([]byte, error) {
offsetMin = int16(offset)
}
+ sec := t.sec()
+ nsec := t.nsec()
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(sec >> 56), // bytes 1-8: seconds
+ byte(sec >> 48),
+ byte(sec >> 40),
+ byte(sec >> 32),
+ byte(sec >> 24),
+ byte(sec >> 16),
+ byte(sec >> 8),
+ byte(sec),
+ byte(nsec >> 24), // bytes 9-12: nanoseconds
+ byte(nsec >> 16),
+ byte(nsec >> 8),
+ byte(nsec),
byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes
byte(offsetMin),
}
@@ -910,18 +1166,22 @@ func (t *Time) UnmarshalBinary(data []byte) error {
}
buf = buf[1:]
- t.sec = int64(buf[7]) | int64(buf[6])<<8 | int64(buf[5])<<16 | int64(buf[4])<<24 |
+ 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 = int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24
+ nsec := 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
+ *t = Time{}
+ t.wall = uint64(nsec)
+ t.ext = sec
+
if offset == -1*60 {
t.setLoc(&utcLoc)
- } else if _, localoff, _, _, _ := Local.lookup(t.sec + internalToUnix); offset == localoff {
+ } else if _, localoff, _, _, _ := Local.lookup(t.unixSec()); offset == localoff {
t.setLoc(Local)
} else {
t.setLoc(FixedZone("", offset))
@@ -1008,7 +1268,7 @@ func Unix(sec int64, nsec int64) Time {
sec--
}
}
- return Time{sec + unixToInternal, int32(nsec), Local}
+ return unixTime(sec, int32(nsec))
}
func isLeap(year int) bool {
@@ -1117,7 +1377,7 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T
unix -= int64(offset)
}
- t := Time{unix + unixToInternal, int32(nsec), nil}
+ t := unixTime(unix, int32(nsec))
t.setLoc(loc)
return t
}
@@ -1130,6 +1390,7 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T
// time. Thus, Truncate(Hour) may return a time with a non-zero
// minute, depending on the time's Location.
func (t Time) Truncate(d Duration) Time {
+ t.stripMono()
if d <= 0 {
return t
}
@@ -1146,11 +1407,12 @@ func (t Time) Truncate(d Duration) Time {
// time. Thus, Round(Hour) may return a time with a non-zero
// minute, depending on the time's Location.
func (t Time) Round(d Duration) Time {
+ t.stripMono()
if d <= 0 {
return t
}
_, r := div(t, d)
- if r+r < d {
+ if lessThanHalf(r, d) {
return t.Add(-r)
}
return t.Add(d - r)
@@ -1161,15 +1423,16 @@ func (t Time) Round(d Duration) Time {
// but it's still here in case we change our minds.
func div(t Time, d Duration) (qmod2 int, r Duration) {
neg := false
- nsec := t.nsec
- if t.sec < 0 {
+ nsec := t.nsec()
+ sec := t.sec()
+ if sec < 0 {
// Operate on absolute value.
neg = true
- t.sec = -t.sec
+ sec = -sec
nsec = -nsec
if nsec < 0 {
nsec += 1e9
- t.sec-- // t.sec >= 1 before the -- so safe
+ sec-- // sec >= 1 before the -- so safe
}
}
@@ -1182,8 +1445,8 @@ func div(t Time, d Duration) (qmod2 int, r Duration) {
// 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)
+ qmod2 = int(sec/d1) & 1
+ r = Duration(sec%d1)*Second + Duration(nsec)
// General case.
// This could be faster if more cleverness were applied,
@@ -1191,7 +1454,7 @@ func div(t Time, d Duration) (qmod2 int, r Duration) {
// No one will care about these cases.
default:
// Compute nanoseconds as 128-bit number.
- sec := uint64(t.sec)
+ sec := uint64(sec)
tmp := (sec >> 32) * 1e9
u1 := tmp >> 32
u0 := tmp << 32
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index 2922560..dba8e0d 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -11,7 +11,9 @@ import (
"fmt"
"math/big"
"math/rand"
+ "os"
"runtime"
+ "strings"
"testing"
"testing/quick"
. "time"
@@ -231,6 +233,7 @@ var truncateRoundTests = []struct {
{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},
+ {Unix(-19012425939, 649146258), 7435029458905025217}, // 5.8*d rounds to 6*d, but .8*d+.8*d < 0 < d
}
func TestTruncateRound(t *testing.T) {
@@ -1056,6 +1059,66 @@ func TestDurationHours(t *testing.T) {
}
}
+var durationTruncateTests = []struct {
+ d Duration
+ m Duration
+ want Duration
+}{
+ {0, Second, 0},
+ {Minute, -7 * Second, Minute},
+ {Minute, 0, Minute},
+ {Minute, 1, Minute},
+ {Minute + 10*Second, 10 * Second, Minute + 10*Second},
+ {2*Minute + 10*Second, Minute, 2 * Minute},
+ {10*Minute + 10*Second, 3 * Minute, 9 * Minute},
+ {Minute + 10*Second, Minute + 10*Second + 1, 0},
+ {Minute + 10*Second, Hour, 0},
+ {-Minute, Second, -Minute},
+ {-10 * Minute, 3 * Minute, -9 * Minute},
+ {-10 * Minute, Hour, 0},
+}
+
+func TestDurationTruncate(t *testing.T) {
+ for _, tt := range durationTruncateTests {
+ if got := tt.d.Truncate(tt.m); got != tt.want {
+ t.Errorf("Duration(%s).Truncate(%s) = %s; want: %s", tt.d, tt.m, got, tt.want)
+ }
+ }
+}
+
+var durationRoundTests = []struct {
+ d Duration
+ m Duration
+ want Duration
+}{
+ {0, Second, 0},
+ {Minute, -11 * Second, Minute},
+ {Minute, 0, Minute},
+ {Minute, 1, Minute},
+ {2 * Minute, Minute, 2 * Minute},
+ {2*Minute + 10*Second, Minute, 2 * Minute},
+ {2*Minute + 30*Second, Minute, 3 * Minute},
+ {2*Minute + 50*Second, Minute, 3 * Minute},
+ {-Minute, 1, -Minute},
+ {-2 * Minute, Minute, -2 * Minute},
+ {-2*Minute - 10*Second, Minute, -2 * Minute},
+ {-2*Minute - 30*Second, Minute, -3 * Minute},
+ {-2*Minute - 50*Second, Minute, -3 * Minute},
+ {8e18, 3e18, 9e18},
+ {9e18, 5e18, 1<<63 - 1},
+ {-8e18, 3e18, -9e18},
+ {-9e18, 5e18, -1 << 63},
+ {3<<61 - 1, 3 << 61, 3 << 61},
+}
+
+func TestDurationRound(t *testing.T) {
+ for _, tt := range durationRoundTests {
+ if got := tt.d.Round(tt.m); got != tt.want {
+ t.Errorf("Duration(%s).Round(%s) = %s; want: %s", tt.d, tt.m, got, tt.want)
+ }
+ }
+}
+
var defaultLocTests = []struct {
name string
f func(t1, t2 Time) bool
@@ -1254,3 +1317,14 @@ func TestZeroMonthString(t *testing.T) {
t.Errorf("zero month = %q; want %q", got, want)
}
}
+
+func TestReadFileLimit(t *testing.T) {
+ const zero = "/dev/zero"
+ if _, err := os.Stat(zero); err != nil {
+ t.Skip("skipping test without a /dev/zero")
+ }
+ _, err := ReadFile(zero)
+ if err == nil || !strings.Contains(err.Error(), "is too large") {
+ t.Errorf("readFile(%q) error = %v; want error containing 'is too large'", zero, err)
+ }
+}
diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go
index fb0aa39..f4d4df9 100644
--- a/libgo/go/time/zoneinfo.go
+++ b/libgo/go/time/zoneinfo.go
@@ -5,6 +5,7 @@
package time
import (
+ "errors"
"sync"
"syscall"
)
@@ -81,7 +82,7 @@ func (l *Location) get() *Location {
}
// String returns a descriptive name for the time zone information,
-// corresponding to the argument to LoadLocation.
+// corresponding to the name argument to LoadLocation or FixedZone.
func (l *Location) String() string {
return l.get().name
}
@@ -256,7 +257,10 @@ func (l *Location) lookupName(name string, unix int64) (offset int, isDST bool,
// 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")
+var errLocation = errors.New("time: invalid location name")
+
+var zoneinfo *string
+var zoneinfoOnce sync.Once
// LoadLocation returns the Location with the given name.
//
@@ -279,11 +283,33 @@ func LoadLocation(name string) (*Location, error) {
if name == "Local" {
return Local, nil
}
- if zoneinfo != "" {
- if z, err := loadZoneFile(zoneinfo, name); err == nil {
+ if containsDotDot(name) || name[0] == '/' || name[0] == '\\' {
+ // No valid IANA Time Zone name contains a single dot,
+ // much less dot dot. Likewise, none begin with a slash.
+ return nil, errLocation
+ }
+ zoneinfoOnce.Do(func() {
+ env, _ := syscall.Getenv("ZONEINFO")
+ zoneinfo = &env
+ })
+ if zoneinfo != nil && *zoneinfo != "" {
+ if z, err := loadZoneFile(*zoneinfo, name); err == nil {
z.name = name
return z, nil
}
}
return loadLocation(name)
}
+
+// containsDotDot reports whether s contains "..".
+func containsDotDot(s string) bool {
+ if len(s) < 2 {
+ return false
+ }
+ for i := 0; i < len(s)-1; i++ {
+ if s[i] == '.' && s[i+1] == '.' {
+ return true
+ }
+ }
+ return false
+}
diff --git a/libgo/go/time/zoneinfo_abbrs_windows.go b/libgo/go/time/zoneinfo_abbrs_windows.go
index 9425db8..db0bbfd 100644
--- a/libgo/go/time/zoneinfo_abbrs_windows.go
+++ b/libgo/go/time/zoneinfo_abbrs_windows.go
@@ -2,8 +2,8 @@
// 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
+// Code generated by genzabbrs.go; DO NOT EDIT.
+// Based on information from http://unicode.org/cldr/data/common/supplemental/windowsZones.xml
package time
@@ -22,124 +22,128 @@ var abbrs = map[string]abbr{
"Namibia Standard Time": {"WAT", "WAST"}, // Africa/Windhoek
"Aleutian Standard Time": {"HST", "HDT"}, // America/Adak
"Alaskan Standard Time": {"AKST", "AKDT"}, // America/Anchorage
- "Tocantins Standard Time": {"BRT", "BRT"}, // America/Araguaina
- "Paraguay Standard Time": {"PYT", "PYST"}, // America/Asuncion
- "Bahia Standard Time": {"BRT", "BRT"}, // America/Bahia
- "SA Pacific Standard Time": {"COT", "COT"}, // America/Bogota
- "Argentina Standard Time": {"ART", "ART"}, // America/Buenos_Aires
+ "Tocantins Standard Time": {"-03", "-03"}, // America/Araguaina
+ "Paraguay Standard Time": {"-04", "-03"}, // America/Asuncion
+ "Bahia Standard Time": {"-03", "-03"}, // America/Bahia
+ "SA Pacific Standard Time": {"-05", "-05"}, // America/Bogota
+ "Argentina Standard Time": {"-03", "-03"}, // America/Buenos_Aires
"Eastern Standard Time (Mexico)": {"EST", "EST"}, // America/Cancun
- "Venezuela Standard Time": {"VET", "VET"}, // America/Caracas
- "SA Eastern Standard Time": {"GFT", "GFT"}, // America/Cayenne
+ "Venezuela Standard Time": {"-04", "-04"}, // America/Caracas
+ "SA Eastern Standard Time": {"-03", "-03"}, // 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
+ "Central Brazilian Standard Time": {"-04", "-03"}, // America/Cuiaba
"Mountain Standard Time": {"MST", "MDT"}, // America/Denver
- "Greenland Standard Time": {"WGT", "WGST"}, // America/Godthab
+ "Greenland Standard Time": {"-03", "-02"}, // America/Godthab
"Turks And Caicos Standard Time": {"AST", "AST"}, // America/Grand_Turk
"Central America Standard Time": {"CST", "CST"}, // America/Guatemala
"Atlantic Standard Time": {"AST", "ADT"}, // America/Halifax
"Cuba Standard Time": {"CST", "CDT"}, // America/Havana
"US Eastern Standard Time": {"EST", "EDT"}, // America/Indianapolis
- "SA Western Standard Time": {"BOT", "BOT"}, // America/La_Paz
+ "SA Western Standard Time": {"-04", "-04"}, // America/La_Paz
"Pacific Standard Time": {"PST", "PDT"}, // America/Los_Angeles
"Central Standard Time (Mexico)": {"CST", "CDT"}, // America/Mexico_City
- "Saint Pierre Standard Time": {"PMST", "PMDT"}, // America/Miquelon
- "Montevideo Standard Time": {"UYT", "UYT"}, // America/Montevideo
+ "Saint Pierre Standard Time": {"-03", "-02"}, // America/Miquelon
+ "Montevideo Standard Time": {"-03", "-03"}, // America/Montevideo
"Eastern Standard Time": {"EST", "EDT"}, // America/New_York
"US Mountain Standard Time": {"MST", "MST"}, // America/Phoenix
- "Haiti Standard Time": {"EST", "EST"}, // America/Port-au-Prince
+ "Haiti Standard Time": {"EST", "EDT"}, // America/Port-au-Prince
+ "Magallanes Standard Time": {"-03", "-03"}, // America/Punta_Arenas
"Canada Central Standard Time": {"CST", "CST"}, // America/Regina
- "Pacific SA Standard Time": {"CLT", "CLST"}, // America/Santiago
- "E. South America Standard Time": {"BRT", "BRST"}, // America/Sao_Paulo
+ "Pacific SA Standard Time": {"-04", "-03"}, // America/Santiago
+ "E. South America Standard Time": {"-03", "-02"}, // America/Sao_Paulo
"Newfoundland Standard Time": {"NST", "NDT"}, // America/St_Johns
"Pacific Standard Time (Mexico)": {"PST", "PDT"}, // America/Tijuana
"Central Asia Standard Time": {"+06", "+06"}, // Asia/Almaty
"Jordan Standard Time": {"EET", "EEST"}, // Asia/Amman
- "Arabic Standard Time": {"AST", "AST"}, // Asia/Baghdad
- "Azerbaijan Standard Time": {"AZT", "AZT"}, // Asia/Baku
- "SE Asia Standard Time": {"ICT", "ICT"}, // Asia/Bangkok
- "Altai Standard Time": {"+06", "+07"}, // Asia/Barnaul
+ "Arabic Standard Time": {"+03", "+03"}, // Asia/Baghdad
+ "Azerbaijan Standard Time": {"+04", "+04"}, // Asia/Baku
+ "SE Asia Standard Time": {"+07", "+07"}, // Asia/Bangkok
+ "Altai Standard Time": {"+07", "+07"}, // Asia/Barnaul
"Middle East Standard Time": {"EET", "EEST"}, // Asia/Beirut
"India Standard Time": {"IST", "IST"}, // Asia/Calcutta
- "Transbaikal Standard Time": {"IRKT", "YAKT"}, // Asia/Chita
- "Sri Lanka Standard Time": {"IST", "IST"}, // Asia/Colombo
+ "Transbaikal Standard Time": {"+09", "+09"}, // Asia/Chita
+ "Sri Lanka Standard Time": {"+0530", "+0530"}, // Asia/Colombo
"Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus
- "Bangladesh Standard Time": {"BDT", "BDT"}, // Asia/Dhaka
- "Arabian Standard Time": {"GST", "GST"}, // Asia/Dubai
+ "Bangladesh Standard Time": {"+06", "+06"}, // Asia/Dhaka
+ "Arabian Standard Time": {"+04", "+04"}, // Asia/Dubai
"West Bank Standard Time": {"EET", "EEST"}, // Asia/Hebron
- "W. Mongolia Standard Time": {"HOVT", "HOVST"}, // Asia/Hovd
- "North Asia East Standard Time": {"IRKT", "IRKT"}, // Asia/Irkutsk
+ "W. Mongolia Standard Time": {"+07", "+07"}, // Asia/Hovd
+ "North Asia East Standard Time": {"+08", "+08"}, // Asia/Irkutsk
"Israel Standard Time": {"IST", "IDT"}, // Asia/Jerusalem
- "Afghanistan Standard Time": {"AFT", "AFT"}, // Asia/Kabul
- "Russia Time Zone 11": {"PETT", "PETT"}, // Asia/Kamchatka
+ "Afghanistan Standard Time": {"+0430", "+0430"}, // Asia/Kabul
+ "Russia Time Zone 11": {"+12", "+12"}, // Asia/Kamchatka
"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
- "N. Central Asia Standard Time": {"+06", "+07"}, // Asia/Novosibirsk
+ "Nepal Standard Time": {"+0545", "+0545"}, // Asia/Katmandu
+ "North Asia Standard Time": {"+07", "+07"}, // Asia/Krasnoyarsk
+ "Magadan Standard Time": {"+11", "+11"}, // Asia/Magadan
+ "N. Central Asia Standard Time": {"+07", "+07"}, // Asia/Novosibirsk
+ "Omsk Standard Time": {"+06", "+06"}, // Asia/Omsk
"North Korea Standard Time": {"KST", "KST"}, // Asia/Pyongyang
- "Myanmar Standard Time": {"MMT", "MMT"}, // Asia/Rangoon
- "Arab Standard Time": {"AST", "AST"}, // Asia/Riyadh
- "Sakhalin Standard Time": {"SAKT", "SAKT"}, // Asia/Sakhalin
+ "Myanmar Standard Time": {"+0630", "+0630"}, // Asia/Rangoon
+ "Arab Standard Time": {"+03", "+03"}, // Asia/Riyadh
+ "Sakhalin Standard Time": {"+11", "+11"}, // Asia/Sakhalin
"Korea Standard Time": {"KST", "KST"}, // Asia/Seoul
"China Standard Time": {"CST", "CST"}, // Asia/Shanghai
- "Singapore Standard Time": {"SGT", "SGT"}, // Asia/Singapore
- "Russia Time Zone 10": {"SRET", "SRET"}, // Asia/Srednekolymsk
+ "Singapore Standard Time": {"+08", "+08"}, // Asia/Singapore
+ "Russia Time Zone 10": {"+11", "+11"}, // Asia/Srednekolymsk
"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
+ "West Asia Standard Time": {"+05", "+05"}, // Asia/Tashkent
+ "Georgian Standard Time": {"+04", "+04"}, // Asia/Tbilisi
+ "Iran Standard Time": {"+0330", "+0430"}, // Asia/Tehran
"Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo
- "Tomsk Standard Time": {"+06", "+07"}, // Asia/Tomsk
- "Ulaanbaatar Standard Time": {"ULAT", "ULAST"}, // 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
+ "Tomsk Standard Time": {"+07", "+07"}, // Asia/Tomsk
+ "Ulaanbaatar Standard Time": {"+08", "+08"}, // Asia/Ulaanbaatar
+ "Vladivostok Standard Time": {"+10", "+10"}, // Asia/Vladivostok
+ "Yakutsk Standard Time": {"+09", "+09"}, // Asia/Yakutsk
+ "Ekaterinburg Standard Time": {"+05", "+05"}, // Asia/Yekaterinburg
+ "Caucasus Standard Time": {"+04", "+04"}, // Asia/Yerevan
+ "Azores Standard Time": {"-01", "+00"}, // Atlantic/Azores
+ "Cape Verde Standard Time": {"-01", "-01"}, // Atlantic/Cape_Verde
"Greenwich Standard Time": {"GMT", "GMT"}, // Atlantic/Reykjavik
"Cen. Australia Standard Time": {"ACST", "ACDT"}, // Australia/Adelaide
"E. Australia Standard Time": {"AEST", "AEST"}, // Australia/Brisbane
"AUS Central Standard Time": {"ACST", "ACST"}, // Australia/Darwin
- "Aus Central W. Standard Time": {"ACWST", "ACWST"}, // Australia/Eucla
+ "Aus Central W. Standard Time": {"+0845", "+0845"}, // Australia/Eucla
"Tasmania Standard Time": {"AEST", "AEDT"}, // Australia/Hobart
- "Lord Howe Standard Time": {"LHST", "LHDT"}, // Australia/Lord_Howe
+ "Lord Howe Standard Time": {"+1030", "+11"}, // Australia/Lord_Howe
"W. Australia Standard Time": {"AWST", "AWST"}, // Australia/Perth
"AUS Eastern Standard Time": {"AEST", "AEDT"}, // 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-08": {"GMT+8", "GMT+8"}, // Etc/GMT+8
- "UTC-09": {"GMT+9", "GMT+9"}, // Etc/GMT+9
- "UTC+12": {"GMT-12", "GMT-12"}, // Etc/GMT-12
- "Astrakhan Standard Time": {"+03", "+04"}, // Europe/Astrakhan
- "W. Europe Standard Time": {"CET", "CEST"}, // Europe/Berlin
- "GTB Standard Time": {"EET", "EEST"}, // Europe/Bucharest
- "Central Europe Standard Time": {"CET", "CEST"}, // Europe/Budapest
- "E. Europe Standard Time": {"EET", "EEST"}, // Europe/Chisinau
- "Turkey Standard Time": {"EET", "EEST"}, // Europe/Istanbul
- "Kaliningrad Standard Time": {"EET", "EET"}, // Europe/Kaliningrad
- "FLE Standard Time": {"EET", "EEST"}, // Europe/Kiev
- "GMT Standard Time": {"GMT", "BST"}, // Europe/London
- "Belarus Standard Time": {"MSK", "MSK"}, // Europe/Minsk
- "Russian Standard Time": {"MSK", "MSK"}, // Europe/Moscow
- "Romance Standard Time": {"CET", "CEST"}, // Europe/Paris
- "Russia Time Zone 3": {"SAMT", "SAMT"}, // Europe/Samara
- "Central European Standard Time": {"CET", "CEST"}, // Europe/Warsaw
- "Mauritius Standard Time": {"MUT", "MUT"}, // Indian/Mauritius
- "Samoa Standard Time": {"WSST", "WSDT"}, // Pacific/Apia
- "New Zealand Standard Time": {"NZST", "NZDT"}, // Pacific/Auckland
- "Bougainville Standard Time": {"BST", "BST"}, // Pacific/Bougainville
- "Chatham Islands Standard Time": {"CHAST", "CHADT"}, // Pacific/Chatham
- "Easter Island Standard Time": {"EAST", "EASST"}, // Pacific/Easter
- "Fiji Standard Time": {"FJT", "FJST"}, // Pacific/Fiji
- "Central Pacific Standard Time": {"SBT", "SBT"}, // Pacific/Guadalcanal
- "Hawaiian Standard Time": {"HST", "HST"}, // Pacific/Honolulu
- "Line Islands Standard Time": {"LINT", "LINT"}, // Pacific/Kiritimati
- "Marquesas Standard Time": {"MART", "MART"}, // Pacific/Marquesas
- "Norfolk Standard Time": {"NFT", "NFT"}, // Pacific/Norfolk
- "West Pacific Standard Time": {"PGT", "PGT"}, // Pacific/Port_Moresby
- "Tonga Standard Time": {"TOT", "TOT"}, // Pacific/Tongatapu
+ "UTC": {"GMT", "GMT"}, // Etc/GMT
+ "UTC-11": {"-11", "-11"}, // Etc/GMT+11
+ "Dateline Standard Time": {"-12", "-12"}, // Etc/GMT+12
+ "UTC-02": {"-02", "-02"}, // Etc/GMT+2
+ "UTC-08": {"-08", "-08"}, // Etc/GMT+8
+ "UTC-09": {"-09", "-09"}, // Etc/GMT+9
+ "UTC+12": {"+12", "+12"}, // Etc/GMT-12
+ "UTC+13": {"+13", "+13"}, // Etc/GMT-13
+ "Astrakhan Standard Time": {"+04", "+04"}, // Europe/Astrakhan
+ "W. Europe Standard Time": {"CET", "CEST"}, // Europe/Berlin
+ "GTB Standard Time": {"EET", "EEST"}, // Europe/Bucharest
+ "Central Europe Standard Time": {"CET", "CEST"}, // Europe/Budapest
+ "E. Europe Standard Time": {"EET", "EEST"}, // Europe/Chisinau
+ "Turkey Standard Time": {"+03", "+03"}, // Europe/Istanbul
+ "Kaliningrad Standard Time": {"EET", "EET"}, // Europe/Kaliningrad
+ "FLE Standard Time": {"EET", "EEST"}, // Europe/Kiev
+ "GMT Standard Time": {"GMT", "BST"}, // Europe/London
+ "Belarus Standard Time": {"+03", "+03"}, // Europe/Minsk
+ "Russian Standard Time": {"MSK", "MSK"}, // Europe/Moscow
+ "Romance Standard Time": {"CET", "CEST"}, // Europe/Paris
+ "Russia Time Zone 3": {"+04", "+04"}, // Europe/Samara
+ "Saratov Standard Time": {"+03", "+04"}, // Europe/Saratov
+ "Central European Standard Time": {"CET", "CEST"}, // Europe/Warsaw
+ "Mauritius Standard Time": {"+04", "+04"}, // Indian/Mauritius
+ "Samoa Standard Time": {"+13", "+14"}, // Pacific/Apia
+ "New Zealand Standard Time": {"NZST", "NZDT"}, // Pacific/Auckland
+ "Bougainville Standard Time": {"+11", "+11"}, // Pacific/Bougainville
+ "Chatham Islands Standard Time": {"+1245", "+1345"}, // Pacific/Chatham
+ "Easter Island Standard Time": {"-06", "-05"}, // Pacific/Easter
+ "Fiji Standard Time": {"+12", "+13"}, // Pacific/Fiji
+ "Central Pacific Standard Time": {"+11", "+11"}, // Pacific/Guadalcanal
+ "Hawaiian Standard Time": {"HST", "HST"}, // Pacific/Honolulu
+ "Line Islands Standard Time": {"+14", "+14"}, // Pacific/Kiritimati
+ "Marquesas Standard Time": {"-0930", "-0930"}, // Pacific/Marquesas
+ "Norfolk Standard Time": {"+11", "+11"}, // Pacific/Norfolk
+ "West Pacific Standard Time": {"+10", "+10"}, // Pacific/Port_Moresby
+ "Tonga Standard Time": {"+13", "+14"}, // Pacific/Tongatapu
}
diff --git a/libgo/go/time/zoneinfo_plan9.go b/libgo/go/time/zoneinfo_plan9.go
index 0694f0a..26637a1 100644
--- a/libgo/go/time/zoneinfo_plan9.go
+++ b/libgo/go/time/zoneinfo_plan9.go
@@ -95,7 +95,7 @@ func loadZoneDataPlan9(s string) (l *Location, err error) {
// Fill in the cache with information about right now,
// since that will be the most common lookup.
- sec, _ := now()
+ 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
diff --git a/libgo/go/time/zoneinfo_read.go b/libgo/go/time/zoneinfo_read.go
index 19cd40d..b0cd9da 100644
--- a/libgo/go/time/zoneinfo_read.go
+++ b/libgo/go/time/zoneinfo_read.go
@@ -11,6 +11,17 @@ package time
import "errors"
+// maxFileSize is the max permitted size of files read by readFile.
+// As reference, the zoneinfo.zip distributed by Go is ~350 KB,
+// so 10MB is overkill.
+const maxFileSize = 10 << 20
+
+type fileSizeError string
+
+func (f fileSizeError) Error() string {
+ return "time: file " + string(f) + " is too large"
+}
+
// Copies of io.Seek* constants to avoid importing "io":
const (
seekStart = 0
@@ -188,7 +199,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
// Fill in the cache with information about right now,
// since that will be the most common lookup.
- sec, _ := now()
+ 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
diff --git a/libgo/go/time/zoneinfo_test.go b/libgo/go/time/zoneinfo_test.go
index 5b6a4dc..8a4caa0 100644
--- a/libgo/go/time/zoneinfo_test.go
+++ b/libgo/go/time/zoneinfo_test.go
@@ -5,10 +5,56 @@
package time_test
import (
+ "fmt"
+ "os"
"testing"
"time"
)
+func init() {
+ if time.ZoneinfoForTesting() != nil {
+ panic(fmt.Errorf("zoneinfo initialized before first LoadLocation"))
+ }
+}
+
+func TestEnvVarUsage(t *testing.T) {
+ time.ResetZoneinfoForTesting()
+
+ const testZoneinfo = "foo.zip"
+ const env = "ZONEINFO"
+
+ defer os.Setenv(env, os.Getenv(env))
+ os.Setenv(env, testZoneinfo)
+
+ // Result isn't important, we're testing the side effect of this command
+ time.LoadLocation("Asia/Jerusalem")
+ defer time.ResetZoneinfoForTesting()
+
+ if zoneinfo := time.ZoneinfoForTesting(); testZoneinfo != *zoneinfo {
+ t.Errorf("zoneinfo does not match env variable: got %q want %q", zoneinfo, testZoneinfo)
+ }
+}
+
+func TestLoadLocationValidatesNames(t *testing.T) {
+ time.ResetZoneinfoForTesting()
+ const env = "ZONEINFO"
+ defer os.Setenv(env, os.Getenv(env))
+ os.Setenv(env, "")
+
+ bad := []string{
+ "/usr/foo/Foo",
+ "\\UNC\foo",
+ "..",
+ "a..",
+ }
+ for _, v := range bad {
+ _, err := time.LoadLocation(v)
+ if err != time.ErrLocation {
+ t.Errorf("LoadLocation(%q) error = %v; want ErrLocation", v, err)
+ }
+ }
+}
+
func TestVersion3(t *testing.T) {
t.Skip("gccgo does not use the zip file")
time.ForceZipFileForTesting(true)
@@ -44,8 +90,8 @@ func TestFirstZone(t *testing.T) {
{
"Pacific/Fakaofo",
1325242799,
- "Thu, 29 Dec 2011 23:59:59 -1100 (TKT)",
- "Sat, 31 Dec 2011 00:00:00 +1300 (TKT)",
+ "Thu, 29 Dec 2011 23:59:59 -1100 (-11)",
+ "Sat, 31 Dec 2011 00:00:00 +1300 (+13)",
},
}
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
index a6e227b..c201f4b 100644
--- a/libgo/go/time/zoneinfo_windows.go
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -132,7 +132,7 @@ func pseudoUnix(year int, d *syscall.Systemtime) int64 {
day -= 7
}
}
- return t.sec + int64(day-1)*secondsPerDay + internalToUnix
+ return t.sec() + int64(day-1)*secondsPerDay + internalToUnix
}
func initLocalFromTZI(i *syscall.Timezoneinformation) {