]> Cypherpunks repositories - gostls13.git/commitdiff
time: expand acceptance of time zones when parsing
authorRob Pike <r@golang.org>
Thu, 15 Aug 2013 06:42:54 +0000 (16:42 +1000)
committerRob Pike <r@golang.org>
Thu, 15 Aug 2013 06:42:54 +0000 (16:42 +1000)
I tried to make it absolutely correct but there are too many
conflicting definitions for the official list of time zones.
Since when we're parsing we know when to expect
a time zone and we know what they look like if not exactly
what the definitive set is, we compromise. We accept any
three-character sequence of upper case letters, possibly
followed by a capital T (all four-letter zones end in T).

There is one crazy special case (ChST) and the possibility
of a signed hour offset for GMT.

Fixes #3790
I hope forever, but I doubt that very much.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/12969043

src/pkg/time/format.go

index ae13811d4128eca703af5ed7390632073e9d30ea..3abe1c210da06d2a607f9faa55de8130ed2f17f3 100644 (file)
@@ -1023,30 +1023,39 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
        return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil
 }
 
-// parseTimeZone parses a time zone string and returns its length.
+// parseTimeZone parses a time zone string and returns its length. Time zones
+// are human-generated and unpredictable. We can't do precise error checking.
+// On the other hand, for a correct parse there must be a time zone at the
+// beginning of the string, so it's almost always true that there's one
+// there. We check: 3 or 4 upper case letters (with one exception). If 4, the
+// last letter must be a T.
+// GMT is special because it can have an hour offset.
 func parseTimeZone(value string) (length int, ok bool) {
        if len(value) < 3 {
                return 0, false
        }
-       // GMT may have an offset.
-       if len(value) >= 3 && value[:3] == "GMT" {
+       // Special case 1: This is the only zone with a lower-case letter.
+       if len(value) >= 4 && value[:4] == "ChST" {
+               return 4, true
+       }
+       // Special case 2: GMT may have an hour offset; treat it specially.
+       if value[:3] == "GMT" {
                length = parseGMT(value)
                return length, true
        }
-
-       if len(value) >= 3 && value[2] == 'T' {
-               length = 3
-       } else if len(value) >= 4 && value[3] == 'T' {
-               length = 4
-       } else {
-               return 0, false
-       }
-       for i := 0; i < length; i++ {
-               if value[i] < 'A' || 'Z' < value[i] {
+       // There must be three upper-case letters.
+       for i := 0; i < 3; i++ {
+               c := value[i]
+               if c < 'A' || 'Z' < c {
                        return 0, false
                }
        }
-       return length, true
+       // There may be a fourth upper case letter. If so, in a time zone it's always a 'T'.
+       // (The last letter is often not a 'T' in three-letter zones: MSK, MSD, HAE, etc.)
+       if len(value) >= 4 && value[3] == 'T' {
+               return 4, true
+       }
+       return 3, true
 }
 
 // parseGMT parses a GMT time zone. The input string is known to start "GMT".