diff --git a/bench/benches/chrono.rs b/bench/benches/chrono.rs index 8cf7b15616..483549f95d 100644 --- a/bench/benches/chrono.rs +++ b/bench/benches/chrono.rs @@ -6,7 +6,7 @@ use chrono::format::StrftimeItems; use chrono::prelude::*; #[cfg(feature = "unstable-locales")] use chrono::Locale; -use chrono::{DateTime, FixedOffset, Local, Utc, __BenchYearFlags}; +use chrono::{DateTime, Duration, FixedOffset, Local, Utc, __BenchYearFlags}; fn bench_datetime_parse_from_rfc2822(c: &mut Criterion) { c.bench_function("bench_datetime_parse_from_rfc2822", |b| { @@ -195,6 +195,15 @@ fn bench_format_manual(c: &mut Criterion) { }) }); } + +fn bench_naivedate_add_signed(c: &mut Criterion) { + let date = NaiveDate::from_ymd_opt(2023, 7, 29).unwrap(); + let extra = Duration::days(25); + c.bench_function("bench_naivedate_add_signed", |b| { + b.iter(|| black_box(date).checked_add_signed(extra).unwrap()) + }); +} + criterion_group!( benches, bench_datetime_parse_from_rfc2822, @@ -210,6 +219,7 @@ criterion_group!( bench_format, bench_format_with_items, bench_format_manual, + bench_naivedate_add_signed, ); #[cfg(feature = "unstable-locales")] diff --git a/src/naive/date.rs b/src/naive/date.rs index 860593498d..0dcb36fcda 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -782,9 +782,15 @@ impl NaiveDate { /// Add a duration of `i32` days to the date. pub(crate) const fn add_days(self, days: i32) -> Option { - if days == 0 { - return Some(self); + // fast path if the result is within the same year + const ORDINAL_MASK: i32 = 0b1_1111_1111_0000; + if let Some(ordinal) = ((self.ymdf & ORDINAL_MASK) >> 4).checked_add(days) { + if ordinal > 0 && ordinal <= 365 { + let year_and_flags = self.ymdf & !ORDINAL_MASK; + return Some(NaiveDate { ymdf: year_and_flags | (ordinal << 4) }); + } } + // do the full check let year = self.year(); let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal());