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:
parent
80ca8c5d04
commit
727b2b6f7d
@ -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
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user