diff options
author | Ian Lance Taylor <iant@google.com> | 2016-02-03 21:58:02 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-02-03 21:58:02 +0000 |
commit | f98dd1a338867a408f7c72d73fbad7fe7fc93e3a (patch) | |
tree | 2f8da9862a9c1fe0df138917f997b03439c02773 /libgo/go/time | |
parent | b081ed4efc144da0c45a6484aebfd10e0eb9fda3 (diff) | |
download | gcc-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.go | 48 | ||||
-rw-r--r-- | libgo/go/time/format_test.go | 83 | ||||
-rw-r--r-- | libgo/go/time/time.go | 13 | ||||
-rw-r--r-- | libgo/go/time/time_test.go | 14 | ||||
-rw-r--r-- | libgo/go/time/zoneinfo.go | 2 | ||||
-rw-r--r-- | libgo/go/time/zoneinfo_windows.go | 32 |
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 |