time/
date.rs

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