time/
date.rs

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