1
0
mirror of https://github.com/golang/go synced 2024-11-22 10:14:40 -07:00

time: handle GMT possibly with offset

Update #3790
Handle time zones like GMT-8.
The more general time zone-matching problem is not yet resolved.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/12922043
This commit is contained in:
Rob Pike 2013-08-15 10:10:49 +10:00
parent 80ca8c5d04
commit 727b2b6f7d
2 changed files with 64 additions and 19 deletions

View File

@ -353,8 +353,8 @@ var atoiError = errors.New("time: invalid number")
// Duplicates functionality in strconv, but avoids dependency. // Duplicates functionality in strconv, but avoids dependency.
func atoi(s string) (x int, err error) { func atoi(s string) (x int, err error) {
neg := false neg := false
if s != "" && s[0] == '-' { if s != "" && (s[0] == '-' || s[0] == '+') {
neg = true neg = s[0] == '-'
s = s[1:] s = s[1:]
} }
q, rem, err := leadingInt(s) q, rem, err := leadingInt(s)
@ -933,25 +933,12 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
value = value[3:] value = value[3:]
break break
} }
n, ok := parseTimeZone(value)
if len(value) >= 3 && value[2] == 'T' { if !ok {
p, value = value[0:3], value[3:]
} else if len(value) >= 4 && value[3] == 'T' {
p, value = value[0:4], value[4:]
} else {
err = errBad err = errBad
break break
} }
for i := 0; i < len(p); i++ { zoneName, value = value[:n], value[n:]
if p[i] < 'A' || 'Z' < p[i] {
err = errBad
}
}
if err != nil {
break
}
// It's a valid format.
zoneName = p
case stdFracSecond0: case stdFracSecond0:
// stdFracSecond0 requires the exact number of digits as specified in // stdFracSecond0 requires the exact number of digits as specified in
@ -1024,7 +1011,11 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
} }
// Otherwise, create fake zone with unknown offset. // Otherwise, create fake zone with unknown offset.
t.loc = FixedZone(zoneName, 0) if len(zoneName) > 3 && zoneName[:3] == "GMT" {
offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT.
offset *= 3600
}
t.loc = FixedZone(zoneName, offset)
return t, nil return t, nil
} }
@ -1032,6 +1023,57 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil
} }
// parseTimeZone parses a time zone string and returns its length.
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" {
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] {
return 0, false
}
}
return length, true
}
// 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 -14 through 12 excluding zero.
func parseGMT(value string) int {
value = value[3:]
if len(value) == 0 {
return 3
}
sign := value[0]
if sign != '-' && sign != '+' {
return 3
}
x, rem, err := leadingInt(value[1:])
if err != nil {
return 3
}
if sign == '-' {
x = -x
}
if x == 0 || x < -14 || 12 < x {
return 3
}
return 3 + len(value) - len(rem)
}
func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) { func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) {
if value[0] != '.' { if value[0] != '.' {
err = errBad err = errBad

View File

@ -510,6 +510,9 @@ var parseTests = []ParseTest{
// Month and day names only match when not followed by a lower-case letter. // Month and day names only match when not followed by a lower-case letter.
{"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb 4 21:00:57 2010", false, true, 1, 0}, {"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb 4 21:00:57 2010", false, true, 1, 0},
// GMT with offset.
{"GMT-8", UnixDate, "Fri Feb 5 05:00:57 GMT-8 2010", true, true, 1, 0},
// Accept any number of fractional second digits (including none) for .999... // Accept any number of fractional second digits (including none) for .999...
// In Go 1, .999... was completely ignored in the format, meaning the first two // In Go 1, .999... was completely ignored in the format, meaning the first two
// cases would succeed, but the next four would not. Go 1.1 accepts all six. // cases would succeed, but the next four would not. Go 1.1 accepts all six.