Ver Fonte

fix(date): parse RFC 3339 dates with a lower-case t or z

RFC 3339 section 5.6 allows the "T" separator and the "Z" time zone
designator to be lower case, and RFC 4287 requires Atom dates to follow
RFC 3339. time.Parse only accepts upper case, so a date such as
"2003-12-13t18:30:02z" failed to parse and the entry date fell back to
the time of the refresh.

Upper-case these two characters before trying the known layouts.
ybai08 há 1 semana atrás
pai
commit
04fc79f786
2 ficheiros alterados com 41 adições e 1 exclusões
  1. 17 1
      internal/reader/date/parser.go
  2. 24 0
      internal/reader/date/parser_test.go

+ 17 - 1
internal/reader/date/parser.go

@@ -327,7 +327,7 @@ func Parse(rawInput string) (t time.Time, err error) {
 		return time.Unix(timestamp, 0), nil
 	}
 
-	processedInput := replacer.Replace(rawInput)
+	processedInput := normalizeRFC3339Separators(replacer.Replace(rawInput))
 
 	for _, layout := range dateFormatsLocalTimesOnly {
 		if t, err = parseLocalTimeDates(layout, processedInput); err == nil {
@@ -344,6 +344,22 @@ func Parse(rawInput string) (t time.Time, err error) {
 	return t, fmt.Errorf(`date parser: failed to parse date "%s"`, rawInput)
 }
 
+// normalizeRFC3339Separators upper-cases the "t" separator and the "z" time zone
+// designator of RFC 3339 date-times. RFC 3339 section 5.6 allows them to be
+// lower case, but time.Parse only accepts upper case.
+func normalizeRFC3339Separators(value string) string {
+	if len(value) < 11 || value[4] != '-' || value[7] != '-' || (value[10] != 't' && value[10] != 'T') {
+		return value
+	}
+
+	value = value[:10] + "T" + value[11:]
+	if strings.HasSuffix(value, "z") {
+		value = value[:len(value)-1] + "Z"
+	}
+
+	return value
+}
+
 // According to Golang documentation:
 //
 // RFC822, RFC850, and RFC1123 formats should be applied only to local times.

+ 24 - 0
internal/reader/date/parser_test.go

@@ -45,6 +45,30 @@ func TestParseAtomDate(t *testing.T) {
 	}
 }
 
+func TestParseAtomDateWithLowerCaseSeparators(t *testing.T) {
+	// RFC 3339 section 5.6 allows "T" and "Z" to be lower case.
+	testCases := map[string]int64{
+		"2003-12-13t18:30:02z":      1071340202,
+		"2003-12-13T18:30:02z":      1071340202,
+		"2003-12-13t18:30:02Z":      1071340202,
+		"1985-04-12t23:20:50.52z":   482196050,
+		"1996-12-19t16:39:57-08:00": 851042397,
+		" 2003-12-13t18:30:02z\n":   1071340202,
+	}
+
+	for input, expectedTS := range testCases {
+		date, err := Parse(input)
+		if err != nil {
+			t.Errorf(`Unable to parse date %q: %v`, input, err)
+			continue
+		}
+
+		if date.Unix() != expectedTS {
+			t.Errorf(`The Unix timestamp for %q should be %v instead of %v`, input, expectedTS, date.Unix())
+		}
+	}
+}
+
 func TestParseRSSDateTimezone(t *testing.T) {
 	date, err := Parse("Fri, 31 Mar 2023 20:19:00 America/Los_Angeles")
 	if err != nil {