Skip to content

time: bugs in parsing time string with GMT as time zone. #40472

Closed as not planned
@ghost

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.

go/src/time/format.go

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:]

go/src/time/format.go

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.

go/src/time/format.go

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions