Skip to content

Commit e990df3

Browse files
committed
Make DateTime::checked_*_days always return Some when valid
1 parent 96bb8df commit e990df3

File tree

2 files changed

+11
-6
lines changed

2 files changed

+11
-6
lines changed

src/datetime/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,9 @@ impl<Tz: TimeZone> DateTime<Tz> {
455455
/// daylight saving time transition.
456456
#[must_use]
457457
pub fn checked_add_days(self, days: Days) -> Option<Self> {
458-
self.naive_local()
459-
.checked_add_days(days)?
458+
self.overflowing_naive_local()
459+
.checked_add_days(days)
460+
.filter(|d| d.date() <= NaiveDate::AFTER_MAX)?
460461
.and_local_timezone(TimeZone::from_offset(&self.offset))
461462
.single()
462463
}
@@ -471,8 +472,9 @@ impl<Tz: TimeZone> DateTime<Tz> {
471472
/// daylight saving time transition.
472473
#[must_use]
473474
pub fn checked_sub_days(self, days: Days) -> Option<Self> {
474-
self.naive_local()
475-
.checked_sub_days(days)?
475+
self.overflowing_naive_local()
476+
.checked_sub_days(days)
477+
.filter(|d| d.date() >= NaiveDate::BEFORE_MIN)?
476478
.and_local_timezone(TimeZone::from_offset(&self.offset))
477479
.single()
478480
}

src/naive/date.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,10 +786,13 @@ impl NaiveDate {
786786

787787
/// Add a duration of `i32` days to the date.
788788
pub(crate) const fn add_days(self, days: i32) -> Option<Self> {
789-
// fast path if the result is within the same year
789+
// Fast path if the result is within the same year.
790+
// Also `DateTime::checked_(add|sub)_days` relies on this path, because if the value remains
791+
// within the year it doesn't do a check if the year is in range.
792+
// That is useful when working with values near `DateTime::MIN` or `DateTime::MAX`.
790793
const ORDINAL_MASK: i32 = 0b1_1111_1111_0000;
791794
if let Some(ordinal) = ((self.ymdf & ORDINAL_MASK) >> 4).checked_add(days) {
792-
if ordinal > 0 && ordinal <= 365 {
795+
if ordinal > 0 && ordinal <= (365 + self.leap_year() as i32) {
793796
let year_and_flags = self.ymdf & !ORDINAL_MASK;
794797
return Some(NaiveDate { ymdf: year_and_flags | (ordinal << 4) });
795798
}

0 commit comments

Comments
 (0)