aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/time
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/time')
-rw-r--r--libgo/go/time/example_test.go15
-rw-r--r--libgo/go/time/format.go13
-rw-r--r--libgo/go/time/format_test.go21
-rw-r--r--libgo/go/time/sleep.go3
-rw-r--r--libgo/go/time/sleep_test.go4
-rw-r--r--libgo/go/time/time.go44
-rw-r--r--libgo/go/time/zoneinfo.go13
-rw-r--r--libgo/go/time/zoneinfo_android.go3
-rw-r--r--libgo/go/time/zoneinfo_js.go67
-rw-r--r--libgo/go/time/zoneinfo_read.go15
-rw-r--r--libgo/go/time/zoneinfo_test.go11
11 files changed, 181 insertions, 28 deletions
diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go
index 494a416..0fd325f 100644
--- a/libgo/go/time/example_test.go
+++ b/libgo/go/time/example_test.go
@@ -132,7 +132,7 @@ func ExampleAfter() {
select {
case m := <-c:
handle(m)
- case <-time.After(5 * time.Minute):
+ case <-time.After(10 * time.Second):
fmt.Println("timed out")
}
}
@@ -144,7 +144,7 @@ func ExampleSleep() {
func statusUpdate() string { return "" }
func ExampleTick() {
- c := time.Tick(1 * time.Minute)
+ c := time.Tick(5 * time.Second)
for now := range c {
fmt.Printf("%v %s\n", now, statusUpdate())
}
@@ -429,6 +429,17 @@ func ExampleTime_Truncate() {
// t.Truncate(10m0s) = 12:10:00
}
+func ExampleLoadLocation() {
+ location, err := time.LoadLocation("America/Los_Angeles")
+ if err != nil {
+ panic(err)
+ }
+
+ timeInUTC := time.Date(2018, 8, 30, 12, 0, 0, 0, time.UTC)
+ fmt.Println(timeInUTC.In(location))
+ // Output: 2018-08-30 05:00:00 -0700 PDT
+}
+
func ExampleLocation() {
// China doesn't have daylight saving. It uses a fixed 8 hour offset from UTC.
secondsEastOfUTC := int((8 * time.Hour).Seconds())
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
index 237f287..2adbbe0 100644
--- a/libgo/go/time/format.go
+++ b/libgo/go/time/format.go
@@ -1120,7 +1120,8 @@ func parseTimeZone(value string) (length int, ok bool) {
// Special Case 3: Some time zones are not named, but have +/-00 format
if value[0] == '+' || value[0] == '-' {
length = parseSignedOffset(value)
- return length, true
+ ok := length > 0 // parseSignedOffset returns 0 in case of bad input
+ return length, ok
}
// How many upper-case letters are there? Need at least three, at most five.
var nUpper int
@@ -1152,7 +1153,7 @@ func parseTimeZone(value string) (length int, ok bool) {
// parseGMT parses a GMT time zone. The input string is known to start "GMT".
// The function checks whether that is followed by a sign and a number in the
-// range -14 through 12 excluding zero.
+// range -23 through +23 excluding zero.
func parseGMT(value string) int {
value = value[3:]
if len(value) == 0 {
@@ -1163,7 +1164,7 @@ func parseGMT(value string) int {
}
// parseSignedOffset parses a signed timezone offset (e.g. "+03" or "-04").
-// The function checks for a signed number in the range -14 through +12 excluding zero.
+// The function checks for a signed number in the range -23 through +23 excluding zero.
// Returns length of the found offset string or 0 otherwise
func parseSignedOffset(value string) int {
sign := value[0]
@@ -1171,13 +1172,15 @@ func parseSignedOffset(value string) int {
return 0
}
x, rem, err := leadingInt(value[1:])
- if err != nil {
+
+ // fail if nothing consumed by leadingInt
+ if err != nil || value[1:] == rem {
return 0
}
if sign == '-' {
x = -x
}
- if x == 0 || x < -14 || 12 < x {
+ if x < -23 || 23 < x {
return 0
}
return len(value) - len(rem)
diff --git a/libgo/go/time/format_test.go b/libgo/go/time/format_test.go
index 72dd592..0b9f3f4 100644
--- a/libgo/go/time/format_test.go
+++ b/libgo/go/time/format_test.go
@@ -418,7 +418,11 @@ var parseTimeZoneTests = []ParseTimeZoneTest{
{"gmt hi there", 0, false},
{"GMT hi there", 3, true},
{"GMT+12 hi there", 6, true},
- {"GMT+00 hi there", 3, true}, // 0 or 00 is not a legal offset.
+ {"GMT+00 hi there", 6, true},
+ {"GMT+", 3, true},
+ {"GMT+3", 5, true},
+ {"GMT+a", 3, true},
+ {"GMT+3a", 5, true},
{"GMT-5 hi there", 5, true},
{"GMT-51 hi there", 3, true},
{"ChST hi there", 4, true},
@@ -429,8 +433,19 @@ var parseTimeZoneTests = []ParseTimeZoneTest{
{"ESASTT hi", 0, false}, // run of upper-case letters too long.
{"ESATY hi", 0, false}, // five letters must end in T.
{"WITA hi", 4, true}, // Issue #18251
- {"+03 hi", 3, true}, // Issue #24071
- {"-04 hi", 3, true}, // Issue #24071
+ // Issue #24071
+ {"+03 hi", 3, true},
+ {"-04 hi", 3, true},
+ // Issue #26032
+ {"+00", 3, true},
+ {"-11", 3, true},
+ {"-12", 3, true},
+ {"-23", 3, true},
+ {"-24", 0, false},
+ {"+13", 3, true},
+ {"+14", 3, true},
+ {"+23", 3, true},
+ {"+24", 0, false},
}
func TestParseTimeZone(t *testing.T) {
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go
index b8c81b4..10edf6f 100644
--- a/libgo/go/time/sleep.go
+++ b/libgo/go/time/sleep.go
@@ -8,9 +8,6 @@ package time
// A negative or zero duration causes Sleep to return immediately.
func Sleep(d Duration)
-// runtimeNano returns the current value of the runtime clock in nanoseconds.
-func runtimeNano() int64
-
// Interface to timers implemented in package runtime.
// Must be in sync with ../runtime/time.go:/^type timer
type runtimeTimer struct {
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
index e6a08fc..42df6d1 100644
--- a/libgo/go/time/sleep_test.go
+++ b/libgo/go/time/sleep_test.go
@@ -426,10 +426,6 @@ 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/time.go b/libgo/go/time/time.go
index 2374043..d0d780f 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -75,7 +75,10 @@
//
package time
-import "errors"
+import (
+ "errors"
+ _ "unsafe" // for go:linkname
+)
// A Time represents an instant in time with nanosecond precision.
//
@@ -102,6 +105,10 @@ import "errors"
// change the instant in time being denoted and therefore does not affect the
// computations described in earlier paragraphs.
//
+// Representations of a Time value saved by the GobEncode, MarshalBinary,
+// MarshalJSON, and MarshalText methods store the Time.Location's offset, but not
+// the location name. They therefore lose information about Daylight Saving Time.
+//
// 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.
@@ -908,13 +915,27 @@ func (t Time) Sub(u Time) Duration {
// Since returns the time elapsed since t.
// It is shorthand for time.Now().Sub(t).
func Since(t Time) Duration {
- return Now().Sub(t)
+ var now Time
+ if t.wall&hasMonotonic != 0 {
+ // Common case optimization: if t has monotomic time, then Sub will use only it.
+ now = Time{hasMonotonic, runtimeNano() - startNano, nil}
+ } else {
+ now = Now()
+ }
+ return now.Sub(t)
}
// Until returns the duration until t.
// It is shorthand for t.Sub(time.Now()).
func Until(t Time) Duration {
- return t.Sub(Now())
+ var now Time
+ if t.wall&hasMonotonic != 0 {
+ // Common case optimization: if t has monotomic time, then Sub will use only it.
+ now = Time{hasMonotonic, runtimeNano() - startNano, nil}
+ } else {
+ now = Now()
+ }
+ return t.Sub(now)
}
// AddDate returns the time corresponding to adding the
@@ -933,7 +954,7 @@ func (t Time) AddDate(years int, months int, days int) Time {
const (
secondsPerMinute = 60
- secondsPerHour = 60 * 60
+ secondsPerHour = 60 * secondsPerMinute
secondsPerDay = 24 * secondsPerHour
secondsPerWeek = 7 * secondsPerDay
daysPer400Years = 365*400 + 97
@@ -1050,9 +1071,22 @@ func daysIn(m Month, year int) int {
// Provided by package runtime.
func now() (sec int64, nsec int32, mono int64)
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+//go:linkname runtimeNano runtime.nanotime
+func runtimeNano() int64
+
+// Monotonic times are reported as offsets from startNano.
+// We initialize startNano to runtimeNano() - 1 so that on systems where
+// monotonic time resolution is fairly low (e.g. Windows 2008
+// which appears to have a default resolution of 15ms),
+// we avoid ever reporting a monotonic time of 0.
+// (Callers may want to use 0 as "time not set".)
+var startNano int64 = runtimeNano() - 1
+
// Now returns the current local time.
func Now() Time {
sec, nsec, mono := now()
+ mono -= startNano
sec += unixToInternal - minWall
if uint64(sec)>>33 != 0 {
return Time{uint64(nsec), sec + minWall, Local}
@@ -1076,7 +1110,7 @@ func (t Time) Local() Time {
return t
}
-// In returns a copy of t representating the same time instant, but
+// In returns a copy of t representing the same time instant, but
// with the copy's location information set to loc for display
// purposes.
//
diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go
index d2bc642..7dffbfa 100644
--- a/libgo/go/time/zoneinfo.go
+++ b/libgo/go/time/zoneinfo.go
@@ -205,7 +205,7 @@ func (l *Location) lookupFirstZone() int {
return 0
}
-// firstZoneUsed returns whether the first zone is used by some
+// firstZoneUsed reports whether the first zone is used by some
// transition.
func (l *Location) firstZoneUsed() bool {
for _, tx := range l.tx {
@@ -288,14 +288,23 @@ func LoadLocation(name string) (*Location, error) {
env, _ := syscall.Getenv("ZONEINFO")
zoneinfo = &env
})
+ var firstErr error
if *zoneinfo != "" {
if zoneData, err := loadTzinfoFromDirOrZip(*zoneinfo, name); err == nil {
if z, err := LoadLocationFromTZData(name, zoneData); err == nil {
return z, nil
}
+ firstErr = err
+ } else if err != syscall.ENOENT {
+ firstErr = err
}
}
- return loadLocation(name, zoneSources)
+ if z, err := loadLocation(name, zoneSources); err == nil {
+ return z, nil
+ } else if firstErr == nil {
+ firstErr = err
+ }
+ return nil, firstErr
}
// containsDotDot reports whether s contains "..".
diff --git a/libgo/go/time/zoneinfo_android.go b/libgo/go/time/zoneinfo_android.go
index 65e0975..237ff20 100644
--- a/libgo/go/time/zoneinfo_android.go
+++ b/libgo/go/time/zoneinfo_android.go
@@ -11,6 +11,7 @@ package time
import (
"errors"
"runtime"
+ "syscall"
)
var zoneSources = []string{
@@ -75,5 +76,5 @@ func androidLoadTzinfoFromTzdata(file, name string) ([]byte, error) {
}
return buf, nil
}
- return nil, errors.New("cannot find " + name + " in tzdata file " + file)
+ return nil, syscall.ENOENT
}
diff --git a/libgo/go/time/zoneinfo_js.go b/libgo/go/time/zoneinfo_js.go
new file mode 100644
index 0000000..2d76a57
--- /dev/null
+++ b/libgo/go/time/zoneinfo_js.go
@@ -0,0 +1,67 @@
+// Copyright 2018 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 js,wasm
+
+package time
+
+import (
+ "runtime"
+ "syscall/js"
+)
+
+var zoneSources = []string{
+ "/usr/share/zoneinfo/",
+ "/usr/share/lib/zoneinfo/",
+ "/usr/lib/locale/TZ/",
+ runtime.GOROOT() + "/lib/time/zoneinfo.zip",
+}
+
+func initLocal() {
+ localLoc.name = "Local"
+
+ z := zone{}
+ d := js.Global().Get("Date").New()
+ offset := d.Call("getTimezoneOffset").Int() * -1
+ z.offset = offset * 60
+ // According to https://tc39.github.io/ecma262/#sec-timezoneestring,
+ // the timezone name from (new Date()).toTimeString() is an implementation-dependent
+ // result, and in Google Chrome, it gives the fully expanded name rather than
+ // the abbreviation.
+ // Hence, we construct the name from the offset.
+ z.name = "UTC"
+ if offset < 0 {
+ z.name += "-"
+ offset *= -1
+ } else {
+ z.name += "+"
+ }
+ z.name += itoa(offset / 60)
+ min := offset % 60
+ if min != 0 {
+ z.name += ":" + itoa(min)
+ }
+ localLoc.zone = []zone{z}
+}
+
+// itoa is like strconv.Itoa but only works for values of i in range [0,99].
+// It panics if i is out of range.
+func itoa(i int) string {
+ if i < 10 {
+ return digits[i : i+1]
+ }
+ return smallsString[i*2 : i*2+2]
+}
+
+const smallsString = "00010203040506070809" +
+ "10111213141516171819" +
+ "20212223242526272829" +
+ "30313233343536373839" +
+ "40414243444546474849" +
+ "50515253545556575859" +
+ "60616263646566676869" +
+ "70717273747576777879" +
+ "80818283848586878889" +
+ "90919293949596979899"
+const digits = "0123456789"
diff --git a/libgo/go/time/zoneinfo_read.go b/libgo/go/time/zoneinfo_read.go
index 20f84f0..d8d4070 100644
--- a/libgo/go/time/zoneinfo_read.go
+++ b/libgo/go/time/zoneinfo_read.go
@@ -11,6 +11,7 @@ package time
import (
"errors"
+ "runtime"
"syscall"
)
@@ -55,7 +56,7 @@ func (d *dataIO) big4() (n uint32, ok bool) {
d.error = true
return 0, false
}
- return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
+ return uint32(p[3]) | uint32(p[2])<<8 | uint32(p[1])<<16 | uint32(p[0])<<24, true
}
func (d *dataIO) byte() (n byte, ok bool) {
@@ -172,6 +173,14 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
return nil, badData
}
zone[i].name = byteString(abbrev[b:])
+ if runtime.GOOS == "aix" && len(name) > 8 && (name[:8] == "Etc/GMT+" || name[:8] == "Etc/GMT-") {
+ // There is a bug with AIX 7.2 TL 0 with files in Etc,
+ // GMT+1 will return GMT-1 instead of GMT+1 or -01.
+ if name != "Etc/GMT+0" {
+ // GMT+0 is OK
+ zone[i].name = name[4:]
+ }
+ }
}
// Now the transition time info.
@@ -262,7 +271,7 @@ func get2(b []byte) int {
func loadTzinfoFromZip(zipfile, name string) ([]byte, error) {
fd, err := open(zipfile)
if err != nil {
- return nil, errors.New("open " + zipfile + ": " + err.Error())
+ return nil, err
}
defer closefd(fd)
@@ -364,7 +373,7 @@ func loadTzinfoFromZip(zipfile, name string) ([]byte, error) {
return buf, nil
}
- return nil, errors.New("cannot find " + name + " in zip file " + zipfile)
+ return nil, syscall.ENOENT
}
// loadTzinfoFromTzdata returns the time zone information of the time zone
diff --git a/libgo/go/time/zoneinfo_test.go b/libgo/go/time/zoneinfo_test.go
index 9bf8c4f..2f7612d 100644
--- a/libgo/go/time/zoneinfo_test.go
+++ b/libgo/go/time/zoneinfo_test.go
@@ -5,6 +5,7 @@
package time_test
import (
+ "errors"
"fmt"
"os"
"reflect"
@@ -36,6 +37,16 @@ func TestEnvVarUsage(t *testing.T) {
}
}
+func TestBadLocationErrMsg(t *testing.T) {
+ time.ResetZoneinfoForTesting()
+ loc := "Asia/SomethingNotExist"
+ want := errors.New("unknown time zone " + loc)
+ _, err := time.LoadLocation(loc)
+ if err.Error() != want.Error() {
+ t.Errorf("LoadLocation(%q) error = %v; want %v", loc, err, want)
+ }
+}
+
func TestLoadLocationValidatesNames(t *testing.T) {
time.ResetZoneinfoForTesting()
const env = "ZONEINFO"