time/
date.rs

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