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