Skip to content

Commit

Permalink
Merge pull request #657 from sputn1ck/fix_leapyear_bug
Browse files Browse the repository at this point in the history
loopdb: fix leapyear parsing
  • Loading branch information
sputn1ck authored Oct 31, 2023
2 parents 6eebf9f + b8ada04 commit e093a0c
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 0 deletions.
12 changes: 12 additions & 0 deletions loopdb/sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,18 @@ func TestTimeConversions(t *testing.T) {
2023, 8, 4, 8, 7, 49, 0, time.UTC,
),
},
{
timeString: "2188-02-29 15:34:23.847906176 +0000 UTC",
expectedTime: time.Date(
2023, 2, 28, 15, 34, 23, 847906176, time.UTC,
),
},
{
timeString: "2188-02-29T16:07:49+08:00",
expectedTime: time.Date(
2023, 2, 28, 8, 7, 49, 0, time.UTC,
),
},
}

for _, test := range tests {
Expand Down
55 changes: 55 additions & 0 deletions loopdb/sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,26 @@ func fixTimeStamp(dateTimeStr string) (time.Time, error) {
)
}

// If the year is a leap year and the date is 29th of February, we
// need to change it to 28th of February. Otherwise, the time.Parse
// function will fail, as a non-leap year cannot have 29th of February.
day, month, err := extractDayAndMonth(dateTimeStr)
if err != nil {
return time.Time{}, fmt.Errorf("unable to parse timestamp day "+
"and month %v: %v", dateTimeStr, err)
}

if !isLeapYear(thisYear) &&
month == 2 && day == 29 {

dateTimeStr = strings.Replace(
dateTimeStr,
fmt.Sprintf("%d-02-29", thisYear),
fmt.Sprintf("%d-02-28", thisYear),
1,
)
}

parsedTime, err := parseLayouts(defaultLayouts(), dateTimeStr)
if err != nil {
return time.Time{}, fmt.Errorf("unable to parse timestamp %v: %v",
Expand Down Expand Up @@ -403,3 +423,38 @@ func getTimeStampYear(dateTimeStr string) (int, error) {

return year, nil
}

// extractDayAndMonth extracts the day and month from a date string.
func extractDayAndMonth(dateStr string) (int, int, error) {
// Split the date string into parts using various delimiters.
parts := strings.FieldsFunc(dateStr, func(r rune) bool {
return r == '-' || r == ' ' || r == 'T' || r == ':' || r == '+' || r == 'Z'
})

if len(parts) < 3 {
return 0, 0, fmt.Errorf("Invalid date format: %s", dateStr)
}

// Extract year, month, and day from the parts.
_, err := strconv.Atoi(parts[0])
if err != nil {
return 0, 0, err
}

month, err := strconv.Atoi(parts[1])
if err != nil {
return 0, 0, err
}

day, err := strconv.Atoi(parts[2])
if err != nil {
return 0, 0, err
}

return day, month, nil
}

// isLeapYear returns true if the year is a leap year.
func isLeapYear(year int) bool {
return (year%4 == 0 && year%100 != 0) || (year%400 == 0)
}

0 comments on commit e093a0c

Please sign in to comment.