diff --git a/token/token.go b/token/token.go index 2b3d99d6..f5a5eeee 100644 --- a/token/token.go +++ b/token/token.go @@ -4,6 +4,7 @@ import ( "fmt" "strconv" "strings" + "time" ) // Character type for character @@ -600,20 +601,23 @@ func ToNumber(value string) *NumberValue { } } -func looksLikeTimeValue(value string) bool { - for i, c := range value { - switch c { - case ':', '1', '2', '3', '4', '5', '6', '7', '8', '9': - continue - case '0': - if i == 0 { - return false - } - continue +// This is a subset of the formats permitted by the regular expression +// defined at http://yaml.org/type/timestamp.html. Note that time.Parse +// cannot handle: "2001-12-14 21:59:43.10 -5" from the examples. +var timestampFormats = []string{ + time.RFC3339Nano, + "2006-01-02t15:04:05.999999999Z07:00", // RFC3339Nano with lower-case "t". + time.DateTime, + time.DateOnly, +} + +func isTimestamp(value string) bool { + for _, format := range timestampFormats { + if _, err := time.Parse(format, value); err == nil { + return true } - return false } - return true + return false } // IsNeedQuoted whether need quote for passed string or not @@ -637,7 +641,7 @@ func IsNeedQuoted(value string) bool { case ':', ' ': return true } - if looksLikeTimeValue(value) { + if isTimestamp(value) { return true } for i, c := range value { diff --git a/token/token_test.go b/token/token_test.go index 27565fbb..b3058d17 100644 --- a/token/token_test.go +++ b/token/token_test.go @@ -81,7 +81,10 @@ func TestIsNeedQuoted(t *testing.T) { "", "true", "1.234", - "1:1", + "2001-12-15T02:59:43.1Z", + "2001-12-14t21:59:43.10-05:00", + "2001-12-15 2:59:43.10", + "2002-12-14", "hoge # comment", "\\0", "#a b", @@ -128,15 +131,18 @@ func TestIsNeedQuoted(t *testing.T) { } for i, test := range needQuotedTests { if !token.IsNeedQuoted(test) { - t.Fatalf("%d: failed to quoted judge for %s", i, test) + t.Errorf("%d: failed to quoted judge for %s", i, test) } } notNeedQuotedTests := []string{ "Hello World", + // time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" from the examples. + // https://yaml.org/type/timestamp.html + "2001-12-14 21:59:43.10 -5", } for i, test := range notNeedQuotedTests { if token.IsNeedQuoted(test) { - t.Fatalf("%d: failed to quoted judge for %s", i, test) + t.Errorf("%d: failed to quoted judge for %s", i, test) } } }