]> Cypherpunks repositories - gostls13.git/commitdiff
time: accept .999 in Parse
authorRuss Cox <rsc@golang.org>
Mon, 4 Jun 2012 17:09:19 +0000 (13:09 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 4 Jun 2012 17:09:19 +0000 (13:09 -0400)
The recent shuffle in parsing formats exposed probably unintentional
behavior in time.Parse, namely that it was mostly ignoring ".99999"
in the format, producing the following behavior:

fmt.Println(time.Parse("03:04:05.999 MST", "12:00:00.888 PDT")) // error (.888 unexpected)
fmt.Println(time.Parse("03:04:05.999", "12:00:00")) // error (input too short)
fmt.Println(time.Parse("03:04:05.999 MST", "12:00:00 PDT"))  // ok (extra bytes on input make it ok)

http://play.golang.org/p/ESJ1UYXzq2

API CHANGE:

This CL makes all three examples valid: ".999" can match an
empty string or else a fractional second with at most nine digits.

Fixes #3701.

R=r, r
CC=golang-dev
https://golang.org/cl/6267045

src/pkg/time/format.go
src/pkg/time/time_test.go

index b36a58b6612b9cb4b18737b3d65912d0bcf06172..46f4fbc13b55f685e751bcb3103a11dd7195b421 100644 (file)
@@ -852,10 +852,24 @@ func Parse(layout, value string) (Time, error) {
                        // It's a valid format.
                        zoneName = p
 
-               case stdFracSecond0, stdFracSecond9:
+               case stdFracSecond0:
                        ndigit := std >> stdArgShift
                        nsec, rangeErrString, err = parseNanoseconds(value, 1+ndigit)
                        value = value[1+ndigit:]
+
+               case stdFracSecond9:
+                       if len(value) < 2 || value[0] != '.' || value[1] < '0' || '9' < value[1] {
+                               // Fractional second omitted.
+                               break
+                       }
+                       // Take any number of digits, even more than asked for,
+                       // because it is what the stdSecond case would do.
+                       i := 0
+                       for i < 9 && i+1 < len(value) && '0' <= value[i+1] && value[i+1] <= '9' {
+                               i++
+                       }
+                       nsec, rangeErrString, err = parseNanoseconds(value, 1+i)
+                       value = value[1+i:]
                }
                if rangeErrString != "" {
                        return Time{}, &ParseError{alayout, avalue, stdstr, value, ": " + rangeErrString + " out of range"}
index 68e551e5f73c66cf830986715215360025b61d29..0204fc29ee7292762f7736d88717708117b7a494 100644 (file)
@@ -324,6 +324,16 @@ var parseTests = []ParseTest{
        // Leading zeros in other places should not be taken as fractional seconds.
        {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
        {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
+
+       // 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
+       // cases would succeed, but the next four would not. Go 1.1 accepts all six.
+       {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+       {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+       {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+       {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+       {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+       {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
 }
 
 func TestParse(t *testing.T) {