You've already forked parse_datetime
mirror of
https://github.com/uutils/parse_datetime.git
synced 2026-06-10 16:13:15 -07:00
parse_datetime: relative Year overflow for leap years
This commit is contained in:
committed by
Sylvestre Ledru
parent
dbfdea454f
commit
14bbd4e848
+14
-13
@@ -280,20 +280,21 @@ impl DateTimeBuilder {
|
||||
|
||||
// 4d. Apply relative adjustments.
|
||||
for rel in self.relative {
|
||||
let desired_day = dt.day();
|
||||
dt = if let relative::Relative::Months(x) = rel {
|
||||
// GNU way of calculating relative Months
|
||||
// GNU changes the Month and then checks if the target Month has
|
||||
// this day. If this day does not exist in the target month it overflows
|
||||
// the difference
|
||||
dt = dt.checked_add::<Span>(Span::new().try_months(x)?)?;
|
||||
if desired_day != dt.day() {
|
||||
dt = dt.checked_add((desired_day - dt.day()).days())?;
|
||||
dt = match rel {
|
||||
relative::Relative::Years(_) | relative::Relative::Months(_) => {
|
||||
// GNU way of calculating relative months and years
|
||||
// GNU changes the month and then checks if the target month has
|
||||
// this day. If this day does not exist in the target month it overflows
|
||||
// the difference
|
||||
let desired_day = dt.day();
|
||||
dt = dt.checked_add::<Span>(rel.try_into()?)?;
|
||||
if desired_day != dt.day() {
|
||||
dt = dt.checked_add((desired_day - dt.day()).days())?;
|
||||
}
|
||||
dt
|
||||
}
|
||||
dt
|
||||
} else {
|
||||
dt.checked_add::<Span>(rel.try_into()?)?
|
||||
};
|
||||
_ => dt.checked_add::<Span>(rel.try_into()?)?,
|
||||
}
|
||||
}
|
||||
|
||||
// 4e. Apply final fixed offset.
|
||||
|
||||
+14
-2
@@ -158,8 +158,8 @@ fn test_time_months_ago(#[case] input: &str, #[case] expected: &str) {
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::from_29_feb_in_1_month("2026-02-28 1 months", "2026-03-28")]
|
||||
#[case::from_29_feb_1_month_ago("2026-02-28 1 months ago", "2026-01-28")]
|
||||
#[case::from_28_feb_in_1_month("2026-02-28 1 months", "2026-03-28")]
|
||||
#[case::from_28_feb_1_month_ago("2026-02-28 1 months ago", "2026-01-28")]
|
||||
#[case::from_31_jan_in_1_month("2026-01-31 1 months", "2026-03-03")]
|
||||
#[case::from_31_march_1_month_ago("2026-03-31 1 months ago", "2026-03-03")]
|
||||
#[case::from_15_march_1_month_ago("2026-03-15 1 months ago", "2026-02-15")]
|
||||
@@ -190,6 +190,18 @@ fn test_relative_month_time_dest_month_does_not_have_the_day(
|
||||
check_time(input, expected, "%Y-%m-%d", Some(now));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::from_29_feb_in_1_year("2024-02-29 1 year", "2025-03-01")]
|
||||
#[case::from_29_feb_1_year_ago("2024-02-29 1 year ago", "2023-03-01")]
|
||||
fn test_relative_year_time_leap_year(#[case] input: &str, #[case] expected: &str) {
|
||||
let now = "2026-01-12"
|
||||
.parse::<DateTime>()
|
||||
.unwrap()
|
||||
.to_zoned(TimeZone::UTC)
|
||||
.unwrap();
|
||||
check_time(input, expected, "%Y-%m-%d", Some(now));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::from_29_feb_in_1_month("2024-02-29 1 months", "2024-03-29")]
|
||||
#[case::from_29_feb_1_month_ago("2024-02-29 1 months ago", "2024-01-29")]
|
||||
|
||||
Reference in New Issue
Block a user