aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/time
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2016-02-03 21:58:02 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2016-02-03 21:58:02 +0000
commitf98dd1a338867a408f7c72d73fbad7fe7fc93e3a (patch)
tree2f8da9862a9c1fe0df138917f997b03439c02773 /libgo/go/time
parentb081ed4efc144da0c45a6484aebfd10e0eb9fda3 (diff)
downloadgcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.zip
gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.tar.gz
gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.tar.bz2
libgo: Update to go1.6rc1.
Reviewed-on: https://go-review.googlesource.com/19200 From-SVN: r233110
Diffstat (limited to 'libgo/go/time')
-rw-r--r--libgo/go/time/format.go48
-rw-r--r--libgo/go/time/format_test.go83
-rw-r--r--libgo/go/time/time.go13
-rw-r--r--libgo/go/time/time_test.go14
-rw-r--r--libgo/go/time/zoneinfo.go2
-rw-r--r--libgo/go/time/zoneinfo_windows.go32
6 files changed, 168 insertions, 24 deletions
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
index 873d3ff..e616feb 100644
--- a/libgo/go/time/format.go
+++ b/libgo/go/time/format.go
@@ -34,14 +34,23 @@ import "errors"
// Numeric time zone offsets format as follows:
// -0700 ±hhmm
// -07:00 ±hh:mm
+// -07 ±hh
// Replacing the sign in the format with a Z triggers
// the ISO 8601 behavior of printing Z instead of an
// offset for the UTC zone. Thus:
// Z0700 Z or ±hhmm
// Z07:00 Z or ±hh:mm
+// Z07 Z or ±hh
//
// The executable example for time.Format demonstrates the working
// of the layout string in detail and is a good reference.
+//
+// Note that the RFC822, RFC850, and RFC1123 formats should be applied
+// only to local times. Applying them to UTC times will use "UTC" as the
+// time zone abbreviation, while strictly speaking those RFCs require the
+// use of "GMT" in that case.
+// In general RFC1123Z should be used instead of RFC1123 for servers
+// that insist on that format, and RFC3339 should be preferred for new protocols.
const (
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
@@ -86,6 +95,7 @@ const (
stdTZ = iota // "MST"
stdISO8601TZ // "Z0700" // prints Z for UTC
stdISO8601SecondsTZ // "Z070000"
+ stdISO8601ShortTZ // "Z07"
stdISO8601ColonTZ // "Z07:00" // prints Z for UTC
stdISO8601ColonSecondsTZ // "Z07:00:00"
stdNumTZ // "-0700" // always numeric
@@ -162,8 +172,12 @@ func nextStdChunk(layout string) (prefix string, std int, suffix string) {
}
return layout[0:i], stdDay, layout[i+1:]
- case '_': // _2
+ case '_': // _2, _2006
if len(layout) >= i+2 && layout[i+1] == '2' {
+ //_2006 is really a literal _, followed by stdLongYear
+ if len(layout) >= i+5 && layout[i+1:i+5] == "2006" {
+ return layout[0 : i+1], stdLongYear, layout[i+5:]
+ }
return layout[0:i], stdUnderDay, layout[i+2:]
}
@@ -216,6 +230,9 @@ func nextStdChunk(layout string) (prefix string, std int, suffix string) {
if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" {
return layout[0:i], stdISO8601ColonTZ, layout[i+6:]
}
+ if len(layout) >= i+3 && layout[i:i+3] == "Z07" {
+ return layout[0:i], stdISO8601ShortTZ, layout[i+3:]
+ }
case '.': // .000 or .999 - repeated digits for fractional seconds.
if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') {
@@ -518,7 +535,7 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
case stdZeroMinute:
b = appendInt(b, min, 2)
case stdSecond:
- b = appendInt(b, sec, 2)
+ b = appendInt(b, sec, 0)
case stdZeroSecond:
b = appendInt(b, sec, 2)
case stdPM:
@@ -533,10 +550,10 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
} else {
b = append(b, "am"...)
}
- case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
+ case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumShortTZ, stdNumColonSecondsTZ:
// Ugly special case. We cheat and take the "Z" variants
// to mean "the time zone as formatted for ISO 8601".
- if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ColonSecondsTZ) {
+ if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ShortTZ || std == stdISO8601ColonSecondsTZ) {
b = append(b, 'Z')
break
}
@@ -553,7 +570,9 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
b = append(b, ':')
}
- b = appendInt(b, zone%60, 2)
+ if std != stdNumShortTZ && std != stdISO8601ShortTZ {
+ b = appendInt(b, zone%60, 2)
+ }
// append seconds if appropriate
if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
@@ -696,6 +715,11 @@ 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.
@@ -794,7 +818,8 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
value = value[1:]
}
day, value, err = getnum(value, std == stdZeroDay)
- if day < 0 || 31 < day {
+ if day < 0 {
+ // Note that we allow any one- or two-digit day here.
rangeErrString = "day"
}
case stdHour:
@@ -861,8 +886,8 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
default:
err = errBad
}
- case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
- if (std == stdISO8601TZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' {
+ case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
+ if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' {
value = value[1:]
z = UTC
break
@@ -878,7 +903,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
break
}
sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:]
- } else if std == stdNumShortTZ {
+ } else if std == stdNumShortTZ || std == stdISO8601ShortTZ {
if len(value) < 3 {
err = errBad
break
@@ -975,6 +1000,11 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
hour = 0
}
+ // Validate the day of the month.
+ if day > daysIn(Month(month), year) {
+ return Time{}, &ParseError{alayout, avalue, "", value, ": day out of range"}
+ }
+
if z != nil {
return Date(year, Month(month), day, hour, min, sec, nsec, z), nil
}
diff --git a/libgo/go/time/format_test.go b/libgo/go/time/format_test.go
index 75a08c7..a2592e2 100644
--- a/libgo/go/time/format_test.go
+++ b/libgo/go/time/format_test.go
@@ -74,6 +74,16 @@ func TestFormat(t *testing.T) {
}
}
+// issue 12440.
+func TestFormatSingleDigits(t *testing.T) {
+ time := Date(2001, 2, 3, 4, 5, 6, 700000000, UTC)
+ test := FormatTest{"single digit format", "3:4:5", "4:5:6"}
+ result := time.Format(test.format)
+ if result != test.result {
+ t.Errorf("%s expected %q got %q", test.name, test.result, result)
+ }
+}
+
func TestFormatShortYear(t *testing.T) {
years := []int{
-100001, -100000, -99999,
@@ -183,6 +193,57 @@ func TestParse(t *testing.T) {
}
}
+// All parsed with ANSIC.
+var dayOutOfRangeTests = []struct {
+ date string
+ ok bool
+}{
+ {"Thu Jan 99 21:00:57 2010", false},
+ {"Thu Jan 31 21:00:57 2010", true},
+ {"Thu Jan 32 21:00:57 2010", false},
+ {"Thu Feb 28 21:00:57 2012", true},
+ {"Thu Feb 29 21:00:57 2012", true},
+ {"Thu Feb 29 21:00:57 2010", false},
+ {"Thu Mar 31 21:00:57 2010", true},
+ {"Thu Mar 32 21:00:57 2010", false},
+ {"Thu Apr 30 21:00:57 2010", true},
+ {"Thu Apr 31 21:00:57 2010", false},
+ {"Thu May 31 21:00:57 2010", true},
+ {"Thu May 32 21:00:57 2010", false},
+ {"Thu Jun 30 21:00:57 2010", true},
+ {"Thu Jun 31 21:00:57 2010", false},
+ {"Thu Jul 31 21:00:57 2010", true},
+ {"Thu Jul 32 21:00:57 2010", false},
+ {"Thu Aug 31 21:00:57 2010", true},
+ {"Thu Aug 32 21:00:57 2010", false},
+ {"Thu Sep 30 21:00:57 2010", true},
+ {"Thu Sep 31 21:00:57 2010", false},
+ {"Thu Oct 31 21:00:57 2010", true},
+ {"Thu Oct 32 21:00:57 2010", false},
+ {"Thu Nov 30 21:00:57 2010", true},
+ {"Thu Nov 31 21:00:57 2010", false},
+ {"Thu Dec 31 21:00:57 2010", true},
+ {"Thu Dec 32 21:00:57 2010", false},
+}
+
+func TestParseDayOutOfRange(t *testing.T) {
+ for _, test := range dayOutOfRangeTests {
+ _, err := Parse(ANSIC, test.date)
+ switch {
+ case test.ok && err == nil:
+ // OK
+ case !test.ok && err != nil:
+ if !strings.Contains(err.Error(), "day out of range") {
+ t.Errorf("%q: expected 'day' error, got %v", test.date, err)
+ }
+ case test.ok && err != nil:
+ t.Errorf("%q: unexpected error: %v", test.date, err)
+ case !test.ok && err == nil:
+ t.Errorf("%q: expected 'day' error, got none", test.date)
+ }
+ }
+}
+
func TestParseInLocation(t *testing.T) {
// Check that Parse (and ParseInLocation) understand that
// Feb 01 AST (Arabia Standard Time) and Feb 01 AST (Atlantic Standard Time)
@@ -493,6 +554,9 @@ var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
{"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
{"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
{"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
+ {"2006-01-02T15:04:05-07", "1871-01-01T05:33:02+01", 1 * 60 * 60},
+ {"2006-01-02T15:04:05-07", "1871-01-01T05:33:02-02", -2 * 60 * 60},
+ {"2006-01-02T15:04:05Z07", "1871-01-01T05:33:02-02", -2 * 60 * 60},
}
func TestParseSecondsInTimeZone(t *testing.T) {
@@ -518,3 +582,22 @@ func TestFormatSecondsInTimeZone(t *testing.T) {
}
}
}
+
+// Issue 11334.
+func TestUnderscoreTwoThousand(t *testing.T) {
+ format := "15:04_20060102"
+ input := "14:38_20150618"
+ time, err := Parse(format, input)
+ if err != nil {
+ t.Error(err)
+ }
+ if y, m, d := time.Date(); y != 2015 || m != 6 || d != 18 {
+ t.Errorf("Incorrect y/m/d, got %d/%d/%d", y, m, d)
+ }
+ if h := time.Hour(); h != 14 {
+ t.Errorf("Incorrect hour, got %d", h)
+ }
+ if m := time.Minute(); m != 38 {
+ t.Errorf("Incorrect minute, got %d", m)
+ }
+}
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index 294cc77..ef4ba58 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -180,7 +180,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 2470-2869. Even the days
+// printed for 1970-2469 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
@@ -935,7 +935,12 @@ func (t Time) MarshalJSON() ([]byte, error) {
// See golang.org/issue/4556#c15 for more discussion.
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
}
- return []byte(t.Format(`"` + RFC3339Nano + `"`)), nil
+
+ b := make([]byte, 0, len(RFC3339Nano)+2)
+ b = append(b, '"')
+ b = t.AppendFormat(b, RFC3339Nano)
+ b = append(b, '"')
+ return b, nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
@@ -952,7 +957,9 @@ func (t Time) MarshalText() ([]byte, error) {
if y := t.Year(); y < 0 || y >= 10000 {
return nil, errors.New("Time.MarshalText: year outside of range [0,9999]")
}
- return []byte(t.Format(RFC3339Nano)), nil
+
+ b := make([]byte, 0, len(RFC3339Nano))
+ return t.AppendFormat(b, RFC3339Nano), nil
}
// UnmarshalText implements the encoding.TextUnmarshaler interface.
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index 2d16ea5..a925e98 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -1060,6 +1060,20 @@ func BenchmarkFormatNow(b *testing.B) {
}
}
+func BenchmarkMarshalJSON(b *testing.B) {
+ t := Now()
+ for i := 0; i < b.N; i++ {
+ t.MarshalJSON()
+ }
+}
+
+func BenchmarkMarshalText(b *testing.B) {
+ t := Now()
+ for i := 0; i < b.N; i++ {
+ t.MarshalText()
+ }
+}
+
func BenchmarkParse(b *testing.B) {
for i := 0; i < b.N; i++ {
Parse(ANSIC, "Mon Jan 2 15:04:05 2006")
diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go
index c8e53a2..c567439 100644
--- a/libgo/go/time/zoneinfo.go
+++ b/libgo/go/time/zoneinfo.go
@@ -21,7 +21,7 @@ type Location struct {
// To avoid the binary search through tx, keep a
// static one-element cache that gives the correct
// zone for the time when the Location was created.
- // if cacheStart <= t <= cacheEnd,
+ // if cacheStart <= t < cacheEnd,
// lookup can return cacheZone.
// The units for cacheStart and cacheEnd are seconds
// since January 1, 1970 UTC, to match the argument
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
index d04ebec..bcb8ccd 100644
--- a/libgo/go/time/zoneinfo_windows.go
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -20,8 +20,9 @@ import (
// The implementation assumes that this year's rules for daylight savings
// time apply to all previous and future years as well.
-// matchZoneKey checks if stdname and dstname match the corresponding "Std"
-// and "Dlt" key values in the kname key stored under the open registry key zones.
+// matchZoneKey checks if stdname and dstname match the corresponding key
+// values "MUI_Std" and MUI_Dlt" or "Std" and "Dlt" (the latter down-level
+// from Vista) in the kname key stored under the open registry key zones.
func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (matched bool, err2 error) {
k, err := registry.OpenKey(zones, kname, registry.READ)
if err != nil {
@@ -29,18 +30,27 @@ func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (ma
}
defer k.Close()
- s, _, err := k.GetStringValue("Std")
- if err != nil {
- return false, err
+ var std, dlt string
+ if err = registry.LoadRegLoadMUIString(); err == nil {
+ // Try MUI_Std and MUI_Dlt first, fallback to Std and Dlt if *any* error occurs
+ std, err = k.GetMUIStringValue("MUI_Std")
+ if err == nil {
+ dlt, err = k.GetMUIStringValue("MUI_Dlt")
+ }
}
- if s != stdname {
- return false, nil
+ if err != nil { // Fallback to Std and Dlt
+ if std, _, err = k.GetStringValue("Std"); err != nil {
+ return false, err
+ }
+ if dlt, _, err = k.GetStringValue("Dlt"); err != nil {
+ return false, err
+ }
}
- s, _, err = k.GetStringValue("Dlt")
- if err != nil {
- return false, err
+
+ if std != stdname {
+ return false, nil
}
- if s != dstname && dstname != stdname {
+ if dlt != dstname && dstname != stdname {
return false, nil
}
return true, nil