Use overflowing_naive_local in map_local

This fixes out-of-range panics in all the `with_*` methods that use `map_local`.
This commit is contained in:
Paul Dicker 2023-05-19 18:10:01 +02:00 committed by Paul Dicker
parent e6580db095
commit e28f2afa70
2 changed files with 51 additions and 1 deletions

View File

@ -750,7 +750,9 @@ fn map_local<Tz: TimeZone, F>(dt: &DateTime<Tz>, mut f: F) -> Option<DateTime<Tz
where
F: FnMut(NaiveDateTime) -> Option<NaiveDateTime>,
{
f(dt.naive_local()).and_then(|datetime| dt.timezone().from_local_datetime(&datetime).single())
f(dt.overflowing_naive_local())
.and_then(|datetime| dt.timezone().from_local_datetime(&datetime).single())
.filter(|dt| dt >= &DateTime::<Utc>::MIN_UTC && dt <= &DateTime::<Utc>::MAX_UTC)
}
impl DateTime<FixedOffset> {

View File

@ -1389,6 +1389,54 @@ fn test_min_max_getters() {
assert_eq!(beyond_max.nanosecond(), 999_999_999);
}
#[test]
fn test_min_max_setters() {
let offset_min = FixedOffset::west_opt(2 * 60 * 60).unwrap();
let beyond_min = offset_min.from_utc_datetime(&NaiveDateTime::MIN);
let offset_max = FixedOffset::east_opt(2 * 60 * 60).unwrap();
let beyond_max = offset_max.from_utc_datetime(&NaiveDateTime::MAX);
assert_eq!(beyond_min.with_year(2020).unwrap().year(), 2020);
assert_eq!(beyond_min.with_month(beyond_min.month()), Some(beyond_min));
assert_eq!(beyond_min.with_month(3), None);
assert_eq!(beyond_min.with_month0(beyond_min.month0()), Some(beyond_min));
assert_eq!(beyond_min.with_month0(3), None);
assert_eq!(beyond_min.with_day(beyond_min.day()), Some(beyond_min));
assert_eq!(beyond_min.with_day(15), None);
assert_eq!(beyond_min.with_day0(beyond_min.day0()), Some(beyond_min));
assert_eq!(beyond_min.with_day0(15), None);
assert_eq!(beyond_min.with_ordinal(beyond_min.ordinal()), Some(beyond_min));
assert_eq!(beyond_min.with_ordinal(200), None);
assert_eq!(beyond_min.with_ordinal0(beyond_min.ordinal0()), Some(beyond_min));
assert_eq!(beyond_min.with_ordinal0(200), None);
assert_eq!(beyond_min.with_hour(beyond_min.hour()), Some(beyond_min));
assert_eq!(beyond_min.with_hour(23), beyond_min.checked_add_signed(OldDuration::hours(1)));
assert_eq!(beyond_min.with_hour(5), None);
assert_eq!(beyond_min.with_minute(0), Some(beyond_min));
assert_eq!(beyond_min.with_second(0), Some(beyond_min));
assert_eq!(beyond_min.with_nanosecond(0), Some(beyond_min));
assert_eq!(beyond_max.with_year(2020).unwrap().year(), 2020);
assert_eq!(beyond_max.with_month(beyond_max.month()), Some(beyond_max));
assert_eq!(beyond_max.with_month(3), None);
assert_eq!(beyond_max.with_month0(beyond_max.month0()), Some(beyond_max));
assert_eq!(beyond_max.with_month0(3), None);
assert_eq!(beyond_max.with_day(beyond_max.day()), Some(beyond_max));
assert_eq!(beyond_max.with_day(15), None);
assert_eq!(beyond_max.with_day0(beyond_max.day0()), Some(beyond_max));
assert_eq!(beyond_max.with_day0(15), None);
assert_eq!(beyond_max.with_ordinal(beyond_max.ordinal()), Some(beyond_max));
assert_eq!(beyond_max.with_ordinal(200), None);
assert_eq!(beyond_max.with_ordinal0(beyond_max.ordinal0()), Some(beyond_max));
assert_eq!(beyond_max.with_ordinal0(200), None);
assert_eq!(beyond_max.with_hour(beyond_max.hour()), Some(beyond_max));
assert_eq!(beyond_max.with_hour(0), beyond_max.checked_sub_signed(OldDuration::hours(1)));
assert_eq!(beyond_max.with_hour(5), None);
assert_eq!(beyond_max.with_minute(beyond_max.minute()), Some(beyond_max));
assert_eq!(beyond_max.with_second(beyond_max.second()), Some(beyond_max));
assert_eq!(beyond_max.with_nanosecond(beyond_max.nanosecond()), Some(beyond_max));
}
#[test]
#[should_panic]
fn test_local_beyond_min_datetime() {