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 25, 2023
1 parent b7aef2b commit 40b0150
Showing 1 changed file with 158 additions and 1 deletion.
159 changes: 158 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 @@ -1331,6 +1331,163 @@ 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 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);
let max_time = NaiveTime::from_hms_nano_opt(23, 59, 59, 999_999_999).unwrap();

assert_eq!(format!("{:?}", beyond_min), "-262144-12-31T22:00:00-02:00");
// RFC 2822 doesn't support years with more than 4 digits.
// assert_eq!(beyond_min.to_rfc2822(), "");
#[cfg(any(feature = "alloc", feature = "std"))]
assert_eq!(beyond_min.to_rfc3339(), "-262144-12-31T22:00:00-02:00");
#[cfg(any(feature = "alloc", feature = "std"))]
assert_eq!(
beyond_min.format("%Y-%m-%dT%H:%M:%S%:z").to_string(),
"-262144-12-31T22:00:00-02:00"
);
assert_eq!(beyond_min.year(), -262144);
assert_eq!(beyond_min.month(), 12);
assert_eq!(beyond_min.month0(), 11);
assert_eq!(beyond_min.day(), 31);
assert_eq!(beyond_min.day0(), 30);
assert_eq!(beyond_min.ordinal(), 366);
assert_eq!(beyond_min.ordinal0(), 365);
assert_eq!(beyond_min.weekday(), Weekday::Wed);
assert_eq!(beyond_min.iso_week().year(), -262143);
assert_eq!(beyond_min.iso_week().week(), 1);
assert_eq!(beyond_min.checked_add_days(Days::new(0)), Some(beyond_min));
assert_eq!(
beyond_min.checked_add_days(Days::new(1)),
Some(offset_min.from_utc_datetime(&(NaiveDate::MIN + Days(1)).and_time(NaiveTime::MIN)))
);
assert_eq!(beyond_min.checked_sub_days(Days::new(0)), Some(beyond_min));
assert_eq!(beyond_min.checked_sub_days(Days::new(1)), None);
assert_eq!(beyond_min.checked_add_months(Months::new(0)), Some(beyond_min));
assert_eq!(
beyond_min.checked_add_months(Months::new(1)),
Some(offset_min.from_utc_datetime(&(NaiveDate::MIN + Months(1)).and_time(NaiveTime::MIN)))
);
assert_eq!(beyond_min.checked_sub_months(Months::new(0)), Some(beyond_min));
assert_eq!(beyond_min.checked_sub_months(Months::new(1)), None);
assert_eq!(beyond_min.with_year(beyond_min.year()), Some(beyond_min));
let res = NaiveDate::MIN.with_year(2021).unwrap().and_time(NaiveTime::MIN) + offset_min;
assert_eq!(beyond_min.with_year(2020), offset_min.from_local_datetime(&res).single());
assert_eq!(
offset_min
.from_utc_datetime(
&NaiveDate::from_ymd_opt(2023, 1, 1).unwrap().and_time(NaiveTime::MIN)
)
.with_year(NaiveDate::MIN.year() - 1),
Some(beyond_min)
);
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.hour(), 22);
assert_eq!(beyond_min.minute(), 0);
assert_eq!(beyond_min.second(), 0);
assert_eq!(beyond_min.nanosecond(), 0);
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!(format!("{:?}", beyond_max), "+262143-01-01T01:59:59.999999999+02:00");
// RFC 2822 doesn't support years with more than 4 digits.
// assert_eq!(beyond_max.to_rfc2822(), "");
#[cfg(any(feature = "alloc", feature = "std"))]
assert_eq!(beyond_max.to_rfc3339(), "+262143-01-01T01:59:59.999999999+02:00");
#[cfg(any(feature = "alloc", feature = "std"))]
assert_eq!(
beyond_max.format("%Y-%m-%dT%H:%M:%S%.9f%:z").to_string(),
"+262143-01-01T01:59:59.999999999+02:00"
);
assert_eq!(beyond_max.year(), 262143);
assert_eq!(beyond_max.month(), 1);
assert_eq!(beyond_max.month0(), 0);
assert_eq!(beyond_max.day(), 1);
assert_eq!(beyond_max.day0(), 0);
assert_eq!(beyond_max.ordinal(), 1);
assert_eq!(beyond_max.ordinal0(), 0);
assert_eq!(beyond_max.weekday(), Weekday::Tue);
assert_eq!(beyond_max.iso_week().year(), 262143);
assert_eq!(beyond_max.iso_week().week(), 1);
assert_eq!(beyond_max.checked_add_days(Days::new(0)), Some(beyond_max));
assert_eq!(beyond_max.checked_add_days(Days::new(1)), None);
assert_eq!(beyond_max.checked_sub_days(Days::new(0)), Some(beyond_max));
assert_eq!(
beyond_max.checked_sub_days(Days::new(1)),
Some(offset_max.from_utc_datetime(&(NaiveDate::MAX - Days(1)).and_time(max_time)))
);
assert_eq!(beyond_max.checked_add_months(Months::new(0)), Some(beyond_max));
assert_eq!(beyond_max.checked_add_months(Months::new(1)), None);
assert_eq!(beyond_max.checked_sub_months(Months::new(0)), Some(beyond_max));
assert_eq!(
beyond_max.checked_sub_months(Months::new(1)),
Some(offset_max.from_utc_datetime(&(NaiveDate::MAX - Months(1)).and_time(max_time)))
);
assert_eq!(beyond_max.with_year(beyond_max.year()), Some(beyond_max));
let res = NaiveDate::MAX.with_year(2019).unwrap().and_time(max_time) + offset_max;
assert_eq!(beyond_max.with_year(2020), offset_max.from_local_datetime(&res).single());
assert_eq!(
offset_max
.from_utc_datetime(&NaiveDate::from_ymd_opt(2023, 12, 31).unwrap().and_time(max_time))
.with_year(NaiveDate::MAX.year() + 1),
Some(beyond_max)
);
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.hour(), 1);
assert_eq!(beyond_max.minute(), 59);
assert_eq!(beyond_max.second(), 59);
assert_eq!(beyond_max.nanosecond(), 999_999_999);
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() {
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

0 comments on commit 40b0150

Please sign in to comment.