Skip to main content

time/
date.rs

1//! The [`Date`] struct and its associated `impl`s.
2
3#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::fmt;
6use core::mem::MaybeUninit;
7use core::num::NonZero;
8use core::ops::{Add, AddAssign, Sub, SubAssign};
9use core::time::Duration as StdDuration;
10#[cfg(feature = "formatting")]
11use std::io;
12
13use deranged::{ri32, ru8, ru32};
14use num_conv::prelude::*;
15use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
16
17#[cfg(any(feature = "formatting", feature = "parsing"))]
18use crate::PrivateMethod;
19#[cfg(feature = "formatting")]
20use crate::formatting::Formattable;
21use crate::internal_macros::{const_try, const_try_opt, div_floor, ensure_ranged};
22use crate::num_fmt::{four_to_six_digits, str_from_raw_parts, two_digits_zero_padded};
23#[cfg(feature = "parsing")]
24use crate::parsing::{Parsable, Parsed};
25use crate::unit::*;
26use crate::util::{days_in_month_leap, range_validated, weeks_in_year};
27use crate::{Duration, Month, PrimitiveDateTime, Time, Weekday, error, hint};
28
29type Year = ri32<MIN_YEAR, MAX_YEAR>;
30
31/// The minimum valid year.
32pub(crate) const MIN_YEAR: i32 = if cfg!(feature = "large-dates") {
33    -999_999
34} else {
35    -9999
36};
37/// The maximum valid year.
38pub(crate) const MAX_YEAR: i32 = if cfg!(feature = "large-dates") {
39    999_999
40} else {
41    9999
42};
43
44/// Date in the proleptic Gregorian calendar.
45///
46/// By default, years between ±9999 inclusive are representable. This can be expanded to ±999,999
47/// inclusive by enabling the `large-dates` crate feature. Doing so has performance implications
48/// and introduces some ambiguities when parsing.
49#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
50pub struct Date {
51    /// Bitpacked field containing the year, ordinal, and whether the year is a leap year.
52    // |     x      | xxxxxxxxxxxxxxxxxxxxx |       x       | xxxxxxxxx |
53    // |   1 bit    |        21 bits        |     1 bit     |  9 bits   |
54    // | unassigned |         year          | is leap year? |  ordinal  |
55    // The year is 15 bits when `large-dates` is not enabled.
56    value: NonZero<i32>,
57}
58
59impl Date {
60    /// Provide a representation of `Date` as a `i32`. This value can be used for equality, hashing,
61    /// and ordering.
62    ///
63    /// **Note**: This value is explicitly signed, so do not cast this to or treat this as an
64    /// unsigned integer. Doing so will lead to incorrect results for values with differing
65    /// signs.
66    #[inline]
67    pub(crate) const fn as_i32(self) -> i32 {
68        self.value.get()
69    }
70
71    /// The Unix epoch: 1970-01-01
72    // Safety: `ordinal` is not zero.
73    pub(crate) const UNIX_EPOCH: Self = unsafe { Self::__from_ordinal_date_unchecked(1970, 1) };
74
75    /// The minimum valid `Date`.
76    ///
77    /// The value of this may vary depending on the feature flags enabled.
78    // Safety: `ordinal` is not zero.
79    pub const MIN: Self = unsafe { Self::__from_ordinal_date_unchecked(MIN_YEAR, 1) };
80
81    /// The maximum valid `Date`.
82    ///
83    /// The value of this may vary depending on the feature flags enabled.
84    // Safety: `ordinal` is not zero.
85    pub const MAX: Self = unsafe {
86        Self::__from_ordinal_date_unchecked(MAX_YEAR, range_validated::days_in_year(MAX_YEAR))
87    };
88
89    /// Construct a `Date` from its internal representation, the validity of which must be
90    /// guaranteed by the caller.
91    ///
92    /// # Safety
93    ///
94    /// - `ordinal` must be non-zero and at most the number of days in `year`
95    /// - `is_leap_year` must be `true` if and only if `year` is a leap year
96    #[inline]
97    #[track_caller]
98    const unsafe fn from_parts(year: i32, is_leap_year: bool, ordinal: u16) -> Self {
99        debug_assert!(year >= MIN_YEAR);
100        debug_assert!(year <= MAX_YEAR);
101        debug_assert!(ordinal != 0);
102        debug_assert!(ordinal <= range_validated::days_in_year(year));
103        debug_assert!(range_validated::is_leap_year(year) == is_leap_year);
104
105        Self {
106            // Safety: `ordinal` is not zero.
107            value: unsafe {
108                NonZero::new_unchecked((year << 10) | ((is_leap_year as i32) << 9) | ordinal as i32)
109            },
110        }
111    }
112
113    /// Construct a `Date` from the year and ordinal values, the validity of which must be
114    /// guaranteed by the caller.
115    ///
116    /// # Safety
117    ///
118    /// - `year` must be in the range `MIN_YEAR..=MAX_YEAR`.
119    /// - `ordinal` must be non-zero and at most the number of days in `year`.
120    #[doc(hidden)]
121    #[inline]
122    #[track_caller]
123    pub const unsafe fn __from_ordinal_date_unchecked(year: i32, ordinal: u16) -> Self {
124        // Safety: The caller must guarantee that `ordinal` is not zero and that the year is in
125        // range.
126        unsafe { Self::from_parts(year, range_validated::is_leap_year(year), ordinal) }
127    }
128
129    /// Attempt to create a `Date` from the year, month, and day.
130    ///
131    /// ```rust
132    /// # use time::{Date, Month};
133    /// assert!(Date::from_calendar_date(2019, Month::January, 1).is_ok());
134    /// assert!(Date::from_calendar_date(2019, Month::December, 31).is_ok());
135    /// ```
136    ///
137    /// ```rust
138    /// # use time::{Date, Month};
139    /// assert!(Date::from_calendar_date(2019, Month::February, 29).is_err()); // 2019 isn't a leap year.
140    /// ```
141    #[inline]
142    pub const fn from_calendar_date(
143        year: i32,
144        month: Month,
145        day: u8,
146    ) -> Result<Self, error::ComponentRange> {
147        /// Cumulative days through the beginning of a month in both common and leap years.
148        const DAYS_CUMULATIVE_COMMON_LEAP: [[u16; 12]; 2] = [
149            [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
150            [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
151        ];
152
153        ensure_ranged!(Year: year);
154
155        let is_leap_year = range_validated::is_leap_year(year);
156        match day {
157            1..=28 => {}
158            29..=31 if day <= days_in_month_leap(month as u8, is_leap_year) => hint::cold_path(),
159            _ => {
160                hint::cold_path();
161                return Err(error::ComponentRange::conditional("day"));
162            }
163        }
164
165        // Safety: `ordinal` is not zero and `is_leap_year` is correct.
166        Ok(unsafe {
167            Self::from_parts(
168                year,
169                is_leap_year,
170                DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year as usize][month as usize - 1] + day as u16,
171            )
172        })
173    }
174
175    /// Attempt to create a `Date` from the year and ordinal day number.
176    ///
177    /// ```rust
178    /// # use time::Date;
179    /// assert!(Date::from_ordinal_date(2019, 1).is_ok());
180    /// assert!(Date::from_ordinal_date(2019, 365).is_ok());
181    /// ```
182    ///
183    /// ```rust
184    /// # use time::Date;
185    /// assert!(Date::from_ordinal_date(2019, 366).is_err()); // 2019 isn't a leap year.
186    /// ```
187    #[inline]
188    pub const fn from_ordinal_date(year: i32, ordinal: u16) -> Result<Self, error::ComponentRange> {
189        ensure_ranged!(Year: year);
190
191        let is_leap_year = range_validated::is_leap_year(year);
192        match ordinal {
193            1..=365 => {}
194            366 if is_leap_year => hint::cold_path(),
195            _ => {
196                hint::cold_path();
197                return Err(error::ComponentRange::conditional("ordinal"));
198            }
199        }
200
201        // Safety: `ordinal` is not zero.
202        Ok(unsafe { Self::from_parts(year, is_leap_year, ordinal) })
203    }
204
205    /// Attempt to create a `Date` from the ISO year, week, and weekday.
206    ///
207    /// ```rust
208    /// # use time::{Date, Weekday::*};
209    /// assert!(Date::from_iso_week_date(2019, 1, Monday).is_ok());
210    /// assert!(Date::from_iso_week_date(2019, 1, Tuesday).is_ok());
211    /// assert!(Date::from_iso_week_date(2020, 53, Friday).is_ok());
212    /// ```
213    ///
214    /// ```rust
215    /// # use time::{Date, Weekday::*};
216    /// assert!(Date::from_iso_week_date(2019, 53, Monday).is_err()); // 2019 doesn't have 53 weeks.
217    /// ```
218    pub const fn from_iso_week_date(
219        year: i32,
220        week: u8,
221        weekday: Weekday,
222    ) -> Result<Self, error::ComponentRange> {
223        ensure_ranged!(Year: year);
224        match week {
225            1..=52 => {}
226            53 if week <= weeks_in_year(year) => hint::cold_path(),
227            _ => {
228                hint::cold_path();
229                return Err(error::ComponentRange::conditional("week"));
230            }
231        }
232
233        let adj_year = year - 1;
234        let raw = 365 * adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100)
235            + div_floor!(adj_year, 400);
236        let jan_4 = match (raw % 7) as i8 {
237            -6 | 1 => 8,
238            -5 | 2 => 9,
239            -4 | 3 => 10,
240            -3 | 4 => 4,
241            -2 | 5 => 5,
242            -1 | 6 => 6,
243            _ => 7,
244        };
245        let ordinal = week as i16 * 7 + weekday.number_from_monday() as i16 - jan_4;
246
247        if ordinal <= 0 {
248            // Safety: `ordinal` is not zero.
249            return Ok(unsafe {
250                Self::__from_ordinal_date_unchecked(
251                    year - 1,
252                    ordinal
253                        .cast_unsigned()
254                        .wrapping_add(range_validated::days_in_year(year - 1)),
255                )
256            });
257        }
258
259        let is_leap_year = range_validated::is_leap_year(year);
260        let days_in_year = if is_leap_year { 366 } else { 365 };
261        let ordinal = ordinal.cast_unsigned();
262        Ok(if ordinal > days_in_year {
263            // Issue #777
264            if hint::unlikely(year == MAX_YEAR) {
265                return Err(error::ComponentRange::conditional("weekday"));
266            }
267            // Safety: the year is in range and `ordinal` is not zero.
268            unsafe { Self::__from_ordinal_date_unchecked(year + 1, ordinal - days_in_year) }
269        } else {
270            // Safety: `ordinal` is not zero and `is_leap_year` is correct.
271            unsafe { Self::from_parts(year, is_leap_year, ordinal) }
272        })
273    }
274
275    /// Create a `Date` from the Julian day.
276    ///
277    /// ```rust
278    /// # use time::Date;
279    /// # use time_macros::date;
280    /// assert_eq!(Date::from_julian_day(0), Ok(date!(-4713-11-24)));
281    /// assert_eq!(Date::from_julian_day(2_451_545), Ok(date!(2000-01-01)));
282    /// assert_eq!(Date::from_julian_day(2_458_485), Ok(date!(2019-01-01)));
283    /// assert_eq!(Date::from_julian_day(2_458_849), Ok(date!(2019-12-31)));
284    /// ```
285    #[doc(alias = "from_julian_date")]
286    #[inline]
287    pub const fn from_julian_day(julian_day: i32) -> Result<Self, error::ComponentRange> {
288        type JulianDay = ri32<{ Date::MIN.to_julian_day() }, { Date::MAX.to_julian_day() }>;
289        ensure_ranged!(JulianDay: julian_day);
290        // Safety: The Julian day number is in range.
291        Ok(unsafe { Self::from_julian_day_unchecked(julian_day) })
292    }
293
294    /// Create a `Date` from the Julian day.
295    ///
296    /// # Safety
297    ///
298    /// The provided Julian day number must be between `Date::MIN.to_julian_day()` and
299    /// `Date::MAX.to_julian_day()` inclusive.
300    #[inline]
301    pub(crate) const unsafe fn from_julian_day_unchecked(julian_day: i32) -> Self {
302        debug_assert!(julian_day >= Self::MIN.to_julian_day());
303        debug_assert!(julian_day <= Self::MAX.to_julian_day());
304
305        const ERAS: u32 = 5_949;
306        // Rata Die shift:
307        const D_SHIFT: u32 = 146097 * ERAS - 1_721_060;
308        // Year shift:
309        const Y_SHIFT: u32 = 400 * ERAS;
310
311        const CEN_MUL: u32 = ((4u64 << 47) / 146_097) as u32;
312        const JUL_MUL: u32 = ((4u64 << 40) / 1_461 + 1) as u32;
313        const CEN_CUT: u32 = ((365u64 << 32) / 36_525) as u32;
314
315        let day = julian_day.cast_unsigned().wrapping_add(D_SHIFT);
316        let c_n = (day as u64 * CEN_MUL as u64) >> 15;
317        let cen = (c_n >> 32) as u32;
318        let cpt = c_n as u32;
319        let ijy = cpt > CEN_CUT || cen.is_multiple_of(4);
320        let jul = day - cen / 4 + cen;
321        let y_n = (jul as u64 * JUL_MUL as u64) >> 8;
322        let yrs = (y_n >> 32) as u32;
323        let ypt = y_n as u32;
324
325        let year = yrs.wrapping_sub(Y_SHIFT).cast_signed();
326        let ordinal = ((ypt as u64 * 1_461) >> 34) as u32 + ijy as u32;
327        let leap = yrs.is_multiple_of(4) & ijy;
328
329        // Safety: `ordinal` is not zero and `is_leap_year` is correct, so long as the Julian day
330        // number is in range, which is guaranteed by the caller.
331        unsafe { Self::from_parts(year, leap, ordinal as u16) }
332    }
333
334    /// Whether `is_leap_year(self.year())` is `true`.
335    ///
336    /// This method is optimized to take advantage of the fact that the value is pre-computed upon
337    /// construction and stored in the bitpacked struct.
338    #[inline]
339    const fn is_in_leap_year(self) -> bool {
340        (self.value.get() >> 9) & 1 == 1
341    }
342
343    /// Get the year of the date.
344    ///
345    /// ```rust
346    /// # use time_macros::date;
347    /// assert_eq!(date!(2019-01-01).year(), 2019);
348    /// assert_eq!(date!(2019-12-31).year(), 2019);
349    /// assert_eq!(date!(2020-01-01).year(), 2020);
350    /// ```
351    #[inline]
352    pub const fn year(self) -> i32 {
353        self.value.get() >> 10
354    }
355
356    /// Get the month.
357    ///
358    /// ```rust
359    /// # use time::Month;
360    /// # use time_macros::date;
361    /// assert_eq!(date!(2019-01-01).month(), Month::January);
362    /// assert_eq!(date!(2019-12-31).month(), Month::December);
363    /// ```
364    #[inline]
365    pub const fn month(self) -> Month {
366        let ordinal = self.ordinal() as u32;
367        let jan_feb_len = 59 + self.is_in_leap_year() as u32;
368
369        let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len {
370            (0, 0)
371        } else {
372            (2, jan_feb_len)
373        };
374
375        let ordinal = ordinal - ordinal_adj;
376        let month = ((ordinal * 268 + 8031) >> 13) + month_adj;
377
378        // Safety: `month` is guaranteed to be between 1 and 12 inclusive.
379        unsafe {
380            match Month::from_number(NonZero::new_unchecked(month as u8)) {
381                Ok(month) => month,
382                Err(_) => core::hint::unreachable_unchecked(),
383            }
384        }
385    }
386
387    /// Get the day of the month.
388    ///
389    /// The returned value will always be in the range `1..=31`.
390    ///
391    /// ```rust
392    /// # use time_macros::date;
393    /// assert_eq!(date!(2019-01-01).day(), 1);
394    /// assert_eq!(date!(2019-12-31).day(), 31);
395    /// ```
396    #[inline]
397    pub const fn day(self) -> u8 {
398        let ordinal = self.ordinal() as u32;
399        let jan_feb_len = 59 + self.is_in_leap_year() as u32;
400
401        let ordinal_adj = if ordinal <= jan_feb_len {
402            0
403        } else {
404            jan_feb_len
405        };
406
407        let ordinal = ordinal - ordinal_adj;
408        let month = (ordinal * 268 + 8031) >> 13;
409        let days_in_preceding_months = (month * 3917 - 3866) >> 7;
410        (ordinal - days_in_preceding_months) as u8
411    }
412
413    /// Get the day of the year.
414    ///
415    /// The returned value will always be in the range `1..=366` (`1..=365` for common years).
416    ///
417    /// ```rust
418    /// # use time_macros::date;
419    /// assert_eq!(date!(2019-01-01).ordinal(), 1);
420    /// assert_eq!(date!(2019-12-31).ordinal(), 365);
421    /// ```
422    #[inline]
423    pub const fn ordinal(self) -> u16 {
424        (self.value.get() & 0x1FF) as u16
425    }
426
427    /// Get the ISO 8601 year and week number.
428    #[inline]
429    pub(crate) const fn iso_year_week(self) -> (i32, u8) {
430        let (year, ordinal) = self.to_ordinal_date();
431
432        match ((ordinal + 10 - self.weekday().number_from_monday() as u16) / 7) as u8 {
433            0 => (year - 1, weeks_in_year(year - 1)),
434            53 if weeks_in_year(year) == 52 => (year + 1, 1),
435            week => (year, week),
436        }
437    }
438
439    /// Get the ISO week number.
440    ///
441    /// The returned value will always be in the range `1..=53`.
442    ///
443    /// ```rust
444    /// # use time_macros::date;
445    /// assert_eq!(date!(2019-01-01).iso_week(), 1);
446    /// assert_eq!(date!(2019-10-04).iso_week(), 40);
447    /// assert_eq!(date!(2020-01-01).iso_week(), 1);
448    /// assert_eq!(date!(2020-12-31).iso_week(), 53);
449    /// assert_eq!(date!(2021-01-01).iso_week(), 53);
450    /// ```
451    #[inline]
452    pub const fn iso_week(self) -> u8 {
453        self.iso_year_week().1
454    }
455
456    /// Get the week number where week 1 begins on the first Sunday.
457    ///
458    /// The returned value will always be in the range `0..=53`.
459    ///
460    /// ```rust
461    /// # use time_macros::date;
462    /// assert_eq!(date!(2019-01-01).sunday_based_week(), 0);
463    /// assert_eq!(date!(2020-01-01).sunday_based_week(), 0);
464    /// assert_eq!(date!(2020-12-31).sunday_based_week(), 52);
465    /// assert_eq!(date!(2021-01-01).sunday_based_week(), 0);
466    /// ```
467    #[inline]
468    pub const fn sunday_based_week(self) -> u8 {
469        ((self.ordinal().cast_signed() - self.weekday().number_days_from_sunday() as i16 + 6) / 7)
470            as u8
471    }
472
473    /// Get the week number where week 1 begins on the first Monday.
474    ///
475    /// The returned value will always be in the range `0..=53`.
476    ///
477    /// ```rust
478    /// # use time_macros::date;
479    /// assert_eq!(date!(2019-01-01).monday_based_week(), 0);
480    /// assert_eq!(date!(2020-01-01).monday_based_week(), 0);
481    /// assert_eq!(date!(2020-12-31).monday_based_week(), 52);
482    /// assert_eq!(date!(2021-01-01).monday_based_week(), 0);
483    /// ```
484    #[inline]
485    pub const fn monday_based_week(self) -> u8 {
486        ((self.ordinal().cast_signed() - self.weekday().number_days_from_monday() as i16 + 6) / 7)
487            as u8
488    }
489
490    /// Get the year, month, and day.
491    ///
492    /// ```rust
493    /// # use time::Month;
494    /// # use time_macros::date;
495    /// assert_eq!(
496    ///     date!(2019-01-01).to_calendar_date(),
497    ///     (2019, Month::January, 1)
498    /// );
499    /// ```
500    #[inline]
501    pub const fn to_calendar_date(self) -> (i32, Month, u8) {
502        let (year, ordinal) = self.to_ordinal_date();
503        let ordinal = ordinal as u32;
504        let jan_feb_len = 59 + self.is_in_leap_year() as u32;
505
506        let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len {
507            (0, 0)
508        } else {
509            (2, jan_feb_len)
510        };
511
512        let ordinal = ordinal - ordinal_adj;
513        let month = (ordinal * 268 + 8031) >> 13;
514        let days_in_preceding_months = (month * 3917 - 3866) >> 7;
515        let day = ordinal - days_in_preceding_months;
516        let month = month + month_adj;
517
518        (
519            year,
520            // Safety: `month` is guaranteed to be between 1 and 12 inclusive.
521            unsafe {
522                match Month::from_number(NonZero::new_unchecked(month as u8)) {
523                    Ok(month) => month,
524                    Err(_) => core::hint::unreachable_unchecked(),
525                }
526            },
527            day as u8,
528        )
529    }
530
531    /// Get the year and ordinal day number.
532    ///
533    /// ```rust
534    /// # use time_macros::date;
535    /// assert_eq!(date!(2019-01-01).to_ordinal_date(), (2019, 1));
536    /// ```
537    #[inline]
538    pub const fn to_ordinal_date(self) -> (i32, u16) {
539        (self.year(), self.ordinal())
540    }
541
542    /// Get the ISO 8601 year, week number, and weekday.
543    ///
544    /// ```rust
545    /// # use time::Weekday::*;
546    /// # use time_macros::date;
547    /// assert_eq!(date!(2019-01-01).to_iso_week_date(), (2019, 1, Tuesday));
548    /// assert_eq!(date!(2019-10-04).to_iso_week_date(), (2019, 40, Friday));
549    /// assert_eq!(date!(2020-01-01).to_iso_week_date(), (2020, 1, Wednesday));
550    /// assert_eq!(date!(2020-12-31).to_iso_week_date(), (2020, 53, Thursday));
551    /// assert_eq!(date!(2021-01-01).to_iso_week_date(), (2020, 53, Friday));
552    /// ```
553    #[inline]
554    pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
555        let (year, ordinal) = self.to_ordinal_date();
556        let weekday = self.weekday();
557
558        match ((ordinal + 10 - weekday.number_from_monday() as u16) / 7) as u8 {
559            0 => (year - 1, weeks_in_year(year - 1), weekday),
560            53 if weeks_in_year(year) == 52 => (year + 1, 1, weekday),
561            week => (year, week, weekday),
562        }
563    }
564
565    /// Get the weekday.
566    ///
567    /// ```rust
568    /// # use time::Weekday::*;
569    /// # use time_macros::date;
570    /// assert_eq!(date!(2019-01-01).weekday(), Tuesday);
571    /// assert_eq!(date!(2019-02-01).weekday(), Friday);
572    /// assert_eq!(date!(2019-03-01).weekday(), Friday);
573    /// assert_eq!(date!(2019-04-01).weekday(), Monday);
574    /// assert_eq!(date!(2019-05-01).weekday(), Wednesday);
575    /// assert_eq!(date!(2019-06-01).weekday(), Saturday);
576    /// assert_eq!(date!(2019-07-01).weekday(), Monday);
577    /// assert_eq!(date!(2019-08-01).weekday(), Thursday);
578    /// assert_eq!(date!(2019-09-01).weekday(), Sunday);
579    /// assert_eq!(date!(2019-10-01).weekday(), Tuesday);
580    /// assert_eq!(date!(2019-11-01).weekday(), Friday);
581    /// assert_eq!(date!(2019-12-01).weekday(), Sunday);
582    /// ```
583    #[inline]
584    pub const fn weekday(self) -> Weekday {
585        match self.to_julian_day() % 7 {
586            -6 | 1 => Weekday::Tuesday,
587            -5 | 2 => Weekday::Wednesday,
588            -4 | 3 => Weekday::Thursday,
589            -3 | 4 => Weekday::Friday,
590            -2 | 5 => Weekday::Saturday,
591            -1 | 6 => Weekday::Sunday,
592            val => {
593                debug_assert!(val == 0);
594                Weekday::Monday
595            }
596        }
597    }
598
599    /// Get the next calendar date.
600    ///
601    /// ```rust
602    /// # use time::Date;
603    /// # use time_macros::date;
604    /// assert_eq!(date!(2019-01-01).next_day(), Some(date!(2019-01-02)));
605    /// assert_eq!(date!(2019-01-31).next_day(), Some(date!(2019-02-01)));
606    /// assert_eq!(date!(2019-12-31).next_day(), Some(date!(2020-01-01)));
607    /// assert_eq!(Date::MAX.next_day(), None);
608    /// ```
609    #[inline]
610    pub const fn next_day(self) -> Option<Self> {
611        let is_last_day_of_year = matches!(self.value.get() & 0x3FF, 365 | 878);
612        if hint::unlikely(is_last_day_of_year) {
613            if self.value.get() == Self::MAX.value.get() {
614                None
615            } else {
616                // Safety: `ordinal` is not zero.
617                unsafe { Some(Self::__from_ordinal_date_unchecked(self.year() + 1, 1)) }
618            }
619        } else {
620            Some(Self {
621                // Safety: `ordinal` is not zero.
622                value: unsafe { NonZero::new_unchecked(self.value.get() + 1) },
623            })
624        }
625    }
626
627    /// Get the previous calendar date.
628    ///
629    /// ```rust
630    /// # use time::Date;
631    /// # use time_macros::date;
632    /// assert_eq!(date!(2019-01-02).previous_day(), Some(date!(2019-01-01)));
633    /// assert_eq!(date!(2019-02-01).previous_day(), Some(date!(2019-01-31)));
634    /// assert_eq!(date!(2020-01-01).previous_day(), Some(date!(2019-12-31)));
635    /// assert_eq!(Date::MIN.previous_day(), None);
636    /// ```
637    #[inline]
638    pub const fn previous_day(self) -> Option<Self> {
639        if hint::likely(self.ordinal() != 1) {
640            Some(Self {
641                // Safety: `ordinal` is not zero.
642                value: unsafe { NonZero::new_unchecked(self.value.get() - 1) },
643            })
644        } else if self.value.get() == Self::MIN.value.get() {
645            None
646        } else {
647            let year = self.year() - 1;
648            let is_leap_year = range_validated::is_leap_year(year);
649            let ordinal = if is_leap_year { 366 } else { 365 };
650            // Safety: `ordinal` is not zero, `is_leap_year` is correct.
651            Some(unsafe { Self::from_parts(year, is_leap_year, ordinal) })
652        }
653    }
654
655    /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
656    ///
657    /// # Panics
658    /// Panics if an overflow occurred.
659    ///
660    /// # Examples
661    /// ```
662    /// # use time::Weekday;
663    /// # use time_macros::date;
664    /// assert_eq!(
665    ///     date!(2023-06-28).next_occurrence(Weekday::Monday),
666    ///     date!(2023-07-03)
667    /// );
668    /// assert_eq!(
669    ///     date!(2023-06-19).next_occurrence(Weekday::Monday),
670    ///     date!(2023-06-26)
671    /// );
672    /// ```
673    #[inline]
674    #[track_caller]
675    pub const fn next_occurrence(self, weekday: Weekday) -> Self {
676        self.checked_next_occurrence(weekday)
677            .expect("overflow calculating the next occurrence of a weekday")
678    }
679
680    /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
681    ///
682    /// # Panics
683    /// Panics if an overflow occurred.
684    ///
685    /// # Examples
686    /// ```
687    /// # use time::Weekday;
688    /// # use time_macros::date;
689    /// assert_eq!(
690    ///     date!(2023-06-28).prev_occurrence(Weekday::Monday),
691    ///     date!(2023-06-26)
692    /// );
693    /// assert_eq!(
694    ///     date!(2023-06-19).prev_occurrence(Weekday::Monday),
695    ///     date!(2023-06-12)
696    /// );
697    /// ```
698    #[inline]
699    #[track_caller]
700    pub const fn prev_occurrence(self, weekday: Weekday) -> Self {
701        self.checked_prev_occurrence(weekday)
702            .expect("overflow calculating the previous occurrence of a weekday")
703    }
704
705    /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
706    ///
707    /// # Panics
708    /// Panics if an overflow occurred or if `n == 0`.
709    ///
710    /// # Examples
711    /// ```
712    /// # use time::Weekday;
713    /// # use time_macros::date;
714    /// assert_eq!(
715    ///     date!(2023-06-25).nth_next_occurrence(Weekday::Monday, 5),
716    ///     date!(2023-07-24)
717    /// );
718    /// assert_eq!(
719    ///     date!(2023-06-26).nth_next_occurrence(Weekday::Monday, 5),
720    ///     date!(2023-07-31)
721    /// );
722    /// ```
723    #[inline]
724    #[track_caller]
725    pub const fn nth_next_occurrence(self, weekday: Weekday, n: u8) -> Self {
726        self.checked_nth_next_occurrence(weekday, n)
727            .expect("overflow calculating the next occurrence of a weekday")
728    }
729
730    /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
731    ///
732    /// # Panics
733    /// Panics if an overflow occurred or if `n == 0`.
734    ///
735    /// # Examples
736    /// ```
737    /// # use time::Weekday;
738    /// # use time_macros::date;
739    /// assert_eq!(
740    ///     date!(2023-06-27).nth_prev_occurrence(Weekday::Monday, 3),
741    ///     date!(2023-06-12)
742    /// );
743    /// assert_eq!(
744    ///     date!(2023-06-26).nth_prev_occurrence(Weekday::Monday, 3),
745    ///     date!(2023-06-05)
746    /// );
747    /// ```
748    #[inline]
749    #[track_caller]
750    pub const fn nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Self {
751        self.checked_nth_prev_occurrence(weekday, n)
752            .expect("overflow calculating the previous occurrence of a weekday")
753    }
754
755    /// Get the Julian day for the date.
756    ///
757    /// ```rust
758    /// # use time_macros::date;
759    /// assert_eq!(date!(-4713-11-24).to_julian_day(), 0);
760    /// assert_eq!(date!(2000-01-01).to_julian_day(), 2_451_545);
761    /// assert_eq!(date!(2019-01-01).to_julian_day(), 2_458_485);
762    /// assert_eq!(date!(2019-12-31).to_julian_day(), 2_458_849);
763    /// ```
764    #[inline]
765    pub const fn to_julian_day(self) -> i32 {
766        let (year, ordinal) = self.to_ordinal_date();
767
768        // The algorithm requires a non-negative year. Add the lowest value to make it so. This is
769        // adjusted for at the end with the final subtraction.
770        let adj_year = year + 999_999;
771        let century = adj_year / 100;
772
773        let days_before_year = (1461 * adj_year as i64 / 4) as i32 - century + century / 4;
774        days_before_year + ordinal as i32 - 363_521_075
775    }
776
777    /// Computes `self + duration`, returning `None` if an overflow occurred.
778    ///
779    /// ```rust
780    /// # use time::{Date, ext::NumericalDuration};
781    /// # use time_macros::date;
782    /// assert_eq!(Date::MAX.checked_add(1.days()), None);
783    /// assert_eq!(Date::MIN.checked_add((-2).days()), None);
784    /// assert_eq!(
785    ///     date!(2020-12-31).checked_add(2.days()),
786    ///     Some(date!(2021-01-02))
787    /// );
788    /// ```
789    ///
790    /// # Note
791    ///
792    /// This function only takes whole days into account.
793    ///
794    /// ```rust
795    /// # use time::{Date, ext::NumericalDuration};
796    /// # use time_macros::date;
797    /// assert_eq!(Date::MAX.checked_add(23.hours()), Some(Date::MAX));
798    /// assert_eq!(Date::MIN.checked_add((-23).hours()), Some(Date::MIN));
799    /// assert_eq!(
800    ///     date!(2020-12-31).checked_add(23.hours()),
801    ///     Some(date!(2020-12-31))
802    /// );
803    /// assert_eq!(
804    ///     date!(2020-12-31).checked_add(47.hours()),
805    ///     Some(date!(2021-01-01))
806    /// );
807    /// ```
808    #[inline]
809    pub const fn checked_add(self, duration: Duration) -> Option<Self> {
810        let whole_days = duration.whole_days();
811        if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
812            return None;
813        }
814
815        let year = self.year();
816        let is_leap_year = self.is_in_leap_year();
817        let ordinal = self.ordinal() as i32;
818
819        let days_in_year = if is_leap_year { 366 } else { 365 };
820        let whole_days = whole_days as i32;
821
822        // Fast path for when the result is in the same year.
823        if let Some(new_ordinal) = ordinal.checked_add(whole_days)
824            && new_ordinal >= 1
825            && new_ordinal <= days_in_year
826        {
827            // Safety: `new_ordinal` is in range and `is_leap_year` is correct
828            return Some(unsafe { Self::from_parts(year, is_leap_year, new_ordinal as u16) });
829        }
830
831        let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days));
832        if let Ok(date) = Self::from_julian_day(julian_day) {
833            Some(date)
834        } else {
835            None
836        }
837    }
838
839    /// Computes `self + duration`, returning `None` if an overflow occurred.
840    ///
841    /// ```rust
842    /// # use time::{Date, ext::NumericalStdDuration};
843    /// # use time_macros::date;
844    /// assert_eq!(Date::MAX.checked_add_std(1.std_days()), None);
845    /// assert_eq!(
846    ///     date!(2020-12-31).checked_add_std(2.std_days()),
847    ///     Some(date!(2021-01-02))
848    /// );
849    /// ```
850    ///
851    /// # Note
852    ///
853    /// This function only takes whole days into account.
854    ///
855    /// ```rust
856    /// # use time::{Date, ext::NumericalStdDuration};
857    /// # use time_macros::date;
858    /// assert_eq!(Date::MAX.checked_add_std(23.std_hours()), Some(Date::MAX));
859    /// assert_eq!(
860    ///     date!(2020-12-31).checked_add_std(23.std_hours()),
861    ///     Some(date!(2020-12-31))
862    /// );
863    /// assert_eq!(
864    ///     date!(2020-12-31).checked_add_std(47.std_hours()),
865    ///     Some(date!(2021-01-01))
866    /// );
867    /// ```
868    #[inline]
869    pub const fn checked_add_std(self, duration: StdDuration) -> Option<Self> {
870        let whole_days = duration.as_secs() / Second::per_t::<u64>(Day);
871        if whole_days > i32::MAX as u64 {
872            return None;
873        }
874
875        let year = self.year();
876        let is_leap_year = self.is_in_leap_year();
877        let ordinal = self.ordinal() as i32;
878
879        let days_in_year = if is_leap_year { 366 } else { 365 };
880        let whole_days = whole_days as i32;
881
882        // Fast path for when the result is in the same year.
883        if let Some(new_ordinal) = ordinal.checked_add(whole_days)
884            && new_ordinal >= 1
885            && new_ordinal <= days_in_year
886        {
887            // Safety: `new_ordinal` is in range and `is_leap_year` is correct
888            return Some(unsafe { Self::from_parts(year, is_leap_year, new_ordinal as u16) });
889        }
890
891        let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days));
892        if let Ok(date) = Self::from_julian_day(julian_day) {
893            Some(date)
894        } else {
895            None
896        }
897    }
898
899    /// Computes `self - duration`, returning `None` if an overflow occurred.
900    ///
901    /// ```
902    /// # use time::{Date, ext::NumericalDuration};
903    /// # use time_macros::date;
904    /// assert_eq!(Date::MAX.checked_sub((-2).days()), None);
905    /// assert_eq!(Date::MIN.checked_sub(1.days()), None);
906    /// assert_eq!(
907    ///     date!(2020-12-31).checked_sub(2.days()),
908    ///     Some(date!(2020-12-29))
909    /// );
910    /// ```
911    ///
912    /// # Note
913    ///
914    /// This function only takes whole days into account.
915    ///
916    /// ```
917    /// # use time::{Date, ext::NumericalDuration};
918    /// # use time_macros::date;
919    /// assert_eq!(Date::MAX.checked_sub((-23).hours()), Some(Date::MAX));
920    /// assert_eq!(Date::MIN.checked_sub(23.hours()), Some(Date::MIN));
921    /// assert_eq!(
922    ///     date!(2020-12-31).checked_sub(23.hours()),
923    ///     Some(date!(2020-12-31))
924    /// );
925    /// assert_eq!(
926    ///     date!(2020-12-31).checked_sub(47.hours()),
927    ///     Some(date!(2020-12-30))
928    /// );
929    /// ```
930    #[inline]
931    pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
932        let whole_days = duration.whole_days();
933        if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
934            return None;
935        }
936
937        let year = self.year();
938        let is_leap_year = self.is_in_leap_year();
939        let ordinal = self.ordinal() as i32;
940
941        let days_in_year = if is_leap_year { 366 } else { 365 };
942        let whole_days = whole_days as i32;
943
944        // Fast path for when the result is in the same year.
945        if let Some(new_ordinal) = ordinal.checked_sub(whole_days)
946            && new_ordinal >= 1
947            && new_ordinal <= days_in_year
948        {
949            // Safety: `new_ordinal` is in range and `is_leap_year` is correct
950            return Some(unsafe { Self::from_parts(year, is_leap_year, new_ordinal as u16) });
951        }
952
953        let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days));
954        if let Ok(date) = Self::from_julian_day(julian_day) {
955            Some(date)
956        } else {
957            None
958        }
959    }
960
961    /// Computes `self - duration`, returning `None` if an overflow occurred.
962    ///
963    /// ```
964    /// # use time::{Date, ext::NumericalStdDuration};
965    /// # use time_macros::date;
966    /// assert_eq!(Date::MIN.checked_sub_std(1.std_days()), None);
967    /// assert_eq!(
968    ///     date!(2020-12-31).checked_sub_std(2.std_days()),
969    ///     Some(date!(2020-12-29))
970    /// );
971    /// ```
972    ///
973    /// # Note
974    ///
975    /// This function only takes whole days into account.
976    ///
977    /// ```
978    /// # use time::{Date, ext::NumericalStdDuration};
979    /// # use time_macros::date;
980    /// assert_eq!(Date::MIN.checked_sub_std(23.std_hours()), Some(Date::MIN));
981    /// assert_eq!(
982    ///     date!(2020-12-31).checked_sub_std(23.std_hours()),
983    ///     Some(date!(2020-12-31))
984    /// );
985    /// assert_eq!(
986    ///     date!(2020-12-31).checked_sub_std(47.std_hours()),
987    ///     Some(date!(2020-12-30))
988    /// );
989    /// ```
990    #[inline]
991    pub const fn checked_sub_std(self, duration: StdDuration) -> Option<Self> {
992        let whole_days = duration.as_secs() / Second::per_t::<u64>(Day);
993        if whole_days > i32::MAX as u64 {
994            return None;
995        }
996
997        let year = self.year();
998        let is_leap_year = self.is_in_leap_year();
999        let ordinal = self.ordinal() as i32;
1000
1001        let days_in_year = if is_leap_year { 366 } else { 365 };
1002        let whole_days = whole_days as i32;
1003
1004        // Fast path for when the result is in the same year.
1005        if let Some(new_ordinal) = ordinal.checked_sub(whole_days)
1006            && new_ordinal >= 1
1007            && new_ordinal <= days_in_year
1008        {
1009            // Safety: `new_ordinal` is in range and `is_leap_year` is correct
1010            return Some(unsafe { Self::from_parts(year, is_leap_year, new_ordinal as u16) });
1011        }
1012
1013        let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days));
1014        if let Ok(date) = Self::from_julian_day(julian_day) {
1015            Some(date)
1016        } else {
1017            None
1018        }
1019    }
1020
1021    /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
1022    /// Returns `None` if an overflow occurred.
1023    #[inline]
1024    pub(crate) const fn checked_next_occurrence(self, weekday: Weekday) -> Option<Self> {
1025        let day_diff = match weekday as i8 - self.weekday() as i8 {
1026            1 | -6 => 1,
1027            2 | -5 => 2,
1028            3 | -4 => 3,
1029            4 | -3 => 4,
1030            5 | -2 => 5,
1031            6 | -1 => 6,
1032            val => {
1033                debug_assert!(val == 0);
1034                7
1035            }
1036        };
1037
1038        self.checked_add(Duration::days(day_diff))
1039    }
1040
1041    /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
1042    /// Returns `None` if an overflow occurred.
1043    #[inline]
1044    pub(crate) const fn checked_prev_occurrence(self, weekday: Weekday) -> Option<Self> {
1045        let day_diff = match weekday as i8 - self.weekday() as i8 {
1046            1 | -6 => 6,
1047            2 | -5 => 5,
1048            3 | -4 => 4,
1049            4 | -3 => 3,
1050            5 | -2 => 2,
1051            6 | -1 => 1,
1052            val => {
1053                debug_assert!(val == 0);
1054                7
1055            }
1056        };
1057
1058        self.checked_sub(Duration::days(day_diff))
1059    }
1060
1061    /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
1062    /// Returns `None` if an overflow occurred or if `n == 0`.
1063    #[inline]
1064    pub(crate) const fn checked_nth_next_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
1065        if n == 0 {
1066            return None;
1067        }
1068
1069        const_try_opt!(self.checked_next_occurrence(weekday))
1070            .checked_add(Duration::weeks(n as i64 - 1))
1071    }
1072
1073    /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
1074    /// Returns `None` if an overflow occurred or if `n == 0`.
1075    #[inline]
1076    pub(crate) const fn checked_nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
1077        if n == 0 {
1078            return None;
1079        }
1080
1081        const_try_opt!(self.checked_prev_occurrence(weekday))
1082            .checked_sub(Duration::weeks(n as i64 - 1))
1083    }
1084
1085    /// Computes `self + duration`, saturating value on overflow.
1086    ///
1087    /// ```rust
1088    /// # use time::{Date, ext::NumericalDuration};
1089    /// # use time_macros::date;
1090    /// assert_eq!(Date::MAX.saturating_add(1.days()), Date::MAX);
1091    /// assert_eq!(Date::MIN.saturating_add((-2).days()), Date::MIN);
1092    /// assert_eq!(
1093    ///     date!(2020-12-31).saturating_add(2.days()),
1094    ///     date!(2021-01-02)
1095    /// );
1096    /// ```
1097    ///
1098    /// # Note
1099    ///
1100    /// This function only takes whole days into account.
1101    ///
1102    /// ```rust
1103    /// # use time::ext::NumericalDuration;
1104    /// # use time_macros::date;
1105    /// assert_eq!(
1106    ///     date!(2020-12-31).saturating_add(23.hours()),
1107    ///     date!(2020-12-31)
1108    /// );
1109    /// assert_eq!(
1110    ///     date!(2020-12-31).saturating_add(47.hours()),
1111    ///     date!(2021-01-01)
1112    /// );
1113    /// ```
1114    #[inline]
1115    pub const fn saturating_add(self, duration: Duration) -> Self {
1116        if let Some(datetime) = self.checked_add(duration) {
1117            datetime
1118        } else if duration.is_negative() {
1119            Self::MIN
1120        } else {
1121            debug_assert!(duration.is_positive());
1122            Self::MAX
1123        }
1124    }
1125
1126    /// Computes `self - duration`, saturating value on overflow.
1127    ///
1128    /// ```
1129    /// # use time::{Date, ext::NumericalDuration};
1130    /// # use time_macros::date;
1131    /// assert_eq!(Date::MAX.saturating_sub((-2).days()), Date::MAX);
1132    /// assert_eq!(Date::MIN.saturating_sub(1.days()), Date::MIN);
1133    /// assert_eq!(
1134    ///     date!(2020-12-31).saturating_sub(2.days()),
1135    ///     date!(2020-12-29)
1136    /// );
1137    /// ```
1138    ///
1139    /// # Note
1140    ///
1141    /// This function only takes whole days into account.
1142    ///
1143    /// ```
1144    /// # use time::ext::NumericalDuration;
1145    /// # use time_macros::date;
1146    /// assert_eq!(
1147    ///     date!(2020-12-31).saturating_sub(23.hours()),
1148    ///     date!(2020-12-31)
1149    /// );
1150    /// assert_eq!(
1151    ///     date!(2020-12-31).saturating_sub(47.hours()),
1152    ///     date!(2020-12-30)
1153    /// );
1154    /// ```
1155    #[inline]
1156    pub const fn saturating_sub(self, duration: Duration) -> Self {
1157        if let Some(datetime) = self.checked_sub(duration) {
1158            datetime
1159        } else if duration.is_negative() {
1160            Self::MAX
1161        } else {
1162            debug_assert!(duration.is_positive());
1163            Self::MIN
1164        }
1165    }
1166
1167    /// Replace the year. The month and day will be unchanged.
1168    ///
1169    /// ```rust
1170    /// # use time_macros::date;
1171    /// assert_eq!(
1172    ///     date!(2022-02-18).replace_year(2019),
1173    ///     Ok(date!(2019-02-18))
1174    /// );
1175    /// assert!(date!(2022-02-18).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
1176    /// assert!(date!(2022-02-18).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
1177    /// ```
1178    #[inline]
1179    #[must_use = "This method does not mutate the original `Date`."]
1180    pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1181        ensure_ranged!(Year: year);
1182
1183        let new_is_leap_year = range_validated::is_leap_year(year);
1184        let ordinal = self.ordinal();
1185
1186        // Dates in January and February are unaffected by leap years.
1187        if ordinal <= 59 {
1188            // Safety: `ordinal` is not zero and `is_leap_year` is correct.
1189            return Ok(unsafe { Self::from_parts(year, new_is_leap_year, ordinal) });
1190        }
1191
1192        match (self.is_in_leap_year(), new_is_leap_year) {
1193            (false, false) | (true, true) => {
1194                Ok(Self {
1195                    // Safety: Whether the year is leap or common, the ordinal are unchanged, with
1196                    // only the year being replaced.
1197                    value: unsafe {
1198                        NonZero::new_unchecked((year << 10) | (self.value.get() & 0x3FF))
1199                    },
1200                })
1201            }
1202            // February 29 does not exist in common years.
1203            (true, false) if ordinal == 60 => Err(error::ComponentRange::conditional("day")),
1204            // We're going from a common year to a leap year. Shift dates in March and later by
1205            // one day.
1206            // Safety: `ordinal` is not zero and `is_leap_year` is correct.
1207            (false, true) => Ok(unsafe { Self::from_parts(year, true, ordinal + 1) }),
1208            // We're going from a leap year to a common year. Shift dates in January and
1209            // February by one day.
1210            // Safety: `ordinal` is not zero and `is_leap_year` is correct.
1211            (true, false) => Ok(unsafe { Self::from_parts(year, false, ordinal - 1) }),
1212        }
1213    }
1214
1215    /// Replace the month of the year.
1216    ///
1217    /// ```rust
1218    /// # use time_macros::date;
1219    /// # use time::Month;
1220    /// assert_eq!(
1221    ///     date!(2022-02-18).replace_month(Month::January),
1222    ///     Ok(date!(2022-01-18))
1223    /// );
1224    /// assert!(date!(2022-01-30)
1225    ///     .replace_month(Month::February)
1226    ///     .is_err()); // 30 isn't a valid day in February
1227    /// ```
1228    #[inline]
1229    #[must_use = "This method does not mutate the original `Date`."]
1230    pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1231        /// Cumulative days through the beginning of a month in both common and leap years.
1232        const DAYS_CUMULATIVE_COMMON_LEAP: [[u16; 12]; 2] = [
1233            [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
1234            [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
1235        ];
1236
1237        let (year, ordinal) = self.to_ordinal_date();
1238        let mut ordinal = ordinal as u32;
1239        let is_leap_year = self.is_in_leap_year();
1240        let jan_feb_len = 59 + is_leap_year as u32;
1241
1242        if ordinal > jan_feb_len {
1243            ordinal -= jan_feb_len;
1244        }
1245        let current_month = (ordinal * 268 + 8031) >> 13;
1246        let days_in_preceding_months = (current_month * 3917 - 3866) >> 7;
1247        let day = (ordinal - days_in_preceding_months) as u8;
1248
1249        match day {
1250            1..=28 => {}
1251            29..=31 if day <= days_in_month_leap(month as u8, is_leap_year) => hint::cold_path(),
1252            _ => {
1253                hint::cold_path();
1254                return Err(error::ComponentRange::conditional("day"));
1255            }
1256        }
1257
1258        // Safety: `ordinal` is not zero and `is_leap_year` is correct.
1259        Ok(unsafe {
1260            Self::from_parts(
1261                year,
1262                is_leap_year,
1263                DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year as usize][month as usize - 1] + day as u16,
1264            )
1265        })
1266    }
1267
1268    /// Replace the day of the month.
1269    ///
1270    /// ```rust
1271    /// # use time_macros::date;
1272    /// assert_eq!(date!(2022-02-18).replace_day(1), Ok(date!(2022-02-01)));
1273    /// assert!(date!(2022-02-18).replace_day(0).is_err()); // 0 isn't a valid day
1274    /// assert!(date!(2022-02-18).replace_day(30).is_err()); // 30 isn't a valid day in February
1275    /// ```
1276    #[inline]
1277    #[must_use = "This method does not mutate the original `Date`."]
1278    pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1279        let is_leap_year = self.is_in_leap_year();
1280        match day {
1281            1..=28 => {}
1282            29..=31 if day <= days_in_month_leap(self.month() as u8, is_leap_year) => {
1283                hint::cold_path()
1284            }
1285            _ => {
1286                hint::cold_path();
1287                return Err(error::ComponentRange::conditional("day"));
1288            }
1289        }
1290
1291        // Safety: `ordinal` is not zero and `is_leap_year` is correct.
1292        Ok(unsafe {
1293            Self::from_parts(
1294                self.year(),
1295                is_leap_year,
1296                (self.ordinal().cast_signed() - self.day() as i16 + day as i16).cast_unsigned(),
1297            )
1298        })
1299    }
1300
1301    /// Replace the day of the year.
1302    ///
1303    /// ```rust
1304    /// # use time_macros::date;
1305    /// assert_eq!(date!(2022-049).replace_ordinal(1), Ok(date!(2022-001)));
1306    /// assert!(date!(2022-049).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
1307    /// assert!(date!(2022-049).replace_ordinal(366).is_err()); // 2022 isn't a leap year
1308    /// ```
1309    #[inline]
1310    #[must_use = "This method does not mutate the original `Date`."]
1311    pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1312        let is_leap_year = self.is_in_leap_year();
1313        match ordinal {
1314            1..=365 => {}
1315            366 if is_leap_year => hint::cold_path(),
1316            _ => {
1317                hint::cold_path();
1318                return Err(error::ComponentRange::conditional("ordinal"));
1319            }
1320        }
1321
1322        // Safety: `ordinal` is in range and `is_leap_year` is correct.
1323        Ok(unsafe { Self::from_parts(self.year(), is_leap_year, ordinal) })
1324    }
1325}
1326
1327/// Methods to add a [`Time`] component, resulting in a [`PrimitiveDateTime`].
1328impl Date {
1329    /// Create a [`PrimitiveDateTime`] using the existing date. The [`Time`] component will be set
1330    /// to midnight.
1331    ///
1332    /// ```rust
1333    /// # use time_macros::{date, datetime};
1334    /// assert_eq!(date!(1970-01-01).midnight(), datetime!(1970-01-01 0:00));
1335    /// ```
1336    #[inline]
1337    pub const fn midnight(self) -> PrimitiveDateTime {
1338        PrimitiveDateTime::new(self, Time::MIDNIGHT)
1339    }
1340
1341    /// Create a [`PrimitiveDateTime`] using the existing date and the provided [`Time`].
1342    ///
1343    /// ```rust
1344    /// # use time_macros::{date, datetime, time};
1345    /// assert_eq!(
1346    ///     date!(1970-01-01).with_time(time!(0:00)),
1347    ///     datetime!(1970-01-01 0:00),
1348    /// );
1349    /// ```
1350    #[inline]
1351    pub const fn with_time(self, time: Time) -> PrimitiveDateTime {
1352        PrimitiveDateTime::new(self, time)
1353    }
1354
1355    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1356    ///
1357    /// ```rust
1358    /// # use time_macros::date;
1359    /// assert!(date!(1970-01-01).with_hms(0, 0, 0).is_ok());
1360    /// assert!(date!(1970-01-01).with_hms(24, 0, 0).is_err());
1361    /// ```
1362    #[inline]
1363    pub const fn with_hms(
1364        self,
1365        hour: u8,
1366        minute: u8,
1367        second: u8,
1368    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1369        Ok(PrimitiveDateTime::new(
1370            self,
1371            const_try!(Time::from_hms(hour, minute, second)),
1372        ))
1373    }
1374
1375    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1376    ///
1377    /// ```rust
1378    /// # use time_macros::date;
1379    /// assert!(date!(1970-01-01).with_hms_milli(0, 0, 0, 0).is_ok());
1380    /// assert!(date!(1970-01-01).with_hms_milli(24, 0, 0, 0).is_err());
1381    /// ```
1382    #[inline]
1383    pub const fn with_hms_milli(
1384        self,
1385        hour: u8,
1386        minute: u8,
1387        second: u8,
1388        millisecond: u16,
1389    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1390        Ok(PrimitiveDateTime::new(
1391            self,
1392            const_try!(Time::from_hms_milli(hour, minute, second, millisecond)),
1393        ))
1394    }
1395
1396    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1397    ///
1398    /// ```rust
1399    /// # use time_macros::date;
1400    /// assert!(date!(1970-01-01).with_hms_micro(0, 0, 0, 0).is_ok());
1401    /// assert!(date!(1970-01-01).with_hms_micro(24, 0, 0, 0).is_err());
1402    /// ```
1403    #[inline]
1404    pub const fn with_hms_micro(
1405        self,
1406        hour: u8,
1407        minute: u8,
1408        second: u8,
1409        microsecond: u32,
1410    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1411        Ok(PrimitiveDateTime::new(
1412            self,
1413            const_try!(Time::from_hms_micro(hour, minute, second, microsecond)),
1414        ))
1415    }
1416
1417    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1418    ///
1419    /// ```rust
1420    /// # use time_macros::date;
1421    /// assert!(date!(1970-01-01).with_hms_nano(0, 0, 0, 0).is_ok());
1422    /// assert!(date!(1970-01-01).with_hms_nano(24, 0, 0, 0).is_err());
1423    /// ```
1424    #[inline]
1425    pub const fn with_hms_nano(
1426        self,
1427        hour: u8,
1428        minute: u8,
1429        second: u8,
1430        nanosecond: u32,
1431    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1432        Ok(PrimitiveDateTime::new(
1433            self,
1434            const_try!(Time::from_hms_nano(hour, minute, second, nanosecond)),
1435        ))
1436    }
1437}
1438
1439#[cfg(feature = "formatting")]
1440impl Date {
1441    /// Format the `Date` using the provided [format description](crate::format_description).
1442    #[inline]
1443    pub fn format_into(
1444        self,
1445        output: &mut (impl io::Write + ?Sized),
1446        format: &(impl Formattable + ?Sized),
1447    ) -> Result<usize, error::Format> {
1448        format.format_into(output, &self, &mut Default::default(), PrivateMethod)
1449    }
1450
1451    /// Format the `Date` using the provided [format description](crate::format_description).
1452    ///
1453    /// ```rust
1454    /// # use time::format_description;
1455    /// # use time_macros::date;
1456    /// let format = format_description::parse_borrowed::<3>("[year]-[month]-[day]")?;
1457    /// assert_eq!(date!(2020-01-02).format(&format)?, "2020-01-02");
1458    /// # Ok::<_, time::Error>(())
1459    /// ```
1460    #[inline]
1461    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1462        format.format(&self, &mut Default::default(), PrivateMethod)
1463    }
1464}
1465
1466#[cfg(feature = "parsing")]
1467impl Date {
1468    /// Parse a `Date` from the input using the provided [format
1469    /// description](crate::format_description).
1470    ///
1471    /// ```rust
1472    /// # use time::Date;
1473    /// # use time_macros::{date, format_description};
1474    /// let format = format_description!("[year]-[month]-[day]");
1475    /// assert_eq!(Date::parse("2020-01-02", &format)?, date!(2020-01-02));
1476    /// # Ok::<_, time::Error>(())
1477    /// ```
1478    #[inline]
1479    pub fn parse(
1480        input: &str,
1481        description: &(impl Parsable + ?Sized),
1482    ) -> Result<Self, error::Parse> {
1483        description.parse_date(input.as_bytes(), None, PrivateMethod)
1484    }
1485
1486    /// Parse a `Date` from the input using the provided [format
1487    /// description](crate::format_description) and default values.
1488    ///
1489    /// ```rust
1490    /// # use time::Date;
1491    /// # use time::parsing::Parsed;
1492    /// # use time_macros::{date, format_description};
1493    /// let format = format_description!("[month]-[day]");
1494    /// let defaults = Parsed::new().with_year(2020).expect("2020 is a valid year");
1495    /// assert_eq!(
1496    ///     Date::parse_with_defaults(b"01-15", &format, defaults)?,
1497    ///     date!(2020-01-15)
1498    /// );
1499    /// # Ok::<_, time::Error>(())
1500    /// ```
1501    #[inline]
1502    pub fn parse_with_defaults(
1503        input: &[u8],
1504        description: &(impl Parsable + ?Sized),
1505        defaults: Parsed,
1506    ) -> Result<Self, error::Parse> {
1507        description.parse_date(input, Some(defaults), PrivateMethod)
1508    }
1509}
1510
1511mod private {
1512    /// Metadata for `Date`.
1513    #[non_exhaustive]
1514    #[derive(Debug)]
1515    pub struct DateMetadata;
1516}
1517use private::DateMetadata;
1518
1519// This no longer needs special handling, as the format is fixed and doesn't require anything
1520// advanced. Trait impls can't be deprecated and the info is still useful for other types
1521// implementing `SmartDisplay`, so leave it as-is for now.
1522impl SmartDisplay for Date {
1523    type Metadata = DateMetadata;
1524
1525    #[inline]
1526    fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
1527        use crate::ext::DigitCount as _;
1528
1529        let year_sign_width =
1530            if self.year() < 0 || (cfg!(feature = "large-dates") && self.year() >= 10_000) {
1531                1
1532            } else {
1533                0
1534            };
1535        let year_width = self.year().unsigned_abs().num_digits().clamp(4, 6);
1536        let formatted_width = year_sign_width + year_width + 6; // include two dashes and two digits each for month and day
1537
1538        Metadata::new(formatted_width as usize, self, DateMetadata)
1539    }
1540
1541    #[inline]
1542    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1543        fmt::Display::fmt(self, f)
1544    }
1545}
1546
1547impl Date {
1548    /// The maximum number of bytes that the `fmt_into_buffer` method will write, which is also used
1549    /// for the `Display` implementation.
1550    pub(crate) const DISPLAY_BUFFER_SIZE: usize = 13;
1551
1552    /// Format the `Date` into the provided buffer, returning the number of bytes written.
1553    #[inline]
1554    pub(crate) fn fmt_into_buffer(
1555        self,
1556        buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
1557    ) -> usize {
1558        let mut idx = 0;
1559        let (year, month, day) = self.to_calendar_date();
1560
1561        // Compute the sign of the integer, if any. Doing this in a branchless manner gives a
1562        // significant performance improvement.
1563        let neg = year.is_negative() as u8;
1564        let pos = (cfg!(feature = "large-dates") && year - 10_000 >= 0) as u8;
1565        let sign = b'+' + 2 * neg; // b'-' if `neg` is true, b'+' otherwise
1566        // Always write the computed byte, even if it's later overwritten by the first digit of the
1567        // year.
1568        buf[idx] = MaybeUninit::new(sign);
1569        idx += (neg | pos) as usize;
1570
1571        // Safety: `year.unsigned_abs()` is less than 1,000,000.
1572        let [first_two, second_two, third_two] =
1573            four_to_six_digits(unsafe { ru32::new_unchecked(year.unsigned_abs()) });
1574        // Safety:
1575        // - both `first_two` and `buf` are valid for reads and writes of up to 2 bytes.
1576        // - `u8` is 1-aligned, so that is not a concern.
1577        // - `first_two` points to static memory, while `buf` is a local variable, so they do not
1578        //   overlap.
1579        unsafe {
1580            first_two
1581                .as_ptr()
1582                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), first_two.len());
1583        }
1584        idx += first_two.len();
1585        // Safety: See above.
1586        unsafe {
1587            second_two
1588                .as_ptr()
1589                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2);
1590        }
1591        idx += 2;
1592        // Safety: See above.
1593        unsafe {
1594            third_two
1595                .as_ptr()
1596                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2);
1597        }
1598        idx += 2;
1599
1600        buf[idx] = MaybeUninit::new(b'-');
1601        idx += 1;
1602
1603        // Safety: See above for `copy_to_nonoverlapping`. `month` is in the range 1..=12.
1604        unsafe {
1605            two_digits_zero_padded(ru8::new_unchecked(u8::from(month)))
1606                .as_ptr()
1607                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2);
1608        }
1609        idx += 2;
1610
1611        buf[idx] = MaybeUninit::new(b'-');
1612        idx += 1;
1613
1614        // Safety: See above for `copy_to_nonoverlapping`. `day` is in the range 1..=31.
1615        unsafe {
1616            two_digits_zero_padded(ru8::new_unchecked(day))
1617                .as_ptr()
1618                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2);
1619        }
1620        idx += 2;
1621
1622        idx
1623    }
1624}
1625
1626impl fmt::Display for Date {
1627    #[inline]
1628    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1629        let mut buf = [MaybeUninit::uninit(); 13];
1630        let len = self.fmt_into_buffer(&mut buf);
1631        // Safety: All bytes up to `len` have been initialized with ASCII characters.
1632        let s = unsafe { str_from_raw_parts((&raw const buf).cast(), len) };
1633        f.pad(s)
1634    }
1635}
1636
1637impl fmt::Debug for Date {
1638    #[inline]
1639    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1640        fmt::Display::fmt(self, f)
1641    }
1642}
1643
1644impl Add<Duration> for Date {
1645    type Output = Self;
1646
1647    /// # Panics
1648    ///
1649    /// This may panic if an overflow occurs.
1650    #[inline]
1651    #[track_caller]
1652    fn add(self, duration: Duration) -> Self::Output {
1653        self.checked_add(duration)
1654            .expect("overflow adding duration to date")
1655    }
1656}
1657
1658impl Add<StdDuration> for Date {
1659    type Output = Self;
1660
1661    /// # Panics
1662    ///
1663    /// This may panic if an overflow occurs.
1664    #[inline]
1665    #[track_caller]
1666    fn add(self, duration: StdDuration) -> Self::Output {
1667        self.checked_add_std(duration)
1668            .expect("overflow adding duration to date")
1669    }
1670}
1671
1672impl AddAssign<Duration> for Date {
1673    /// # Panics
1674    ///
1675    /// This may panic if an overflow occurs.
1676    #[inline]
1677    #[track_caller]
1678    fn add_assign(&mut self, rhs: Duration) {
1679        *self = *self + rhs;
1680    }
1681}
1682
1683impl AddAssign<StdDuration> for Date {
1684    /// # Panics
1685    ///
1686    /// This may panic if an overflow occurs.
1687    #[inline]
1688    #[track_caller]
1689    fn add_assign(&mut self, rhs: StdDuration) {
1690        *self = *self + rhs;
1691    }
1692}
1693
1694impl Sub<Duration> for Date {
1695    type Output = Self;
1696
1697    /// # Panics
1698    ///
1699    /// This may panic if an overflow occurs.
1700    #[inline]
1701    #[track_caller]
1702    fn sub(self, duration: Duration) -> Self::Output {
1703        self.checked_sub(duration)
1704            .expect("overflow subtracting duration from date")
1705    }
1706}
1707
1708impl Sub<StdDuration> for Date {
1709    type Output = Self;
1710
1711    /// # Panics
1712    ///
1713    /// This may panic if an overflow occurs.
1714    #[inline]
1715    #[track_caller]
1716    fn sub(self, duration: StdDuration) -> Self::Output {
1717        self.checked_sub_std(duration)
1718            .expect("overflow subtracting duration from date")
1719    }
1720}
1721
1722impl SubAssign<Duration> for Date {
1723    /// # Panics
1724    ///
1725    /// This may panic if an overflow occurs.
1726    #[inline]
1727    #[track_caller]
1728    fn sub_assign(&mut self, rhs: Duration) {
1729        *self = *self - rhs;
1730    }
1731}
1732
1733impl SubAssign<StdDuration> for Date {
1734    /// # Panics
1735    ///
1736    /// This may panic if an overflow occurs.
1737    #[inline]
1738    #[track_caller]
1739    fn sub_assign(&mut self, rhs: StdDuration) {
1740        *self = *self - rhs;
1741    }
1742}
1743
1744impl Sub for Date {
1745    type Output = Duration;
1746
1747    #[inline]
1748    fn sub(self, other: Self) -> Self::Output {
1749        Duration::days((self.to_julian_day() - other.to_julian_day()).widen())
1750    }
1751}