summaryrefslogtreecommitdiff
path: root/libgo/go/time
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2017-01-14 00:05:42 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2017-01-14 00:05:42 +0000
commitccea2b367771831e9877ec31e0656d153818bf3f (patch)
treee183ae81a1f48a02945cb6de463a70c5be1b06f6 /libgo/go/time
parentfd961cec64a5807cd6375d5c4042bca4256c5fda (diff)
downloadgcc-ccea2b367771831e9877ec31e0656d153818bf3f.tar.gz
libgo: update to Go 1.8 release candidate 1
Compiler changes: * Change map assignment to use mapassign and assign value directly. * Change string iteration to use decoderune, faster for ASCII strings. * Change makeslice to take int, and use makeslice64 for larger values. * Add new noverflow field to hmap struct used for maps. Unresolved problems, to be fixed later: * Commented out test in go/types/sizes_test.go that doesn't compile. * Commented out reflect.TestStructOf test for padding after zero-sized field. Reviewed-on: https://go-review.googlesource.com/35231 gotools/: Updates for Go 1.8rc1. * Makefile.am (go_cmd_go_files): Add bug.go. (s-zdefaultcc): Write defaultPkgConfig. * Makefile.in: Rebuild. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@244456 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/time')
-rw-r--r--libgo/go/time/example_test.go18
-rw-r--r--libgo/go/time/export_android_test.go12
-rw-r--r--libgo/go/time/format.go62
-rw-r--r--libgo/go/time/format_test.go4
-rw-r--r--libgo/go/time/sleep.go28
-rw-r--r--libgo/go/time/time.go77
-rw-r--r--libgo/go/time/time_test.go139
-rw-r--r--libgo/go/time/zoneinfo.go2
-rw-r--r--libgo/go/time/zoneinfo_abbrs_windows.go183
-rw-r--r--libgo/go/time/zoneinfo_android.go119
-rw-r--r--libgo/go/time/zoneinfo_android_test.go18
-rw-r--r--libgo/go/time/zoneinfo_unix.go2
-rw-r--r--libgo/go/time/zoneinfo_windows.go2
13 files changed, 530 insertions, 136 deletions
diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go
index 4170d5110d0..7dc2bb5e7ee 100644
--- a/libgo/go/time/example_test.go
+++ b/libgo/go/time/example_test.go
@@ -251,20 +251,18 @@ func ExampleTime_Truncate() {
2 * time.Second,
time.Minute,
10 * time.Minute,
- time.Hour,
}
for _, d := range trunc {
- fmt.Printf("t.Truncate(%6s) = %s\n", d, t.Truncate(d).Format("15:04:05.999999999"))
+ fmt.Printf("t.Truncate(%5s) = %s\n", d, t.Truncate(d).Format("15:04:05.999999999"))
}
// Output:
- // t.Truncate( 1ns) = 12:15:30.918273645
- // t.Truncate( 1µs) = 12:15:30.918273
- // t.Truncate( 1ms) = 12:15:30.918
- // t.Truncate( 1s) = 12:15:30
- // t.Truncate( 2s) = 12:15:30
- // t.Truncate( 1m0s) = 12:15:00
- // t.Truncate( 10m0s) = 12:10:00
- // t.Truncate(1h0m0s) = 12:00:00
+ // t.Truncate( 1ns) = 12:15:30.918273645
+ // t.Truncate( 1µs) = 12:15:30.918273
+ // t.Truncate( 1ms) = 12:15:30.918
+ // t.Truncate( 1s) = 12:15:30
+ // t.Truncate( 2s) = 12:15:30
+ // t.Truncate( 1m0s) = 12:15:00
+ // t.Truncate(10m0s) = 12:10:00
}
diff --git a/libgo/go/time/export_android_test.go b/libgo/go/time/export_android_test.go
new file mode 100644
index 00000000000..fa6a058a73b
--- /dev/null
+++ b/libgo/go/time/export_android_test.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+func ForceAndroidTzdataForTest(tzdata bool) {
+ tzdataPaths = origTzdataPaths
+ if tzdata {
+ tzdataPaths = tzdataPaths[:1]
+ }
+}
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
index c2ae7930203..b903e1485c6 100644
--- a/libgo/go/time/format.go
+++ b/libgo/go/time/format.go
@@ -42,6 +42,13 @@ import "errors"
// Z07:00 Z or ±hh:mm
// Z07 Z or ±hh
//
+// The recognized day of week formats are "Mon" and "Monday".
+// The recognized month formats are "Jan" and "January".
+//
+// Text in the format string that is not recognized as part of the reference
+// time is echoed verbatim during Format and expected to appear verbatim
+// in the input to Parse.
+//
// The executable example for time.Format demonstrates the working
// of the layout string in detail and is a good reference.
//
@@ -844,6 +851,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
sec, value, err = getnum(value, std == stdZeroSecond)
if sec < 0 || 60 <= sec {
rangeErrString = "second"
+ break
}
// Special case: do we have a fractional second but no
// fractional second in the format?
@@ -1004,7 +1012,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
}
// Validate the day of the month.
- if day > daysIn(Month(month), year) {
+ if day < 1 || day > daysIn(Month(month), year) {
return Time{}, &ParseError{alayout, avalue, "", value, ": day out of range"}
}
@@ -1020,12 +1028,12 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
// If that zone was in effect at the given time, use it.
name, offset, _, _, _ := local.lookup(t.sec + internalToUnix)
if offset == zoneOffset && (zoneName == "" || name == zoneName) {
- t.loc = local
+ t.setLoc(local)
return t, nil
}
// Otherwise create fake zone to record offset.
- t.loc = FixedZone(zoneName, zoneOffset)
+ t.setLoc(FixedZone(zoneName, zoneOffset))
return t, nil
}
@@ -1036,7 +1044,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
offset, _, ok := local.lookupName(zoneName, t.sec+internalToUnix)
if ok {
t.sec -= int64(offset)
- t.loc = local
+ t.setLoc(local)
return t, nil
}
@@ -1045,7 +1053,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT.
offset *= 3600
}
- t.loc = FixedZone(zoneName, offset)
+ t.setLoc(FixedZone(zoneName, offset))
return t, nil
}
@@ -1093,8 +1101,9 @@ func parseTimeZone(value string) (length int, ok bool) {
if value[4] == 'T' {
return 5, true
}
- case 4: // Must end in T to match.
- if value[3] == 'T' {
+ case 4:
+ // Must end in T, except one special case.
+ if value[3] == 'T' || value[:4] == "WITA" {
return 4, true
}
case 3:
@@ -1173,6 +1182,37 @@ func leadingInt(s string) (x int64, rem string, err error) {
return x, s[i:], nil
}
+// leadingFraction consumes the leading [0-9]* from s.
+// It is used only for fractions, so does not return an error on overflow,
+// it just stops accumulating precision.
+func leadingFraction(s string) (x int64, scale float64, rem string) {
+ i := 0
+ scale = 1
+ overflow := false
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c < '0' || c > '9' {
+ break
+ }
+ if overflow {
+ continue
+ }
+ if x > (1<<63-1)/10 {
+ // It's possible for overflow to give a positive number, so take care.
+ overflow = true
+ continue
+ }
+ y := x*10 + int64(c) - '0'
+ if y < 0 {
+ overflow = true
+ continue
+ }
+ x = y
+ scale *= 10
+ }
+ return x, scale, s[i:]
+}
+
var unitMap = map[string]int64{
"ns": int64(Nanosecond),
"us": int64(Microsecond),
@@ -1235,13 +1275,7 @@ func ParseDuration(s string) (Duration, error) {
if s != "" && s[0] == '.' {
s = s[1:]
pl := len(s)
- f, s, err = leadingInt(s)
- if err != nil {
- return 0, errors.New("time: invalid duration " + orig)
- }
- for n := pl - len(s); n > 0; n-- {
- scale *= 10
- }
+ f, scale, s = leadingFraction(s)
post = pl != len(s)
}
if !pre && !post {
diff --git a/libgo/go/time/format_test.go b/libgo/go/time/format_test.go
index ed5509b3021..648ead0886c 100644
--- a/libgo/go/time/format_test.go
+++ b/libgo/go/time/format_test.go
@@ -224,6 +224,7 @@ var dayOutOfRangeTests = []struct {
{"Thu Nov 31 21:00:57 2010", false},
{"Thu Dec 31 21:00:57 2010", true},
{"Thu Dec 32 21:00:57 2010", false},
+ {"Thu Dec 00 21:00:57 2010", false},
}
func TestParseDayOutOfRange(t *testing.T) {
@@ -406,6 +407,7 @@ var parseTimeZoneTests = []ParseTimeZoneTest{
{"ESAST hi", 5, true},
{"ESASTT hi", 0, false}, // run of upper-case letters too long.
{"ESATY hi", 0, false}, // five letters must end in T.
+ {"WITA hi", 4, true}, // Issue #18251
}
func TestParseTimeZone(t *testing.T) {
@@ -442,6 +444,8 @@ var parseErrorTests = []ParseErrorTest{
{RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
{RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
{RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`},
+ // invalid second followed by optional fractional seconds
+ {RFC3339, "2010-02-04T21:00:67.012345678-08:00", "second out of range"},
}
func TestParseErrors(t *testing.T) {
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go
index 73114f5eecd..4b01404896e 100644
--- a/libgo/go/time/sleep.go
+++ b/libgo/go/time/sleep.go
@@ -12,7 +12,7 @@ func Sleep(d Duration)
func runtimeNano() int64
// Interface to timers implemented in package runtime.
-// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
+// Must be in sync with ../runtime/time.go:/^type timer
type runtimeTimer struct {
i int
when int64
@@ -55,13 +55,22 @@ type Timer struct {
// Stop does not close the channel, to prevent a read from the channel succeeding
// incorrectly.
//
-// To prevent the timer firing after a call to Stop,
-// check the return value and drain the channel. For example:
+// To prevent a timer created with NewTimer from firing after a call to Stop,
+// check the return value and drain the channel.
+// For example, assuming the program has not received from t.C already:
+//
// if !t.Stop() {
// <-t.C
// }
+//
// This cannot be done concurrent to other receives from the Timer's
// channel.
+//
+// For a timer created with AfterFunc(d, f), if t.Stop returns false, then the timer
+// has already expired and the function f has been started in its own goroutine;
+// Stop does not wait for f to complete before returning.
+// If the caller needs to know whether f is completed, it must coordinate
+// with f explicitly.
func (t *Timer) Stop() bool {
if t.r.f == nil {
panic("time: Stop called on uninitialized Timer")
@@ -89,18 +98,25 @@ func NewTimer(d Duration) *Timer {
// It returns true if the timer had been active, false if the timer had
// expired or been stopped.
//
-// To reuse an active timer, always call its Stop method first and—if it had
-// expired—drain the value from its channel. For example:
+// Resetting a timer must take care not to race with the send into t.C
+// that happens when the current timer expires.
+// If a program has already received a value from t.C, the timer is known
+// to have expired, and t.Reset can be used directly.
+// If a program has not yet received a value from t.C, however,
+// the timer must be stopped and—if Stop reports that the timer expired
+// before being stopped—the channel explicitly drained:
+//
// if !t.Stop() {
// <-t.C
// }
// t.Reset(d)
+//
// This should not be done concurrent to other receives from the Timer's
// channel.
//
// Note that it is not possible to use Reset's return value correctly, as there
// is a race condition between draining the channel and the new timer expiring.
-// Reset should always be used in concert with Stop, as described above.
+// Reset should always be invoked on stopped or expired channels, as described above.
// The return value exists to preserve compatibility with existing programs.
func (t *Timer) Reset(d Duration) bool {
if t.r.f == nil {
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index c31de357d58..10b32461e1c 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -4,7 +4,8 @@
// Package time provides functionality for measuring and displaying time.
//
-// The calendrical calculations always assume a Gregorian calendar.
+// The calendrical calculations always assume a Gregorian calendar, with
+// no leap seconds.
package time
import "errors"
@@ -49,11 +50,18 @@ type Time struct {
// loc specifies the Location that should be used to
// determine the minute, hour, month, day, and year
// that correspond to this Time.
- // Only the zero Time has a nil Location.
- // In that case it is interpreted to mean UTC.
+ // The nil location means UTC.
+ // All UTC times are represented with loc==nil, never loc==&utcLoc.
loc *Location
}
+func (t *Time) setLoc(loc *Location) {
+ if loc == &utcLoc {
+ loc = nil
+ }
+ t.loc = loc
+}
+
// 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
@@ -67,8 +75,7 @@ func (t Time) Before(u Time) bool {
// Equal reports whether t and u represent the same time instant.
// Two times can be equal even if they are in different locations.
// For example, 6:00 +0200 CEST and 4:00 UTC are Equal.
-// This comparison is different from using t == u, which also compares
-// the locations.
+// Do not use == with Time values.
func (t Time) Equal(u Time) bool {
return t.sec == u.sec && t.nsec == u.nsec
}
@@ -107,7 +114,14 @@ var months = [...]string{
}
// String returns the English name of the month ("January", "February", ...).
-func (m Month) String() string { return months[m-1] }
+func (m Month) String() string {
+ if January <= m && m <= December {
+ return months[m-1]
+ }
+ buf := make([]byte, 20)
+ n := fmtInt(buf, uint64(m))
+ return "%!Month(" + string(buf[n:]) + ")"
+}
// A Weekday specifies a day of the week (Sunday = 0, ...).
type Weekday int
@@ -585,21 +599,21 @@ func (d Duration) Nanoseconds() int64 { return int64(d) }
func (d Duration) Seconds() float64 {
sec := d / Second
nsec := d % Second
- return float64(sec) + float64(nsec)*1e-9
+ return float64(sec) + float64(nsec)/1e9
}
// Minutes returns the duration as a floating point number of minutes.
func (d Duration) Minutes() float64 {
min := d / Minute
nsec := d % Minute
- return float64(min) + float64(nsec)*(1e-9/60)
+ return float64(min) + float64(nsec)/(60*1e9)
}
// Hours returns the duration as a floating point number of hours.
func (d Duration) Hours() float64 {
hour := d / Hour
nsec := d % Hour
- return float64(hour) + float64(nsec)*(1e-9/60/60)
+ return float64(hour) + float64(nsec)/(60*60*1e9)
}
// Add returns the time t+d.
@@ -640,6 +654,12 @@ func Since(t Time) Duration {
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())
+}
+
// AddDate returns the time corresponding to adding the
// given number of years, months, and days to t.
// For example, AddDate(-1, 2, 3) applied to January 1, 2011
@@ -651,7 +671,7 @@ func Since(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.loc)
+ return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.Location())
}
const (
@@ -781,13 +801,13 @@ func Now() Time {
// UTC returns t with the location set to UTC.
func (t Time) UTC() Time {
- t.loc = UTC
+ t.setLoc(&utcLoc)
return t
}
// Local returns t with the location set to local time.
func (t Time) Local() Time {
- t.loc = Local
+ t.setLoc(Local)
return t
}
@@ -798,7 +818,7 @@ func (t Time) In(loc *Location) Time {
if loc == nil {
panic("time: missing Location in call to Time.In")
}
- t.loc = loc
+ t.setLoc(loc)
return t
}
@@ -826,8 +846,9 @@ func (t Time) Unix() int64 {
// UnixNano returns t as a Unix time, the number of nanoseconds elapsed
// since January 1, 1970 UTC. The result is undefined if the Unix time
-// in nanoseconds cannot be represented by an int64. Note that this
-// means the result of calling UnixNano on the zero Time is undefined.
+// in nanoseconds cannot be represented by an int64 (a date before the year
+// 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)
}
@@ -838,7 +859,7 @@ const timeBinaryVersion byte = 1
func (t Time) MarshalBinary() ([]byte, error) {
var offsetMin int16 // minutes east of UTC. -1 is UTC.
- if t.Location() == &utcLoc {
+ if t.Location() == UTC {
offsetMin = -1
} else {
_, offset := t.Zone()
@@ -899,11 +920,11 @@ func (t *Time) UnmarshalBinary(data []byte) error {
offset := int(int16(buf[1])|int16(buf[0])<<8) * 60
if offset == -1*60 {
- t.loc = &utcLoc
+ t.setLoc(&utcLoc)
} else if _, localoff, _, _, _ := Local.lookup(t.sec + internalToUnix); offset == localoff {
- t.loc = Local
+ t.setLoc(Local)
} else {
- t.loc = FixedZone("", offset)
+ t.setLoc(FixedZone("", offset))
}
return nil
@@ -942,6 +963,10 @@ func (t Time) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the json.Unmarshaler interface.
// The time is expected to be a quoted string in RFC 3339 format.
func (t *Time) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
// Fractional seconds are handled implicitly by Parse.
var err error
*t, err = Parse(`"`+RFC3339+`"`, string(data))
@@ -1092,11 +1117,18 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T
unix -= int64(offset)
}
- return Time{unix + unixToInternal, int32(nsec), loc}
+ t := Time{unix + unixToInternal, int32(nsec), nil}
+ t.setLoc(loc)
+ return t
}
// Truncate returns the result of rounding t down to a multiple of d (since the zero time).
// If d <= 0, Truncate returns t unchanged.
+//
+// Truncate operates on the time as an absolute duration since the
+// zero time; it does not operate on the presentation form of the
+// 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 {
if d <= 0 {
return t
@@ -1108,6 +1140,11 @@ func (t Time) Truncate(d Duration) Time {
// Round returns the result of rounding t to the nearest multiple of d (since the zero time).
// The rounding behavior for halfway values is to round up.
// If d <= 0, Round returns t unchanged.
+//
+// Round operates on the time as an absolute duration since the
+// zero time; it does not operate on the presentation form of the
+// 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 {
if d <= 0 {
return t
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index c9665ea04b5..2922560f097 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -840,6 +840,10 @@ var parseDurationTests = []struct {
{"9223372036s854ms775us807ns", true, (1<<63 - 1) * Nanosecond},
// large negative value
{"-9223372036854775807ns", true, -1<<63 + 1*Nanosecond},
+ // huge string; issue 15011.
+ {"0.100000000000000000000h", true, 6 * Minute},
+ // This value tests the first overflow check in leadingFraction.
+ {"0.830103483285477580700h", true, 49*Minute + 48*Second + 372539827*Nanosecond},
// errors
{"", false, 0},
@@ -891,7 +895,7 @@ func TestLocationRace(t *testing.T) {
go func() {
c <- Now().String()
}()
- Now().String()
+ _ = Now().String()
<-c
Sleep(100 * Millisecond)
@@ -999,6 +1003,21 @@ func TestDurationNanoseconds(t *testing.T) {
}
}
+var secDurationTests = []struct {
+ d Duration
+ want float64
+}{
+ {Duration(300000000), 0.3},
+}
+
+func TestDurationSeconds(t *testing.T) {
+ for _, tt := range secDurationTests {
+ if got := tt.d.Seconds(); got != tt.want {
+ t.Errorf("d.Seconds() = %g; want: %g", got, tt.want)
+ }
+ }
+}
+
var minDurationTests = []struct {
d Duration
want float64
@@ -1007,6 +1026,7 @@ var minDurationTests = []struct {
{Duration(-1), -1 / 60e9},
{Duration(1), 1 / 60e9},
{Duration(60000000000), 1},
+ {Duration(3000), 5e-8},
}
func TestDurationMinutes(t *testing.T) {
@@ -1025,6 +1045,7 @@ var hourDurationTests = []struct {
{Duration(-1), -1 / 3600e9},
{Duration(1), 1 / 3600e9},
{Duration(3600000000000), 1},
+ {Duration(36), 1e-11},
}
func TestDurationHours(t *testing.T) {
@@ -1035,6 +1056,100 @@ func TestDurationHours(t *testing.T) {
}
}
+var defaultLocTests = []struct {
+ name string
+ f func(t1, t2 Time) bool
+}{
+ {"After", func(t1, t2 Time) bool { return t1.After(t2) == t2.After(t1) }},
+ {"Before", func(t1, t2 Time) bool { return t1.Before(t2) == t2.Before(t1) }},
+ {"Equal", func(t1, t2 Time) bool { return t1.Equal(t2) == t2.Equal(t1) }},
+
+ {"IsZero", func(t1, t2 Time) bool { return t1.IsZero() == t2.IsZero() }},
+ {"Date", func(t1, t2 Time) bool {
+ a1, b1, c1 := t1.Date()
+ a2, b2, c2 := t2.Date()
+ return a1 == a2 && b1 == b2 && c1 == c2
+ }},
+ {"Year", func(t1, t2 Time) bool { return t1.Year() == t2.Year() }},
+ {"Month", func(t1, t2 Time) bool { return t1.Month() == t2.Month() }},
+ {"Day", func(t1, t2 Time) bool { return t1.Day() == t2.Day() }},
+ {"Weekday", func(t1, t2 Time) bool { return t1.Weekday() == t2.Weekday() }},
+ {"ISOWeek", func(t1, t2 Time) bool {
+ a1, b1 := t1.ISOWeek()
+ a2, b2 := t2.ISOWeek()
+ return a1 == a2 && b1 == b2
+ }},
+ {"Clock", func(t1, t2 Time) bool {
+ a1, b1, c1 := t1.Clock()
+ a2, b2, c2 := t2.Clock()
+ return a1 == a2 && b1 == b2 && c1 == c2
+ }},
+ {"Hour", func(t1, t2 Time) bool { return t1.Hour() == t2.Hour() }},
+ {"Minute", func(t1, t2 Time) bool { return t1.Minute() == t2.Minute() }},
+ {"Second", func(t1, t2 Time) bool { return t1.Second() == t2.Second() }},
+ {"Nanosecond", func(t1, t2 Time) bool { return t1.Hour() == t2.Hour() }},
+ {"YearDay", func(t1, t2 Time) bool { return t1.YearDay() == t2.YearDay() }},
+
+ // Using Equal since Add don't modify loc using "==" will cause a fail
+ {"Add", func(t1, t2 Time) bool { return t1.Add(Hour).Equal(t2.Add(Hour)) }},
+ {"Sub", func(t1, t2 Time) bool { return t1.Sub(t2) == t2.Sub(t1) }},
+
+ //Original caus for this test case bug 15852
+ {"AddDate", func(t1, t2 Time) bool { return t1.AddDate(1991, 9, 3) == t2.AddDate(1991, 9, 3) }},
+
+ {"UTC", func(t1, t2 Time) bool { return t1.UTC() == t2.UTC() }},
+ {"Local", func(t1, t2 Time) bool { return t1.Local() == t2.Local() }},
+ {"In", func(t1, t2 Time) bool { return t1.In(UTC) == t2.In(UTC) }},
+
+ {"Local", func(t1, t2 Time) bool { return t1.Local() == t2.Local() }},
+ {"Zone", func(t1, t2 Time) bool {
+ a1, b1 := t1.Zone()
+ a2, b2 := t2.Zone()
+ return a1 == a2 && b1 == b2
+ }},
+
+ {"Unix", func(t1, t2 Time) bool { return t1.Unix() == t2.Unix() }},
+ {"UnixNano", func(t1, t2 Time) bool { return t1.UnixNano() == t2.UnixNano() }},
+
+ {"MarshalBinary", func(t1, t2 Time) bool {
+ a1, b1 := t1.MarshalBinary()
+ a2, b2 := t2.MarshalBinary()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+ {"GobEncode", func(t1, t2 Time) bool {
+ a1, b1 := t1.GobEncode()
+ a2, b2 := t2.GobEncode()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+ {"MarshalJSON", func(t1, t2 Time) bool {
+ a1, b1 := t1.MarshalJSON()
+ a2, b2 := t2.MarshalJSON()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+ {"MarshalText", func(t1, t2 Time) bool {
+ a1, b1 := t1.MarshalText()
+ a2, b2 := t2.MarshalText()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+
+ {"Truncate", func(t1, t2 Time) bool { return t1.Truncate(Hour).Equal(t2.Truncate(Hour)) }},
+ {"Round", func(t1, t2 Time) bool { return t1.Round(Hour).Equal(t2.Round(Hour)) }},
+
+ {"== Time{}", func(t1, t2 Time) bool { return (t1 == Time{}) == (t2 == Time{}) }},
+}
+
+func TestDefaultLoc(t *testing.T) {
+ //This test verifyes that all Time's methods behaves identical if loc is set
+ //as nil or UTC
+ for _, tt := range defaultLocTests {
+ t1 := Time{}
+ t2 := Time{}.UTC()
+ if !tt.f(t1, t2) {
+ t.Errorf("Time{} and Time{}.UTC() behave differently for %s", tt.name)
+ }
+ }
+}
+
func BenchmarkNow(b *testing.B) {
for i := 0; i < b.N; i++ {
t = Now()
@@ -1117,3 +1232,25 @@ func BenchmarkDay(b *testing.B) {
_ = t.Day()
}
}
+
+func TestMarshalBinaryZeroTime(t *testing.T) {
+ t0 := Time{}
+ enc, err := t0.MarshalBinary()
+ if err != nil {
+ t.Fatal(err)
+ }
+ t1 := Now() // not zero
+ if err := t1.UnmarshalBinary(enc); err != nil {
+ t.Fatal(err)
+ }
+ if t1 != t0 {
+ t.Errorf("t0=%#v\nt1=%#v\nwant identical structures", t0, t1)
+ }
+}
+
+// Issue 17720: Zero value of time.Month fails to print
+func TestZeroMonthString(t *testing.T) {
+ if got, want := Month(0).String(), "%!Month(0)"; got != want {
+ t.Errorf("zero month = %q; want %q", got, want)
+ }
+}
diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go
index c56743933f9..fb0aa392404 100644
--- a/libgo/go/time/zoneinfo.go
+++ b/libgo/go/time/zoneinfo.go
@@ -9,6 +9,8 @@ import (
"syscall"
)
+//go:generate env ZONEINFO=$GOROOT/lib/time/zoneinfo.zip go run genzabbrs.go -output zoneinfo_abbrs_windows.go
+
// A Location maps time instants to the zone in use at that time.
// Typically, the Location represents the collection of time offsets
// in use in a geographical area, such as CEST and CET for central Europe.
diff --git a/libgo/go/time/zoneinfo_abbrs_windows.go b/libgo/go/time/zoneinfo_abbrs_windows.go
index 344a891d1a4..9425db844ca 100644
--- a/libgo/go/time/zoneinfo_abbrs_windows.go
+++ b/libgo/go/time/zoneinfo_abbrs_windows.go
@@ -13,92 +13,106 @@ type abbr struct {
}
var abbrs = map[string]abbr{
- "Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo
- "Morocco Standard Time": {"WET", "WEST"}, // Africa/Casablanca
- "South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
- "W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
- "E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
- "Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
- "Namibia Standard Time": {"WAT", "WAST"}, // Africa/Windhoek
- "Alaskan Standard Time": {"AKST", "AKDT"}, // America/Anchorage
- "Paraguay Standard Time": {"PYT", "PYST"}, // America/Asuncion
- "Bahia Standard Time": {"BRT", "BRT"}, // America/Bahia
- "SA Pacific Standard Time": {"COT", "COT"}, // America/Bogota
- "Argentina Standard Time": {"ART", "ART"}, // 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
- "Central Standard Time": {"CST", "CDT"}, // America/Chicago
- "Mountain Standard Time (Mexico)": {"MST", "MDT"}, // America/Chihuahua
- "Central Brazilian Standard Time": {"AMT", "AMST"}, // America/Cuiaba
- "Mountain Standard Time": {"MST", "MDT"}, // America/Denver
- "Greenland Standard Time": {"WGT", "WGST"}, // America/Godthab
- "Central America Standard Time": {"CST", "CST"}, // America/Guatemala
- "Atlantic Standard Time": {"AST", "ADT"}, // America/Halifax
- "US Eastern Standard Time": {"EST", "EDT"}, // America/Indianapolis
- "SA Western Standard Time": {"BOT", "BOT"}, // America/La_Paz
- "Pacific Standard Time": {"PST", "PDT"}, // America/Los_Angeles
- "Central Standard Time (Mexico)": {"CST", "CDT"}, // America/Mexico_City
- "Montevideo Standard Time": {"UYT", "UYT"}, // America/Montevideo
- "Eastern Standard Time": {"EST", "EDT"}, // America/New_York
- "US Mountain Standard Time": {"MST", "MST"}, // America/Phoenix
- "Canada Central Standard Time": {"CST", "CST"}, // America/Regina
- "Pacific SA Standard Time": {"CLT", "CLST"}, // America/Santiago
- "E. South America Standard Time": {"BRT", "BRST"}, // America/Sao_Paulo
- "Newfoundland Standard Time": {"NST", "NDT"}, // America/St_Johns
- "Central Asia Standard Time": {"+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
- "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
- "Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus
- "Bangladesh Standard Time": {"BDT", "BDT"}, // Asia/Dhaka
- "Arabian Standard Time": {"GST", "GST"}, // Asia/Dubai
- "North Asia East Standard Time": {"IRKT", "IRKT"}, // Asia/Irkutsk
- "Israel Standard Time": {"IST", "IDT"}, // Asia/Jerusalem
- "Afghanistan Standard Time": {"AFT", "AFT"}, // Asia/Kabul
- "Russia Time Zone 11": {"PETT", "PETT"}, // 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": {"NOVT", "NOVT"}, // Asia/Novosibirsk
- "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
- "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
- "Taipei Standard Time": {"CST", "CST"}, // Asia/Taipei
- "West Asia Standard Time": {"UZT", "UZT"}, // Asia/Tashkent
- "Georgian Standard Time": {"GET", "GET"}, // Asia/Tbilisi
- "Iran Standard Time": {"IRST", "IRDT"}, // Asia/Tehran
- "Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo
- "Ulaanbaatar Standard Time": {"ULAT", "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
- "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
- "Tasmania Standard Time": {"AEST", "AEDT"}, // Australia/Hobart
- "W. Australia Standard Time": {"AWST", "AWST"}, // Australia/Perth
- "AUS Eastern Standard Time": {"AEST", "AEDT"}, // Australia/Sydney
+ "Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo
+ "Morocco Standard Time": {"WET", "WEST"}, // Africa/Casablanca
+ "South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
+ "W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
+ "E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
+ "Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
+ "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
+ "Eastern Standard Time (Mexico)": {"EST", "EST"}, // America/Cancun
+ "Venezuela Standard Time": {"VET", "VET"}, // America/Caracas
+ "SA Eastern Standard Time": {"GFT", "GFT"}, // America/Cayenne
+ "Central Standard Time": {"CST", "CDT"}, // America/Chicago
+ "Mountain Standard Time (Mexico)": {"MST", "MDT"}, // America/Chihuahua
+ "Central Brazilian Standard Time": {"AMT", "AMST"}, // America/Cuiaba
+ "Mountain Standard Time": {"MST", "MDT"}, // America/Denver
+ "Greenland Standard Time": {"WGT", "WGST"}, // America/Godthab
+ "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
+ "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
+ "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
+ "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
+ "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
+ "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
+ "Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus
+ "Bangladesh Standard Time": {"BDT", "BDT"}, // Asia/Dhaka
+ "Arabian Standard Time": {"GST", "GST"}, // 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
+ "Israel Standard Time": {"IST", "IDT"}, // Asia/Jerusalem
+ "Afghanistan Standard Time": {"AFT", "AFT"}, // Asia/Kabul
+ "Russia Time Zone 11": {"PETT", "PETT"}, // 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
+ "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
+ "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
+ "Taipei Standard Time": {"CST", "CST"}, // Asia/Taipei
+ "West Asia Standard Time": {"UZT", "UZT"}, // Asia/Tashkent
+ "Georgian Standard Time": {"GET", "GET"}, // Asia/Tbilisi
+ "Iran Standard Time": {"IRST", "IRDT"}, // Asia/Tehran
+ "Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo
+ "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
+ "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
+ "Tasmania Standard Time": {"AEST", "AEDT"}, // Australia/Hobart
+ "Lord Howe Standard Time": {"LHST", "LHDT"}, // 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
@@ -117,10 +131,15 @@ var abbrs = map[string]abbr{
"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
}
diff --git a/libgo/go/time/zoneinfo_android.go b/libgo/go/time/zoneinfo_android.go
new file mode 100644
index 00000000000..695a8adfaa3
--- /dev/null
+++ b/libgo/go/time/zoneinfo_android.go
@@ -0,0 +1,119 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse the "tzdata" packed timezone file used on Android.
+// The format is lifted from ZoneInfoDB.java and ZoneInfo.java in
+// java/libcore/util in the AOSP.
+
+package time
+
+import (
+ "errors"
+ "runtime"
+)
+
+var tzdataPaths = []string{
+ "/system/usr/share/zoneinfo/tzdata",
+ "/data/misc/zoneinfo/current/tzdata",
+ runtime.GOROOT() + "/lib/time/zoneinfo.zip",
+}
+
+var origTzdataPaths = tzdataPaths
+
+func forceZipFileForTesting(zipOnly bool) {
+ tzdataPaths = make([]string, len(origTzdataPaths))
+ copy(tzdataPaths, origTzdataPaths)
+ if zipOnly {
+ for i := 0; i < len(tzdataPaths)-1; i++ {
+ tzdataPaths[i] = "/XXXNOEXIST"
+ }
+ }
+}
+
+func initTestingZone() {
+ z, err := loadLocation("America/Los_Angeles")
+ if err != nil {
+ panic("cannot load America/Los_Angeles for testing: " + err.Error())
+ }
+ z.name = "Local"
+ localLoc = *z
+}
+
+func initLocal() {
+ // TODO(elias.naur): getprop persist.sys.timezone
+ localLoc = *UTC
+}
+
+func loadLocation(name string) (*Location, error) {
+ var firstErr error
+ for _, path := range tzdataPaths {
+ var z *Location
+ var err error
+ if len(path) > 4 && path[len(path)-4:] == ".zip" {
+ z, err = loadZoneZip(path, name)
+ } else {
+ z, err = loadTzdataFile(path, name)
+ }
+ if 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)
+}
+
+func loadTzdataFile(file, name string) (*Location, error) {
+ const (
+ headersize = 12 + 3*4
+ namesize = 40
+ entrysize = namesize + 3*4
+ )
+ if len(name) > namesize {
+ return nil, errors.New(name + " is longer than the maximum zone name length (40 bytes)")
+ }
+ fd, err := open(file)
+ if err != nil {
+ return nil, err
+ }
+ defer closefd(fd)
+
+ buf := make([]byte, headersize)
+ if err := preadn(fd, buf, 0); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ d := data{buf, false}
+ if magic := d.read(6); string(magic) != "tzdata" {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ d = data{buf[12:], false}
+ indexOff, _ := d.big4()
+ dataOff, _ := d.big4()
+ indexSize := dataOff - indexOff
+ entrycount := indexSize / entrysize
+ buf = make([]byte, indexSize)
+ if err := preadn(fd, buf, int(indexOff)); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ for i := 0; i < int(entrycount); i++ {
+ entry := buf[i*entrysize : (i+1)*entrysize]
+ // len(name) <= namesize is checked at function entry
+ if string(entry[:len(name)]) != name {
+ continue
+ }
+ d := data{entry[namesize:], false}
+ off, _ := d.big4()
+ size, _ := d.big4()
+ buf := make([]byte, size)
+ if err := preadn(fd, buf, int(off+dataOff)); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ return loadZoneData(buf)
+ }
+ return nil, errors.New("cannot find " + name + " in tzdata file " + file)
+}
diff --git a/libgo/go/time/zoneinfo_android_test.go b/libgo/go/time/zoneinfo_android_test.go
new file mode 100644
index 00000000000..ba065d10a65
--- /dev/null
+++ b/libgo/go/time/zoneinfo_android_test.go
@@ -0,0 +1,18 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+ "testing"
+ . "time"
+)
+
+func TestAndroidTzdata(t *testing.T) {
+ ForceAndroidTzdataForTest(true)
+ defer ForceAndroidTzdataForTest(false)
+ if _, err := LoadLocation("America/Los_Angeles"); err != nil {
+ t.Error(err)
+ }
+}
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
index 6c7aafff77b..772748818a9 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,386 darwin,amd64 dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build darwin,386 darwin,amd64 dragonfly freebsd linux,!android 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.
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
index a6546f54b86..a6e227b5b0d 100644
--- a/libgo/go/time/zoneinfo_windows.go
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -11,8 +11,6 @@ import (
"syscall"
)
-//go:generate go run genzabbrs.go -output zoneinfo_abbrs_windows.go
-
// TODO(rsc): Fall back to copy of zoneinfo files.
// BUG(brainman,rsc): On Windows, the operating system does not provide complete