From 3b3f422afed632a7d332e03444a908abc170d402 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 30 Nov 2015 09:21:34 -0800 Subject: [PATCH] time: fix handling of -07, handle Z07 The existing code has partial support for -07 (just the hours of a time zone offset). Complete the support, add support for Z07, and add a few tests. Fixes #13426. Change-Id: Ic6377bbf3e65b4bb761b9779f7e80c07ce4f57e8 Reviewed-on: https://go-review.googlesource.com/17260 Reviewed-by: Brad Fitzpatrick --- src/time/format.go | 20 ++++++++++++++------ src/time/format_test.go | 3 +++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/time/format.go b/src/time/format.go index 697e1dd4ab..949390196a 100644 --- a/src/time/format.go +++ b/src/time/format.go @@ -34,11 +34,13 @@ 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. @@ -86,6 +88,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 @@ -220,6 +223,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') { @@ -537,10 +543,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 } @@ -557,7 +563,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 { @@ -871,8 +879,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 @@ -888,7 +896,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 diff --git a/src/time/format_test.go b/src/time/format_test.go index b1b7a005d4..976c1df5f7 100644 --- a/src/time/format_test.go +++ b/src/time/format_test.go @@ -504,6 +504,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) {