-
Notifications
You must be signed in to change notification settings - Fork 18.4k

Description
What version of Go are you using (go version
)?
Go Playground,
Go 1.14.6
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
go env
Output
Go Playground.
What did you do?
https://play.golang.org/p/UJyx6fMkbJW
var (
tests = [][2]string{
{"Tue Jun 11 2019 13:26:45 GMT+08", "Mon Jan 02 2006 15:04:05 MST-07"},
{"Tue Jun 11 2019 13:26:45 GMT+0800", "Mon Jan 02 2006 15:04:05 MST-0700"},
{"Tue Jun 11 2019 13:26:45 GMT+0000", "Mon Jan 02 2006 15:04:05 MST-0700"},
{"Tue Jun 11 2019 13:26:45 MST+0000", "Mon Jan 02 2006 15:04:05 MST-0700"},
{"Tue Jun 11 2019 13:26:45 MST+08", "Mon Jan 02 2006 15:04:05 MST-07"},
}
)
func demo() {
for _, vl := range tests {
value, layout := vl[0], vl[1]
_, err := time.Parse(layout, value)
fmt.Printf("time.Parse: %q - error: %v\n", value, err)
}
fmt.Println("--------------")
}
What did you expect to see?
All tests passed without error.
What did you see instead?
The GMT ones except "GMT+0800" failed with cannot parse "" as "-0700"
or cannot parse "" as "-07"
.
Details:
When parsing time zones, the Parse
function calls parseTimeZone
, which makes a special case for parsing GMT time zone (which I don't understand why), calling and returning results from parseGMT
, as bytes to consume by Parse
function.
Lines 1047 to 1059 in 85afa2e
case stdTZ: | |
// Does it look like a time zone? | |
if len(value) >= 3 && value[0:3] == "UTC" { | |
z = UTC | |
value = value[3:] | |
break | |
} | |
n, ok := parseTimeZone(value) | |
if !ok { | |
err = errBad | |
break | |
} | |
zoneName, value = value[:n], value[n:] |
Lines 1209 to 1212 in 85afa2e
if value[:3] == "GMT" { | |
length = parseGMT(value) | |
return length, true | |
} |
The parseGMT
function tries to return more than 3 bytes, which is the "GMT"
string, as in other time zone format. You can see in the playground link, that it returns 8 bytes for "GMT+0000"
, and leaving nothing to match with "-0700" in the layout string.
Lines 1247 to 1280 in 85afa2e
// parseGMT parses a GMT time zone. The input string is known to start "GMT". | |
// The function checks whether that is followed by a sign and a number in the | |
// range -23 through +23 excluding zero. | |
func parseGMT(value string) int { | |
value = value[3:] | |
if len(value) == 0 { | |
return 3 | |
} | |
return 3 + parseSignedOffset(value) | |
} | |
// parseSignedOffset parses a signed timezone offset (e.g. "+03" or "-04"). | |
// The function checks for a signed number in the range -23 through +23 excluding zero. | |
// Returns length of the found offset string or 0 otherwise | |
func parseSignedOffset(value string) int { | |
sign := value[0] | |
if sign != '-' && sign != '+' { | |
return 0 | |
} | |
x, rem, err := leadingInt(value[1:]) | |
// fail if nothing consumed by leadingInt | |
if err != nil || value[1:] == rem { | |
return 0 | |
} | |
if sign == '-' { | |
x = -x | |
} | |
if x < -23 || 23 < x { | |
return 0 | |
} | |
return len(value) - len(rem) | |
} |
Interestingly (and confusingly) it does so by checking whether the following string is a signed integer which is in range from -23
to +23
, excluding leading zeroes - but it considers "+0800"
as 800
, which makes it invalid, so parseGMT
returns 3, which makes Parse
functions without an error.
However, all other values showed in the tests ("+0000"
, "+08") are considered valid, and making the Parse
function consumes too much.