Skip to content

Commit

Permalink
Fix quotation for timestamps (#515)
Browse files Browse the repository at this point in the history
Co-authored-by: shuheiktgw <s-kitagawa@mercari.com>
  • Loading branch information
shuheiktgw and shuheiktgw authored Dec 12, 2024
1 parent b5ac9c4 commit 83d3e55
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 24 deletions.
20 changes: 11 additions & 9 deletions encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ func TestEncoder(t *testing.T) {
nil,
},
{
"t2: 2018-01-09T10:40:47Z\nt4: 2098-01-09T10:40:47Z\n",
"t2: \"2018-01-09T10:40:47Z\"\nt4: \"2098-01-09T10:40:47Z\"\n",
map[string]string{
"t2": "2018-01-09T10:40:47Z",
"t4": "2098-01-09T10:40:47Z",
Expand Down Expand Up @@ -717,14 +717,16 @@ func TestEncoder(t *testing.T) {
},
}
for _, test := range tests {
var buf bytes.Buffer
enc := yaml.NewEncoder(&buf, test.options...)
if err := enc.Encode(test.value); err != nil {
t.Fatalf("%+v", err)
}
if test.source != buf.String() {
t.Fatalf("expect = [%s], actual = [%s]", test.source, buf.String())
}
t.Run(test.source, func(t *testing.T) {
var buf bytes.Buffer
enc := yaml.NewEncoder(&buf, test.options...)
if err := enc.Encode(test.value); err != nil {
t.Fatalf("%+v", err)
}
if test.source != buf.String() {
t.Fatalf("expect = [%s], actual = [%s]", test.source, buf.String())
}
})
}
}

Expand Down
33 changes: 20 additions & 13 deletions token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"strconv"
"strings"
"time"
)

// Character type for character
Expand Down Expand Up @@ -612,20 +613,26 @@ 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,

// Not in examples, but to preserve backward compatibility by quoting time values.
"15:4",
}

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
Expand All @@ -649,7 +656,7 @@ func IsNeedQuoted(value string) bool {
case ':', ' ':
return true
}
if looksLikeTimeValue(value) {
if isTimestamp(value) {
return true
}
for i, c := range value {
Expand Down
11 changes: 9 additions & 2 deletions token/token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,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",
Expand Down Expand Up @@ -128,15 +132,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)
}
}
}

0 comments on commit 83d3e55

Please sign in to comment.