diff options
Diffstat (limited to 'libgo/go/time/format.go')
-rw-r--r-- | libgo/go/time/format.go | 48 |
1 files changed, 39 insertions, 9 deletions
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go index 873d3ffde91..e616feb048f 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 } |