don't worry about the number of spaces when parsing.
allow an underscore to stand for a space or digit if the following number is >=10.
R=rsc
CC=golang-dev
https://golang.org/cl/186115
diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go
index 8f81df9..745d9fb 100644
--- a/src/pkg/time/format.go
+++ b/src/pkg/time/format.go
@@ -2,6 +2,7 @@
import (
"bytes"
+ "once"
"os"
"strconv"
)
@@ -14,12 +15,16 @@
// These are predefined layouts for use in Time.Format.
// The standard time used in the layouts is:
-// Mon Jan 2 15:04:05 MST 2006 (MST is GMT-0700)
+// Mon Jan 2 15:04:05 MST 2006 (MST is GMT-0700)
// which is Unix time 1136243045.
// (Think of it as 01/02 03:04:05PM '06 -0700.)
+// An underscore _ represents a space that
+// may be replaced by a digit if the following number
+// (a day) has two digits; for compatibility with
+// fixed-width Unix time formats.
const (
- ANSIC = "Mon Jan 2 15:04:05 2006"
- UnixDate = "Mon Jan 2 15:04:05 MST 2006"
+ ANSIC = "Mon Jan _2 15:04:05 2006"
+ UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
Kitchen = "3:04PM"
@@ -36,6 +41,7 @@
stdLongWeekDay = "Monday"
stdWeekDay = "Mon"
stdDay = "2"
+ stdUnderDay = "_2"
stdZeroDay = "02"
stdHour = "15"
stdHour12 = "3"
@@ -118,20 +124,24 @@
switch {
case '0' <= c && c <= '9':
return numeric
+ case c == '_': // underscore; treated like a number when printing
+ return numeric
case 'a' <= c && c < 'z', 'A' <= c && c <= 'Z':
return alphabetic
}
return separator
}
-func zeroPad(i int) string {
+func pad(i int, padding string) string {
s := strconv.Itoa(i)
if i < 10 {
- s = "0" + s
+ s = padding + s
}
return s
}
+func zeroPad(i int) string { return pad(i, "0") }
+
// Format returns a textual representation of the time value formatted
// according to layout. The layout defines the format by showing the
// representation of a standard time, which is then used to describe
@@ -168,6 +178,8 @@
p = longDayNames[t.Weekday]
case stdDay:
p = strconv.Itoa(t.Day)
+ case stdUnderDay:
+ p = pad(t.Day, " ")
case stdZeroDay:
p = zeroPad(t.Day)
case stdHour:
@@ -250,6 +262,21 @@
strconv.Quote(e.Value) + e.Message
}
+// To simplify comparison, collapse an initial run of spaces into a single space.
+func collapseSpaces(s string) string {
+ if len(s) <= 1 || s[0] != ' ' {
+ return s
+ }
+ var i int
+ for i = 1; i < len(s); i++ {
+ if s[i] != ' ' {
+ return s[i-1:]
+ }
+ }
+ return " "
+}
+
+
// Parse parses a formatted string and returns the time value it represents.
// The layout defines the format by showing the representation of a standard
// time, which is then used to describe the string to be parsed. Predefined
@@ -296,15 +323,21 @@
}
p := value[0:i]
value = value[i:]
- // Separators must match except possibly for a following minus sign (for negative years)
+ // Separators must match but:
+ // - initial run of spaces is treated as a single space
+ // - there could be a following minus sign for negative years
if pieceType == separator {
if len(p) != len(reference) {
// must be exactly a following minus sign
- if len(p) != len(reference)+1 || p[len(p)-1] != '-' {
- return nil, &ParseError{Layout: alayout, Value: avalue, Message: formatErr + alayout}
+ pp := collapseSpaces(p)
+ rr := collapseSpaces(reference)
+ if pp != rr {
+ if len(pp) != len(rr)+1 || p[len(pp)-1] != '-' {
+ return nil, &ParseError{Layout: alayout, Value: avalue, Message: formatErr + alayout}
+ }
+ nextIsYear = true
+ continue
}
- nextIsYear = true
- continue
}
}
var err os.Error
@@ -335,7 +368,7 @@
t.Weekday, err = lookup(shortDayNames, p)
case stdLongWeekDay:
t.Weekday, err = lookup(longDayNames, p)
- case stdDay, stdZeroDay:
+ case stdDay, stdUnderDay, stdZeroDay:
t.Day, err = strconv.Atoi(p)
if t.Day < 0 || 31 < t.Day {
// TODO: be more thorough in date check?
@@ -422,6 +455,7 @@
// It's a valid format.
t.Zone = p
// Can we find it in the table?
+ once.Do(setupZone)
for _, z := range zones {
if p == z.zone.name {
t.ZoneOffset = z.zone.utcoff
diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go
index dab6d20..5036ceb 100644
--- a/src/pkg/time/time_test.go
+++ b/src/pkg/time/time_test.go
@@ -165,6 +165,9 @@
ParseTest{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true},
ParseTest{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true},
ParseTest{"ISO8601", ISO8601, "2010-02-04T21:00:57-0800", true, false},
+ // Amount of white space should not matter.
+ ParseTest{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true},
+ ParseTest{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true},
}
func TestParse(t *testing.T) {