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