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