Skip to content

Commit

Permalink
Add tests for datetimes where the local value is out of range
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Sep 8, 2023
1 parent 5b0518a commit d904534
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 2 deletions.
153 changes: 152 additions & 1 deletion src/datetime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::naive::{NaiveDate, NaiveTime};
use crate::offset::{FixedOffset, TimeZone, Utc};
#[cfg(feature = "clock")]
use crate::offset::{Local, Offset};
use crate::{Datelike, Days, LocalResult, Months, NaiveDateTime, Timelike};
use crate::{Datelike, Days, LocalResult, Months, NaiveDateTime, Timelike, Weekday};

#[derive(Clone)]
struct DstTester;
Expand Down Expand Up @@ -1327,6 +1327,157 @@ fn test_datetime_sub_assign() {
assert_eq!(datetime_sub, datetime - OldDuration::minutes(90));
}

#[test]
fn test_min_max_datetimes() {
let offset_min = FixedOffset::west_opt(2 * 60 * 60).unwrap();
let min = offset_min.from_utc_datetime(&NaiveDateTime::MIN);
let offset_max = FixedOffset::east_opt(2 * 60 * 60).unwrap();
let max = offset_max.from_utc_datetime(&NaiveDateTime::MAX);

assert_eq!(format!("{:?}", min), "-262144-12-31T22:00:00-02:00");
// RFC 2822 doesn't support years with more than 4 digits.
// assert_eq!(min.to_rfc2822(), "");
#[cfg(any(feature = "alloc", feature = "std"))]
assert_eq!(min.to_rfc3339(), "-262144-12-31T22:00:00-02:00");
#[cfg(any(feature = "alloc", feature = "std"))]
assert_eq!(min.format("%Y-%m-%dT%H:%M:%S%:z").to_string(), "-262144-12-31T22:00:00-02:00");
assert_eq!(min.year(), -262144);
assert_eq!(min.month(), 12);
assert_eq!(min.month0(), 11);
assert_eq!(min.day(), 31);
assert_eq!(min.day0(), 30);
assert_eq!(min.ordinal(), 366);
assert_eq!(min.ordinal0(), 365);
assert_eq!(min.weekday(), Weekday::Wed);
assert_eq!(min.iso_week().year(), -262143);
assert_eq!(min.iso_week().week(), 1);
assert_eq!(min.checked_add_days(Days::new(0)), None);
assert_eq!(
min.checked_add_days(Days::new(1)),
Some(offset_min.from_utc_datetime(&(NaiveDate::MIN + Days(1)).and_time(NaiveTime::MIN)))
);
assert_eq!(min.checked_sub_days(Days::new(0)), None);
assert_eq!(min.checked_sub_days(Days::new(1)), None);
assert_eq!(min.checked_add_months(Months::new(0)), Some(min));
assert_eq!(
min.checked_add_months(Months::new(1)),
Some(offset_min.from_utc_datetime(&(NaiveDate::MIN + Months(1)).and_time(NaiveTime::MIN)))
);
assert_eq!(min.checked_sub_months(Months::new(0)), Some(min));
assert_eq!(min.checked_sub_months(Months::new(1)), None);
assert_eq!(min.with_year(min.year()), Some(min));
assert_eq!(
min.with_year(2020),
offset_min
.from_local_datetime(
&(NaiveDate::MIN.with_year(2021).unwrap().and_time(NaiveTime::MIN) + offset_min)
)
.single()
);
assert_eq!(min.with_month(min.month()), Some(min));
assert_eq!(min.with_month(3), None);
assert_eq!(min.with_month0(min.month0()), Some(min));
assert_eq!(min.with_month0(3), None);
assert_eq!(min.with_day(min.day()), Some(min));
assert_eq!(min.with_day(15), None);
assert_eq!(min.with_day0(min.day0()), Some(min));
assert_eq!(min.with_day0(15), None);
assert_eq!(min.with_ordinal(min.ordinal()), Some(min));
assert_eq!(min.with_ordinal(200), None);
assert_eq!(min.with_ordinal0(min.ordinal0()), Some(min));
assert_eq!(min.with_ordinal0(200), None);
assert_eq!(min.hour(), 22);
assert_eq!(min.minute(), 0);
assert_eq!(min.second(), 0);
assert_eq!(min.nanosecond(), 0);
assert_eq!(min.with_hour(min.hour()), Some(min));
assert_eq!(min.with_hour(23), min.checked_add_signed(OldDuration::hours(1)));
assert_eq!(min.with_hour(5), None);
assert_eq!(min.with_minute(0), Some(min));
assert_eq!(min.with_second(0), Some(min));
assert_eq!(min.with_nanosecond(0), Some(min));

assert_eq!(format!("{:?}", max), "+262143-01-01T01:59:59.999999999+02:00");
// RFC 2822 doesn't support years with more than 4 digits.
// assert_eq!(min.to_rfc2822(), "");
#[cfg(any(feature = "alloc", feature = "std"))]
assert_eq!(max.to_rfc3339(), "+262143-01-01T01:59:59.999999999+02:00");
#[cfg(any(feature = "alloc", feature = "std"))]
assert_eq!(
max.format("%Y-%m-%dT%H:%M:%S%.9f%:z").to_string(),
"+262143-01-01T01:59:59.999999999+02:00"
);
assert_eq!(max.year(), 262143);
assert_eq!(max.month(), 1);
assert_eq!(max.month0(), 0);
assert_eq!(max.day(), 1);
assert_eq!(max.day0(), 0);
assert_eq!(max.ordinal(), 1);
assert_eq!(max.ordinal0(), 0);
assert_eq!(max.weekday(), Weekday::Tue);
assert_eq!(max.iso_week().year(), 262143);
assert_eq!(max.iso_week().week(), 1);
assert_eq!(max.checked_add_days(Days::new(0)), None);
assert_eq!(max.checked_add_days(Days::new(1)), None);
assert_eq!(max.checked_sub_days(Days::new(0)), None);
assert_eq!(
max.checked_sub_days(Days::new(1)),
Some(offset_max.from_utc_datetime(&(NaiveDate::MAX - Days(1)).and_time(NaiveTime::MAX)))
);
assert_eq!(max.checked_add_months(Months::new(0)), Some(max));
assert_eq!(max.checked_add_months(Months::new(1)), None);
assert_eq!(max.checked_sub_months(Months::new(0)), Some(max));
assert_eq!(
max.checked_sub_months(Months::new(1)),
Some(offset_max.from_utc_datetime(&(NaiveDate::MAX - Months(1)).and_time(NaiveTime::MAX)))
);
assert_eq!(max.with_year(max.year()), Some(max));
assert_eq!(
max.with_year(2020),
offset_max
.from_local_datetime(
&(NaiveDate::MAX.with_year(2019).unwrap().and_time(NaiveTime::MAX) + offset_max)
)
.single()
);
assert_eq!(max.with_month(max.month()), Some(max));
assert_eq!(max.with_month(3), None);
assert_eq!(max.with_month0(max.month0()), Some(max));
assert_eq!(max.with_month0(3), None);
assert_eq!(max.with_day(max.day()), Some(max));
assert_eq!(max.with_day(15), None);
assert_eq!(max.with_day0(max.day0()), Some(max));
assert_eq!(max.with_day0(15), None);
assert_eq!(max.with_ordinal(max.ordinal()), Some(max));
assert_eq!(max.with_ordinal(200), None);
assert_eq!(max.with_ordinal0(max.ordinal0()), Some(max));
assert_eq!(max.with_ordinal0(200), None);
assert_eq!(max.hour(), 1);
assert_eq!(max.minute(), 59);
assert_eq!(max.second(), 59);
assert_eq!(max.nanosecond(), 999_999_999);
assert_eq!(max.with_hour(max.hour()), Some(max));
assert_eq!(max.with_hour(0), max.checked_sub_signed(OldDuration::hours(1)));
assert_eq!(max.with_hour(5), None);
assert_eq!(max.with_minute(max.minute()), Some(max));
assert_eq!(max.with_second(max.second()), Some(max));
assert_eq!(max.with_nanosecond(max.nanosecond()), Some(max));
}

#[test]
#[should_panic]
fn test_local_beyond_min_datetime() {
let min = FixedOffset::west_opt(2 * 60 * 60).unwrap().from_utc_datetime(&NaiveDateTime::MIN);
let _ = min.naive_local();
}

#[test]
#[should_panic]
fn test_local_beyond_max_datetime() {
let max = FixedOffset::east_opt(2 * 60 * 60).unwrap().from_utc_datetime(&NaiveDateTime::MAX);
let _ = max.naive_local();
}

#[test]
#[cfg(feature = "clock")]
fn test_datetime_sub_assign_local() {
Expand Down
2 changes: 1 addition & 1 deletion src/naive/time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ impl NaiveTime {

/// The earliest possible `NaiveTime`
pub const MIN: Self = Self { secs: 0, frac: 0 };
pub(super) const MAX: Self = Self { secs: 23 * 3600 + 59 * 60 + 59, frac: 999_999_999 };
pub(crate) const MAX: Self = Self { secs: 23 * 3600 + 59 * 60 + 59, frac: 999_999_999 };
}

impl Timelike for NaiveTime {
Expand Down

0 comments on commit d904534

Please sign in to comment.