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