Skip to content

Commit

Permalink
fix(date test): Fail with invalid datetime
Browse files Browse the repository at this point in the history
Copies date checking functionality from go.time.go to verify that the
provided date is indeed valid for a given year, accounting for leap
years.

Resolves: part of pelletier#613
  • Loading branch information
jidicula committed Oct 16, 2021
1 parent 85f5d56 commit ce30c37
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
61 changes: 61 additions & 0 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func parseLocalDate(b []byte) (LocalDate, error) {

date.Day = parseDecimalDigits(b[8:10])

if !isValidDate(date.Year, time.Month(date.Month), date.Day) {
return LocalDate{}, newDecodeError(b, "impossible date")
}

return date, nil
}

Expand Down Expand Up @@ -137,6 +141,10 @@ func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
}
dt.LocalTime = t

if !isValidDate(dt.Year, time.Month(dt.Month), dt.Day) {
return LocalDateTime{}, rest, newDecodeError(b, "impossible date")
}

return dt, rest, nil
}

Expand Down Expand Up @@ -330,3 +338,56 @@ func checkAndRemoveUnderscores(b []byte) ([]byte, error) {

return cleaned, nil
}

// isValidDate checks if a provided date is a date that exists.
func isValidDate(year int, month time.Month, day int) bool {
if day > daysIn(month, year) {
return false
}
return true
}

const (
January time.Month = 1 + iota
February
March
April
May
June
July
August
September
October
November
December
)

// daysBefore[m] counts the number of days in a non-leap year
// before month m begins. There is an entry for m=12, counting
// the number of days before January of next year (365).
var daysBefore = [...]int32{
0,
31,
31 + 28,
31 + 28 + 31,
31 + 28 + 31 + 30,
31 + 28 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
}

func daysIn(m time.Month, year int) int {
if m == February && isLeap(year) {
return 29
}
return int(daysBefore[m] - daysBefore[m-1])
}

func isLeap(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
5 changes: 5 additions & 0 deletions unmarshaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2091,6 +2091,11 @@ world'`,
desc: "multiline basic string with unfinished escape sequence after the first escape code",
data: "a = \"\"\"\\t\\",
},
{
desc: `impossible date-day`,
data: `A = 2021-03-40T23:59:00`,
msg: `impossible date`,
},
}

for _, e := range examples {
Expand Down

0 comments on commit ce30c37

Please sign in to comment.