Skip to content

Commit 40b0150

Browse files
committed
Add tests for datetimes where the local value is out of range
1 parent b7aef2b commit 40b0150

File tree

1 file changed

+158
-1
lines changed

1 file changed

+158
-1
lines changed

src/datetime/tests.rs

Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::naive::{NaiveDate, NaiveTime};
44
use crate::offset::{FixedOffset, TimeZone, Utc};
55
#[cfg(feature = "clock")]
66
use crate::offset::{Local, Offset};
7-
use crate::{Datelike, Days, LocalResult, Months, NaiveDateTime, Timelike};
7+
use crate::{Datelike, Days, LocalResult, Months, NaiveDateTime, Timelike, Weekday};
88

99
#[derive(Clone)]
1010
struct DstTester;
@@ -1331,6 +1331,163 @@ fn test_datetime_sub_assign() {
13311331
assert_eq!(datetime_sub, datetime - OldDuration::minutes(90));
13321332
}
13331333

1334+
#[test]
1335+
fn test_min_max_datetimes() {
1336+
let offset_min = FixedOffset::west_opt(2 * 60 * 60).unwrap();
1337+
let beyond_min = offset_min.from_utc_datetime(&NaiveDateTime::MIN);
1338+
let offset_max = FixedOffset::east_opt(2 * 60 * 60).unwrap();
1339+
let beyond_max = offset_max.from_utc_datetime(&NaiveDateTime::MAX);
1340+
let max_time = NaiveTime::from_hms_nano_opt(23, 59, 59, 999_999_999).unwrap();
1341+
1342+
assert_eq!(format!("{:?}", beyond_min), "-262144-12-31T22:00:00-02:00");
1343+
// RFC 2822 doesn't support years with more than 4 digits.
1344+
// assert_eq!(beyond_min.to_rfc2822(), "");
1345+
#[cfg(any(feature = "alloc", feature = "std"))]
1346+
assert_eq!(beyond_min.to_rfc3339(), "-262144-12-31T22:00:00-02:00");
1347+
#[cfg(any(feature = "alloc", feature = "std"))]
1348+
assert_eq!(
1349+
beyond_min.format("%Y-%m-%dT%H:%M:%S%:z").to_string(),
1350+
"-262144-12-31T22:00:00-02:00"
1351+
);
1352+
assert_eq!(beyond_min.year(), -262144);
1353+
assert_eq!(beyond_min.month(), 12);
1354+
assert_eq!(beyond_min.month0(), 11);
1355+
assert_eq!(beyond_min.day(), 31);
1356+
assert_eq!(beyond_min.day0(), 30);
1357+
assert_eq!(beyond_min.ordinal(), 366);
1358+
assert_eq!(beyond_min.ordinal0(), 365);
1359+
assert_eq!(beyond_min.weekday(), Weekday::Wed);
1360+
assert_eq!(beyond_min.iso_week().year(), -262143);
1361+
assert_eq!(beyond_min.iso_week().week(), 1);
1362+
assert_eq!(beyond_min.checked_add_days(Days::new(0)), Some(beyond_min));
1363+
assert_eq!(
1364+
beyond_min.checked_add_days(Days::new(1)),
1365+
Some(offset_min.from_utc_datetime(&(NaiveDate::MIN + Days(1)).and_time(NaiveTime::MIN)))
1366+
);
1367+
assert_eq!(beyond_min.checked_sub_days(Days::new(0)), Some(beyond_min));
1368+
assert_eq!(beyond_min.checked_sub_days(Days::new(1)), None);
1369+
assert_eq!(beyond_min.checked_add_months(Months::new(0)), Some(beyond_min));
1370+
assert_eq!(
1371+
beyond_min.checked_add_months(Months::new(1)),
1372+
Some(offset_min.from_utc_datetime(&(NaiveDate::MIN + Months(1)).and_time(NaiveTime::MIN)))
1373+
);
1374+
assert_eq!(beyond_min.checked_sub_months(Months::new(0)), Some(beyond_min));
1375+
assert_eq!(beyond_min.checked_sub_months(Months::new(1)), None);
1376+
assert_eq!(beyond_min.with_year(beyond_min.year()), Some(beyond_min));
1377+
let res = NaiveDate::MIN.with_year(2021).unwrap().and_time(NaiveTime::MIN) + offset_min;
1378+
assert_eq!(beyond_min.with_year(2020), offset_min.from_local_datetime(&res).single());
1379+
assert_eq!(
1380+
offset_min
1381+
.from_utc_datetime(
1382+
&NaiveDate::from_ymd_opt(2023, 1, 1).unwrap().and_time(NaiveTime::MIN)
1383+
)
1384+
.with_year(NaiveDate::MIN.year() - 1),
1385+
Some(beyond_min)
1386+
);
1387+
assert_eq!(beyond_min.with_month(beyond_min.month()), Some(beyond_min));
1388+
assert_eq!(beyond_min.with_month(3), None);
1389+
assert_eq!(beyond_min.with_month0(beyond_min.month0()), Some(beyond_min));
1390+
assert_eq!(beyond_min.with_month0(3), None);
1391+
assert_eq!(beyond_min.with_day(beyond_min.day()), Some(beyond_min));
1392+
assert_eq!(beyond_min.with_day(15), None);
1393+
assert_eq!(beyond_min.with_day0(beyond_min.day0()), Some(beyond_min));
1394+
assert_eq!(beyond_min.with_day0(15), None);
1395+
assert_eq!(beyond_min.with_ordinal(beyond_min.ordinal()), Some(beyond_min));
1396+
assert_eq!(beyond_min.with_ordinal(200), None);
1397+
assert_eq!(beyond_min.with_ordinal0(beyond_min.ordinal0()), Some(beyond_min));
1398+
assert_eq!(beyond_min.with_ordinal0(200), None);
1399+
assert_eq!(beyond_min.hour(), 22);
1400+
assert_eq!(beyond_min.minute(), 0);
1401+
assert_eq!(beyond_min.second(), 0);
1402+
assert_eq!(beyond_min.nanosecond(), 0);
1403+
assert_eq!(beyond_min.with_hour(beyond_min.hour()), Some(beyond_min));
1404+
assert_eq!(beyond_min.with_hour(23), beyond_min.checked_add_signed(OldDuration::hours(1)));
1405+
assert_eq!(beyond_min.with_hour(5), None);
1406+
assert_eq!(beyond_min.with_minute(0), Some(beyond_min));
1407+
assert_eq!(beyond_min.with_second(0), Some(beyond_min));
1408+
assert_eq!(beyond_min.with_nanosecond(0), Some(beyond_min));
1409+
1410+
assert_eq!(format!("{:?}", beyond_max), "+262143-01-01T01:59:59.999999999+02:00");
1411+
// RFC 2822 doesn't support years with more than 4 digits.
1412+
// assert_eq!(beyond_max.to_rfc2822(), "");
1413+
#[cfg(any(feature = "alloc", feature = "std"))]
1414+
assert_eq!(beyond_max.to_rfc3339(), "+262143-01-01T01:59:59.999999999+02:00");
1415+
#[cfg(any(feature = "alloc", feature = "std"))]
1416+
assert_eq!(
1417+
beyond_max.format("%Y-%m-%dT%H:%M:%S%.9f%:z").to_string(),
1418+
"+262143-01-01T01:59:59.999999999+02:00"
1419+
);
1420+
assert_eq!(beyond_max.year(), 262143);
1421+
assert_eq!(beyond_max.month(), 1);
1422+
assert_eq!(beyond_max.month0(), 0);
1423+
assert_eq!(beyond_max.day(), 1);
1424+
assert_eq!(beyond_max.day0(), 0);
1425+
assert_eq!(beyond_max.ordinal(), 1);
1426+
assert_eq!(beyond_max.ordinal0(), 0);
1427+
assert_eq!(beyond_max.weekday(), Weekday::Tue);
1428+
assert_eq!(beyond_max.iso_week().year(), 262143);
1429+
assert_eq!(beyond_max.iso_week().week(), 1);
1430+
assert_eq!(beyond_max.checked_add_days(Days::new(0)), Some(beyond_max));
1431+
assert_eq!(beyond_max.checked_add_days(Days::new(1)), None);
1432+
assert_eq!(beyond_max.checked_sub_days(Days::new(0)), Some(beyond_max));
1433+
assert_eq!(
1434+
beyond_max.checked_sub_days(Days::new(1)),
1435+
Some(offset_max.from_utc_datetime(&(NaiveDate::MAX - Days(1)).and_time(max_time)))
1436+
);
1437+
assert_eq!(beyond_max.checked_add_months(Months::new(0)), Some(beyond_max));
1438+
assert_eq!(beyond_max.checked_add_months(Months::new(1)), None);
1439+
assert_eq!(beyond_max.checked_sub_months(Months::new(0)), Some(beyond_max));
1440+
assert_eq!(
1441+
beyond_max.checked_sub_months(Months::new(1)),
1442+
Some(offset_max.from_utc_datetime(&(NaiveDate::MAX - Months(1)).and_time(max_time)))
1443+
);
1444+
assert_eq!(beyond_max.with_year(beyond_max.year()), Some(beyond_max));
1445+
let res = NaiveDate::MAX.with_year(2019).unwrap().and_time(max_time) + offset_max;
1446+
assert_eq!(beyond_max.with_year(2020), offset_max.from_local_datetime(&res).single());
1447+
assert_eq!(
1448+
offset_max
1449+
.from_utc_datetime(&NaiveDate::from_ymd_opt(2023, 12, 31).unwrap().and_time(max_time))
1450+
.with_year(NaiveDate::MAX.year() + 1),
1451+
Some(beyond_max)
1452+
);
1453+
assert_eq!(beyond_max.with_month(beyond_max.month()), Some(beyond_max));
1454+
assert_eq!(beyond_max.with_month(3), None);
1455+
assert_eq!(beyond_max.with_month0(beyond_max.month0()), Some(beyond_max));
1456+
assert_eq!(beyond_max.with_month0(3), None);
1457+
assert_eq!(beyond_max.with_day(beyond_max.day()), Some(beyond_max));
1458+
assert_eq!(beyond_max.with_day(15), None);
1459+
assert_eq!(beyond_max.with_day0(beyond_max.day0()), Some(beyond_max));
1460+
assert_eq!(beyond_max.with_day0(15), None);
1461+
assert_eq!(beyond_max.with_ordinal(beyond_max.ordinal()), Some(beyond_max));
1462+
assert_eq!(beyond_max.with_ordinal(200), None);
1463+
assert_eq!(beyond_max.with_ordinal0(beyond_max.ordinal0()), Some(beyond_max));
1464+
assert_eq!(beyond_max.with_ordinal0(200), None);
1465+
assert_eq!(beyond_max.hour(), 1);
1466+
assert_eq!(beyond_max.minute(), 59);
1467+
assert_eq!(beyond_max.second(), 59);
1468+
assert_eq!(beyond_max.nanosecond(), 999_999_999);
1469+
assert_eq!(beyond_max.with_hour(beyond_max.hour()), Some(beyond_max));
1470+
assert_eq!(beyond_max.with_hour(0), beyond_max.checked_sub_signed(OldDuration::hours(1)));
1471+
assert_eq!(beyond_max.with_hour(5), None);
1472+
assert_eq!(beyond_max.with_minute(beyond_max.minute()), Some(beyond_max));
1473+
assert_eq!(beyond_max.with_second(beyond_max.second()), Some(beyond_max));
1474+
assert_eq!(beyond_max.with_nanosecond(beyond_max.nanosecond()), Some(beyond_max));
1475+
}
1476+
1477+
#[test]
1478+
#[should_panic]
1479+
fn test_local_beyond_min_datetime() {
1480+
let min = FixedOffset::west_opt(2 * 60 * 60).unwrap().from_utc_datetime(&NaiveDateTime::MIN);
1481+
let _ = min.naive_local();
1482+
}
1483+
1484+
#[test]
1485+
#[should_panic]
1486+
fn test_local_beyond_max_datetime() {
1487+
let max = FixedOffset::east_opt(2 * 60 * 60).unwrap().from_utc_datetime(&NaiveDateTime::MAX);
1488+
let _ = max.naive_local();
1489+
}
1490+
13341491
#[test]
13351492
#[cfg(feature = "clock")]
13361493
fn test_datetime_sub_assign_local() {

0 commit comments

Comments
 (0)