From a272d761959bf32da652c938c0594a5357f83ab7 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sat, 29 Jul 2023 10:55:32 +0200 Subject: [PATCH 1/2] Add benchmark --- bench/benches/chrono.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) 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")] From 28c85aa7e4f4ea9f165659c51f22d49090b0612b Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sat, 29 Jul 2023 10:44:56 +0200 Subject: [PATCH 2/2] Optimize `NaiveDate::add_days` for small values --- src/naive/date.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) 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());