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 ERAS: u32 = 5_949;
309        // Rata Die shift:
310        const D_SHIFT: u32 = 146097 * ERAS - 1_721_060;
311        // Year shift:
312        const Y_SHIFT: u32 = 400 * ERAS;
313
314        const CEN_MUL: u32 = ((4u64 << 47) / 146_097) as u32;
315        const JUL_MUL: u32 = ((4u64 << 40) / 1_461 + 1) as u32;
316        const CEN_CUT: u32 = ((365u64 << 32) / 36_525) as u32;
317
318        let day = julian_day.wrapping_add_unsigned(D_SHIFT) as u32;
319        let c_n = (day as u64 * CEN_MUL as u64) >> 15;
320        let cen = (c_n >> 32) as u32;
321        let cpt = c_n as u32;
322        let ijy = (cpt > CEN_CUT) || (cen % 4 == 0);
323        let jul = day - cen / 4 + cen;
324        let y_n = (jul as u64 * JUL_MUL as u64) >> 8;
325        let yrs = (y_n >> 32) as u32;
326        let ypt = y_n as u32;
327
328        let year = yrs.wrapping_sub(Y_SHIFT) as i32;
329        let ordinal = ((ypt as u64 * 1_461) >> 34) as u32 + ijy as u32;
330        let leap = (yrs % 4 == 0) & ijy;
331
332        // Safety: `ordinal` is not zero and `is_leap_year` is correct, so long as the Julian day
333        // number is in range, which is guaranteed by the caller.
334        unsafe { Self::from_parts(year, leap, 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        self.checked_next_occurrence(weekday)
676            .expect("overflow calculating the next occurrence of a weekday")
677    }
678
679    /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
680    ///
681    /// # Panics
682    /// Panics if an overflow occurred.
683    ///
684    /// # Examples
685    /// ```
686    /// # use time::Weekday;
687    /// # use time_macros::date;
688    /// assert_eq!(
689    ///     date!(2023-06-28).prev_occurrence(Weekday::Monday),
690    ///     date!(2023-06-26)
691    /// );
692    /// assert_eq!(
693    ///     date!(2023-06-19).prev_occurrence(Weekday::Monday),
694    ///     date!(2023-06-12)
695    /// );
696    /// ```
697    #[inline]
698    #[track_caller]
699    pub const fn prev_occurrence(self, weekday: Weekday) -> Self {
700        self.checked_prev_occurrence(weekday)
701            .expect("overflow calculating the previous occurrence of a weekday")
702    }
703
704    /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
705    ///
706    /// # Panics
707    /// Panics if an overflow occurred or if `n == 0`.
708    ///
709    /// # Examples
710    /// ```
711    /// # use time::Weekday;
712    /// # use time_macros::date;
713    /// assert_eq!(
714    ///     date!(2023-06-25).nth_next_occurrence(Weekday::Monday, 5),
715    ///     date!(2023-07-24)
716    /// );
717    /// assert_eq!(
718    ///     date!(2023-06-26).nth_next_occurrence(Weekday::Monday, 5),
719    ///     date!(2023-07-31)
720    /// );
721    /// ```
722    #[inline]
723    #[track_caller]
724    pub const fn nth_next_occurrence(self, weekday: Weekday, n: u8) -> Self {
725        self.checked_nth_next_occurrence(weekday, n)
726            .expect("overflow calculating the next occurrence of a weekday")
727    }
728
729    /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
730    ///
731    /// # Panics
732    /// Panics if an overflow occurred or if `n == 0`.
733    ///
734    /// # Examples
735    /// ```
736    /// # use time::Weekday;
737    /// # use time_macros::date;
738    /// assert_eq!(
739    ///     date!(2023-06-27).nth_prev_occurrence(Weekday::Monday, 3),
740    ///     date!(2023-06-12)
741    /// );
742    /// assert_eq!(
743    ///     date!(2023-06-26).nth_prev_occurrence(Weekday::Monday, 3),
744    ///     date!(2023-06-05)
745    /// );
746    /// ```
747    #[inline]
748    #[track_caller]
749    pub const fn nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Self {
750        self.checked_nth_prev_occurrence(weekday, n)
751            .expect("overflow calculating the previous occurrence of a weekday")
752    }
753
754    /// Get the Julian day for the date.
755    ///
756    /// ```rust
757    /// # use time_macros::date;
758    /// assert_eq!(date!(-4713 - 11 - 24).to_julian_day(), 0);
759    /// assert_eq!(date!(2000-01-01).to_julian_day(), 2_451_545);
760    /// assert_eq!(date!(2019-01-01).to_julian_day(), 2_458_485);
761    /// assert_eq!(date!(2019-12-31).to_julian_day(), 2_458_849);
762    /// ```
763    #[inline]
764    pub const fn to_julian_day(self) -> i32 {
765        let (year, ordinal) = self.to_ordinal_date();
766
767        // The algorithm requires a non-negative year. Add the lowest value to make it so. This is
768        // adjusted for at the end with the final subtraction.
769        let adj_year = year + 999_999;
770        let century = adj_year / 100;
771
772        let days_before_year = (1461 * adj_year as i64 / 4) as i32 - century + century / 4;
773        days_before_year + ordinal as i32 - 363_521_075
774    }
775
776    /// Computes `self + duration`, returning `None` if an overflow occurred.
777    ///
778    /// ```rust
779    /// # use time::{Date, ext::NumericalDuration};
780    /// # use time_macros::date;
781    /// assert_eq!(Date::MAX.checked_add(1.days()), None);
782    /// assert_eq!(Date::MIN.checked_add((-2).days()), None);
783    /// assert_eq!(
784    ///     date!(2020-12-31).checked_add(2.days()),
785    ///     Some(date!(2021-01-02))
786    /// );
787    /// ```
788    ///
789    /// # Note
790    ///
791    /// This function only takes whole days into account.
792    ///
793    /// ```rust
794    /// # use time::{Date, ext::NumericalDuration};
795    /// # use time_macros::date;
796    /// assert_eq!(Date::MAX.checked_add(23.hours()), Some(Date::MAX));
797    /// assert_eq!(Date::MIN.checked_add((-23).hours()), Some(Date::MIN));
798    /// assert_eq!(
799    ///     date!(2020-12-31).checked_add(23.hours()),
800    ///     Some(date!(2020-12-31))
801    /// );
802    /// assert_eq!(
803    ///     date!(2020-12-31).checked_add(47.hours()),
804    ///     Some(date!(2021-01-01))
805    /// );
806    /// ```
807    #[inline]
808    pub const fn checked_add(self, duration: Duration) -> Option<Self> {
809        let whole_days = duration.whole_days();
810        if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
811            return None;
812        }
813
814        let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days as i32));
815        if let Ok(date) = Self::from_julian_day(julian_day) {
816            Some(date)
817        } else {
818            None
819        }
820    }
821
822    /// Computes `self + duration`, returning `None` if an overflow occurred.
823    ///
824    /// ```rust
825    /// # use time::{Date, ext::NumericalStdDuration};
826    /// # use time_macros::date;
827    /// assert_eq!(Date::MAX.checked_add_std(1.std_days()), None);
828    /// assert_eq!(
829    ///     date!(2020-12-31).checked_add_std(2.std_days()),
830    ///     Some(date!(2021-01-02))
831    /// );
832    /// ```
833    ///
834    /// # Note
835    ///
836    /// This function only takes whole days into account.
837    ///
838    /// ```rust
839    /// # use time::{Date, ext::NumericalStdDuration};
840    /// # use time_macros::date;
841    /// assert_eq!(Date::MAX.checked_add_std(23.std_hours()), Some(Date::MAX));
842    /// assert_eq!(
843    ///     date!(2020-12-31).checked_add_std(23.std_hours()),
844    ///     Some(date!(2020-12-31))
845    /// );
846    /// assert_eq!(
847    ///     date!(2020-12-31).checked_add_std(47.std_hours()),
848    ///     Some(date!(2021-01-01))
849    /// );
850    /// ```
851    #[inline]
852    pub const fn checked_add_std(self, duration: StdDuration) -> Option<Self> {
853        let whole_days = duration.as_secs() / Second::per_t::<u64>(Day);
854        if whole_days > i32::MAX as u64 {
855            return None;
856        }
857
858        let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days as i32));
859        if let Ok(date) = Self::from_julian_day(julian_day) {
860            Some(date)
861        } else {
862            None
863        }
864    }
865
866    /// Computes `self - duration`, returning `None` if an overflow occurred.
867    ///
868    /// ```
869    /// # use time::{Date, ext::NumericalDuration};
870    /// # use time_macros::date;
871    /// assert_eq!(Date::MAX.checked_sub((-2).days()), None);
872    /// assert_eq!(Date::MIN.checked_sub(1.days()), None);
873    /// assert_eq!(
874    ///     date!(2020-12-31).checked_sub(2.days()),
875    ///     Some(date!(2020-12-29))
876    /// );
877    /// ```
878    ///
879    /// # Note
880    ///
881    /// This function only takes whole days into account.
882    ///
883    /// ```
884    /// # use time::{Date, ext::NumericalDuration};
885    /// # use time_macros::date;
886    /// assert_eq!(Date::MAX.checked_sub((-23).hours()), Some(Date::MAX));
887    /// assert_eq!(Date::MIN.checked_sub(23.hours()), Some(Date::MIN));
888    /// assert_eq!(
889    ///     date!(2020-12-31).checked_sub(23.hours()),
890    ///     Some(date!(2020-12-31))
891    /// );
892    /// assert_eq!(
893    ///     date!(2020-12-31).checked_sub(47.hours()),
894    ///     Some(date!(2020-12-30))
895    /// );
896    /// ```
897    #[inline]
898    pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
899        let whole_days = duration.whole_days();
900        if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
901            return None;
902        }
903
904        let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days as i32));
905        if let Ok(date) = Self::from_julian_day(julian_day) {
906            Some(date)
907        } else {
908            None
909        }
910    }
911
912    /// Computes `self - duration`, returning `None` if an overflow occurred.
913    ///
914    /// ```
915    /// # use time::{Date, ext::NumericalStdDuration};
916    /// # use time_macros::date;
917    /// assert_eq!(Date::MIN.checked_sub_std(1.std_days()), None);
918    /// assert_eq!(
919    ///     date!(2020-12-31).checked_sub_std(2.std_days()),
920    ///     Some(date!(2020-12-29))
921    /// );
922    /// ```
923    ///
924    /// # Note
925    ///
926    /// This function only takes whole days into account.
927    ///
928    /// ```
929    /// # use time::{Date, ext::NumericalStdDuration};
930    /// # use time_macros::date;
931    /// assert_eq!(Date::MIN.checked_sub_std(23.std_hours()), Some(Date::MIN));
932    /// assert_eq!(
933    ///     date!(2020-12-31).checked_sub_std(23.std_hours()),
934    ///     Some(date!(2020-12-31))
935    /// );
936    /// assert_eq!(
937    ///     date!(2020-12-31).checked_sub_std(47.std_hours()),
938    ///     Some(date!(2020-12-30))
939    /// );
940    /// ```
941    #[inline]
942    pub const fn checked_sub_std(self, duration: StdDuration) -> Option<Self> {
943        let whole_days = duration.as_secs() / Second::per_t::<u64>(Day);
944        if whole_days > i32::MAX as u64 {
945            return None;
946        }
947
948        let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days as i32));
949        if let Ok(date) = Self::from_julian_day(julian_day) {
950            Some(date)
951        } else {
952            None
953        }
954    }
955
956    /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
957    /// Returns `None` if an overflow occurred.
958    #[inline]
959    pub(crate) const fn checked_next_occurrence(self, weekday: Weekday) -> Option<Self> {
960        let day_diff = match weekday as i8 - self.weekday() as i8 {
961            1 | -6 => 1,
962            2 | -5 => 2,
963            3 | -4 => 3,
964            4 | -3 => 4,
965            5 | -2 => 5,
966            6 | -1 => 6,
967            val => {
968                debug_assert!(val == 0);
969                7
970            }
971        };
972
973        self.checked_add(Duration::days(day_diff))
974    }
975
976    /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
977    /// Returns `None` if an overflow occurred.
978    #[inline]
979    pub(crate) const fn checked_prev_occurrence(self, weekday: Weekday) -> Option<Self> {
980        let day_diff = match weekday as i8 - self.weekday() as i8 {
981            1 | -6 => 6,
982            2 | -5 => 5,
983            3 | -4 => 4,
984            4 | -3 => 3,
985            5 | -2 => 2,
986            6 | -1 => 1,
987            val => {
988                debug_assert!(val == 0);
989                7
990            }
991        };
992
993        self.checked_sub(Duration::days(day_diff))
994    }
995
996    /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
997    /// Returns `None` if an overflow occurred or if `n == 0`.
998    #[inline]
999    pub(crate) const fn checked_nth_next_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
1000        if n == 0 {
1001            return None;
1002        }
1003
1004        const_try_opt!(self.checked_next_occurrence(weekday))
1005            .checked_add(Duration::weeks(n as i64 - 1))
1006    }
1007
1008    /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
1009    /// Returns `None` if an overflow occurred or if `n == 0`.
1010    #[inline]
1011    pub(crate) const fn checked_nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
1012        if n == 0 {
1013            return None;
1014        }
1015
1016        const_try_opt!(self.checked_prev_occurrence(weekday))
1017            .checked_sub(Duration::weeks(n as i64 - 1))
1018    }
1019
1020    /// Computes `self + duration`, saturating value on overflow.
1021    ///
1022    /// ```rust
1023    /// # use time::{Date, ext::NumericalDuration};
1024    /// # use time_macros::date;
1025    /// assert_eq!(Date::MAX.saturating_add(1.days()), Date::MAX);
1026    /// assert_eq!(Date::MIN.saturating_add((-2).days()), Date::MIN);
1027    /// assert_eq!(
1028    ///     date!(2020-12-31).saturating_add(2.days()),
1029    ///     date!(2021-01-02)
1030    /// );
1031    /// ```
1032    ///
1033    /// # Note
1034    ///
1035    /// This function only takes whole days into account.
1036    ///
1037    /// ```rust
1038    /// # use time::ext::NumericalDuration;
1039    /// # use time_macros::date;
1040    /// assert_eq!(
1041    ///     date!(2020-12-31).saturating_add(23.hours()),
1042    ///     date!(2020-12-31)
1043    /// );
1044    /// assert_eq!(
1045    ///     date!(2020-12-31).saturating_add(47.hours()),
1046    ///     date!(2021-01-01)
1047    /// );
1048    /// ```
1049    #[inline]
1050    pub const fn saturating_add(self, duration: Duration) -> Self {
1051        if let Some(datetime) = self.checked_add(duration) {
1052            datetime
1053        } else if duration.is_negative() {
1054            Self::MIN
1055        } else {
1056            debug_assert!(duration.is_positive());
1057            Self::MAX
1058        }
1059    }
1060
1061    /// Computes `self - duration`, saturating value on overflow.
1062    ///
1063    /// ```
1064    /// # use time::{Date, ext::NumericalDuration};
1065    /// # use time_macros::date;
1066    /// assert_eq!(Date::MAX.saturating_sub((-2).days()), Date::MAX);
1067    /// assert_eq!(Date::MIN.saturating_sub(1.days()), Date::MIN);
1068    /// assert_eq!(
1069    ///     date!(2020-12-31).saturating_sub(2.days()),
1070    ///     date!(2020-12-29)
1071    /// );
1072    /// ```
1073    ///
1074    /// # Note
1075    ///
1076    /// This function only takes whole days into account.
1077    ///
1078    /// ```
1079    /// # use time::ext::NumericalDuration;
1080    /// # use time_macros::date;
1081    /// assert_eq!(
1082    ///     date!(2020-12-31).saturating_sub(23.hours()),
1083    ///     date!(2020-12-31)
1084    /// );
1085    /// assert_eq!(
1086    ///     date!(2020-12-31).saturating_sub(47.hours()),
1087    ///     date!(2020-12-30)
1088    /// );
1089    /// ```
1090    #[inline]
1091    pub const fn saturating_sub(self, duration: Duration) -> Self {
1092        if let Some(datetime) = self.checked_sub(duration) {
1093            datetime
1094        } else if duration.is_negative() {
1095            Self::MAX
1096        } else {
1097            debug_assert!(duration.is_positive());
1098            Self::MIN
1099        }
1100    }
1101
1102    /// Replace the year. The month and day will be unchanged.
1103    ///
1104    /// ```rust
1105    /// # use time_macros::date;
1106    /// assert_eq!(
1107    ///     date!(2022-02-18).replace_year(2019),
1108    ///     Ok(date!(2019-02-18))
1109    /// );
1110    /// assert!(date!(2022-02-18).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
1111    /// assert!(date!(2022-02-18).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
1112    /// ```
1113    #[inline]
1114    #[must_use = "This method does not mutate the original `Date`."]
1115    pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1116        ensure_ranged!(Year: year);
1117
1118        let ordinal = self.ordinal();
1119
1120        // Dates in January and February are unaffected by leap years.
1121        if ordinal <= 59 {
1122            // Safety: `ordinal` is not zero.
1123            return Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) });
1124        }
1125
1126        match (self.is_in_leap_year(), is_leap_year(year)) {
1127            (false, false) | (true, true) => {
1128                // Safety: `ordinal` is not zero.
1129                Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
1130            }
1131            // February 29 does not exist in common years.
1132            (true, false) if ordinal == 60 => Err(error::ComponentRange {
1133                name: "day",
1134                value: 29,
1135                minimum: 1,
1136                maximum: 28,
1137                conditional_message: Some("for the given month and year"),
1138            }),
1139            // We're going from a common year to a leap year. Shift dates in March and later by
1140            // one day.
1141            // Safety: `ordinal` is not zero.
1142            (false, true) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal + 1) }),
1143            // We're going from a leap year to a common year. Shift dates in January and
1144            // February by one day.
1145            // Safety: `ordinal` is not zero.
1146            (true, false) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal - 1) }),
1147        }
1148    }
1149
1150    /// Replace the month of the year.
1151    ///
1152    /// ```rust
1153    /// # use time_macros::date;
1154    /// # use time::Month;
1155    /// assert_eq!(
1156    ///     date!(2022-02-18).replace_month(Month::January),
1157    ///     Ok(date!(2022-01-18))
1158    /// );
1159    /// assert!(date!(2022-01-30)
1160    ///     .replace_month(Month::February)
1161    ///     .is_err()); // 30 isn't a valid day in February
1162    /// ```
1163    #[inline]
1164    #[must_use = "This method does not mutate the original `Date`."]
1165    pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1166        let (year, _, day) = self.to_calendar_date();
1167        Self::from_calendar_date(year, month, day)
1168    }
1169
1170    /// Replace the day of the month.
1171    ///
1172    /// ```rust
1173    /// # use time_macros::date;
1174    /// assert_eq!(date!(2022-02-18).replace_day(1), Ok(date!(2022-02-01)));
1175    /// assert!(date!(2022-02-18).replace_day(0).is_err()); // 0 isn't a valid day
1176    /// assert!(date!(2022-02-18).replace_day(30).is_err()); // 30 isn't a valid day in February
1177    /// ```
1178    #[inline]
1179    #[must_use = "This method does not mutate the original `Date`."]
1180    pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1181        match day {
1182            1..=28 => {}
1183            29..=31 if day <= self.month().length(self.year()) => {}
1184            _ => {
1185                return Err(error::ComponentRange {
1186                    name: "day",
1187                    minimum: 1,
1188                    maximum: self.month().length(self.year()) as i64,
1189                    value: day as i64,
1190                    conditional_message: Some("for the given month and year"),
1191                });
1192            }
1193        }
1194
1195        // Safety: `ordinal` is not zero.
1196        Ok(unsafe {
1197            Self::__from_ordinal_date_unchecked(
1198                self.year(),
1199                (self.ordinal() as i16 - self.day() as i16 + day as i16) as u16,
1200            )
1201        })
1202    }
1203
1204    /// Replace the day of the year.
1205    ///
1206    /// ```rust
1207    /// # use time_macros::date;
1208    /// assert_eq!(date!(2022-049).replace_ordinal(1), Ok(date!(2022-001)));
1209    /// assert!(date!(2022-049).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
1210    /// assert!(date!(2022-049).replace_ordinal(366).is_err()); // 2022 isn't a leap year
1211    /// ````
1212    #[inline]
1213    #[must_use = "This method does not mutate the original `Date`."]
1214    pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1215        match ordinal {
1216            1..=365 => {}
1217            366 if self.is_in_leap_year() => {}
1218            _ => {
1219                return Err(error::ComponentRange {
1220                    name: "ordinal",
1221                    minimum: 1,
1222                    maximum: days_in_year(self.year()) as i64,
1223                    value: ordinal as i64,
1224                    conditional_message: Some("for the given year"),
1225                });
1226            }
1227        }
1228
1229        // Safety: `ordinal` is in range.
1230        Ok(unsafe { Self::__from_ordinal_date_unchecked(self.year(), ordinal) })
1231    }
1232}
1233
1234/// Methods to add a [`Time`] component, resulting in a [`PrimitiveDateTime`].
1235impl Date {
1236    /// Create a [`PrimitiveDateTime`] using the existing date. The [`Time`] component will be set
1237    /// to midnight.
1238    ///
1239    /// ```rust
1240    /// # use time_macros::{date, datetime};
1241    /// assert_eq!(date!(1970-01-01).midnight(), datetime!(1970-01-01 0:00));
1242    /// ```
1243    #[inline]
1244    pub const fn midnight(self) -> PrimitiveDateTime {
1245        PrimitiveDateTime::new(self, Time::MIDNIGHT)
1246    }
1247
1248    /// Create a [`PrimitiveDateTime`] using the existing date and the provided [`Time`].
1249    ///
1250    /// ```rust
1251    /// # use time_macros::{date, datetime, time};
1252    /// assert_eq!(
1253    ///     date!(1970-01-01).with_time(time!(0:00)),
1254    ///     datetime!(1970-01-01 0:00),
1255    /// );
1256    /// ```
1257    #[inline]
1258    pub const fn with_time(self, time: Time) -> PrimitiveDateTime {
1259        PrimitiveDateTime::new(self, time)
1260    }
1261
1262    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1263    ///
1264    /// ```rust
1265    /// # use time_macros::date;
1266    /// assert!(date!(1970-01-01).with_hms(0, 0, 0).is_ok());
1267    /// assert!(date!(1970-01-01).with_hms(24, 0, 0).is_err());
1268    /// ```
1269    #[inline]
1270    pub const fn with_hms(
1271        self,
1272        hour: u8,
1273        minute: u8,
1274        second: u8,
1275    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1276        Ok(PrimitiveDateTime::new(
1277            self,
1278            const_try!(Time::from_hms(hour, minute, second)),
1279        ))
1280    }
1281
1282    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1283    ///
1284    /// ```rust
1285    /// # use time_macros::date;
1286    /// assert!(date!(1970-01-01).with_hms_milli(0, 0, 0, 0).is_ok());
1287    /// assert!(date!(1970-01-01).with_hms_milli(24, 0, 0, 0).is_err());
1288    /// ```
1289    #[inline]
1290    pub const fn with_hms_milli(
1291        self,
1292        hour: u8,
1293        minute: u8,
1294        second: u8,
1295        millisecond: u16,
1296    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1297        Ok(PrimitiveDateTime::new(
1298            self,
1299            const_try!(Time::from_hms_milli(hour, minute, second, millisecond)),
1300        ))
1301    }
1302
1303    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1304    ///
1305    /// ```rust
1306    /// # use time_macros::date;
1307    /// assert!(date!(1970-01-01).with_hms_micro(0, 0, 0, 0).is_ok());
1308    /// assert!(date!(1970-01-01).with_hms_micro(24, 0, 0, 0).is_err());
1309    /// ```
1310    #[inline]
1311    pub const fn with_hms_micro(
1312        self,
1313        hour: u8,
1314        minute: u8,
1315        second: u8,
1316        microsecond: u32,
1317    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1318        Ok(PrimitiveDateTime::new(
1319            self,
1320            const_try!(Time::from_hms_micro(hour, minute, second, microsecond)),
1321        ))
1322    }
1323
1324    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1325    ///
1326    /// ```rust
1327    /// # use time_macros::date;
1328    /// assert!(date!(1970-01-01).with_hms_nano(0, 0, 0, 0).is_ok());
1329    /// assert!(date!(1970-01-01).with_hms_nano(24, 0, 0, 0).is_err());
1330    /// ```
1331    #[inline]
1332    pub const fn with_hms_nano(
1333        self,
1334        hour: u8,
1335        minute: u8,
1336        second: u8,
1337        nanosecond: u32,
1338    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1339        Ok(PrimitiveDateTime::new(
1340            self,
1341            const_try!(Time::from_hms_nano(hour, minute, second, nanosecond)),
1342        ))
1343    }
1344}
1345
1346#[cfg(feature = "formatting")]
1347impl Date {
1348    /// Format the `Date` using the provided [format description](crate::format_description).
1349    #[inline]
1350    pub fn format_into(
1351        self,
1352        output: &mut (impl io::Write + ?Sized),
1353        format: &(impl Formattable + ?Sized),
1354    ) -> Result<usize, error::Format> {
1355        format.format_into(output, Some(self), None, None)
1356    }
1357
1358    /// Format the `Date` using the provided [format description](crate::format_description).
1359    ///
1360    /// ```rust
1361    /// # use time::{format_description};
1362    /// # use time_macros::date;
1363    /// let format = format_description::parse("[year]-[month]-[day]")?;
1364    /// assert_eq!(date!(2020-01-02).format(&format)?, "2020-01-02");
1365    /// # Ok::<_, time::Error>(())
1366    /// ```
1367    #[inline]
1368    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1369        format.format(Some(self), None, None)
1370    }
1371}
1372
1373#[cfg(feature = "parsing")]
1374impl Date {
1375    /// Parse a `Date` from the input using the provided [format
1376    /// description](crate::format_description).
1377    ///
1378    /// ```rust
1379    /// # use time::Date;
1380    /// # use time_macros::{date, format_description};
1381    /// let format = format_description!("[year]-[month]-[day]");
1382    /// assert_eq!(Date::parse("2020-01-02", &format)?, date!(2020-01-02));
1383    /// # Ok::<_, time::Error>(())
1384    /// ```
1385    #[inline]
1386    pub fn parse(
1387        input: &str,
1388        description: &(impl Parsable + ?Sized),
1389    ) -> Result<Self, error::Parse> {
1390        description.parse_date(input.as_bytes())
1391    }
1392}
1393
1394mod private {
1395    #[non_exhaustive]
1396    #[derive(Debug, Clone, Copy)]
1397    pub struct DateMetadata {
1398        /// The width of the year component, including the sign.
1399        pub(super) year_width: u8,
1400        /// Whether the sign should be displayed.
1401        pub(super) display_sign: bool,
1402        pub(super) year: i32,
1403        pub(super) month: u8,
1404        pub(super) day: u8,
1405    }
1406}
1407use private::DateMetadata;
1408
1409impl SmartDisplay for Date {
1410    type Metadata = DateMetadata;
1411
1412    #[inline]
1413    fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
1414        let (year, month, day) = self.to_calendar_date();
1415
1416        // There is a minimum of four digits for any year.
1417        let mut year_width = cmp::max(year.unsigned_abs().num_digits(), 4);
1418        let display_sign = if !(0..10_000).contains(&year) {
1419            // An extra character is required for the sign.
1420            year_width += 1;
1421            true
1422        } else {
1423            false
1424        };
1425
1426        let formatted_width = year_width.extend::<usize>()
1427            + smart_display::padded_width_of!(
1428                "-",
1429                u8::from(month) => width(2),
1430                "-",
1431                day => width(2),
1432            );
1433
1434        Metadata::new(
1435            formatted_width,
1436            self,
1437            DateMetadata {
1438                year_width,
1439                display_sign,
1440                year,
1441                month: u8::from(month),
1442                day,
1443            },
1444        )
1445    }
1446
1447    #[inline]
1448    fn fmt_with_metadata(
1449        &self,
1450        f: &mut fmt::Formatter<'_>,
1451        metadata: Metadata<Self>,
1452    ) -> fmt::Result {
1453        let DateMetadata {
1454            year_width,
1455            display_sign,
1456            year,
1457            month,
1458            day,
1459        } = *metadata;
1460        let year_width = year_width.extend();
1461
1462        if display_sign {
1463            f.pad_with_width(
1464                metadata.unpadded_width(),
1465                format_args!("{year:+0year_width$}-{month:02}-{day:02}"),
1466            )
1467        } else {
1468            f.pad_with_width(
1469                metadata.unpadded_width(),
1470                format_args!("{year:0year_width$}-{month:02}-{day:02}"),
1471            )
1472        }
1473    }
1474}
1475
1476impl fmt::Display for Date {
1477    #[inline]
1478    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1479        SmartDisplay::fmt(self, f)
1480    }
1481}
1482
1483impl fmt::Debug for Date {
1484    #[inline]
1485    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1486        fmt::Display::fmt(self, f)
1487    }
1488}
1489
1490impl Add<Duration> for Date {
1491    type Output = Self;
1492
1493    /// # Panics
1494    ///
1495    /// This may panic if an overflow occurs.
1496    #[inline]
1497    #[track_caller]
1498    fn add(self, duration: Duration) -> Self::Output {
1499        self.checked_add(duration)
1500            .expect("overflow adding duration to date")
1501    }
1502}
1503
1504impl Add<StdDuration> for Date {
1505    type Output = Self;
1506
1507    /// # Panics
1508    ///
1509    /// This may panic if an overflow occurs.
1510    #[inline]
1511    #[track_caller]
1512    fn add(self, duration: StdDuration) -> Self::Output {
1513        self.checked_add_std(duration)
1514            .expect("overflow adding duration to date")
1515    }
1516}
1517
1518impl_add_assign!(Date: Duration, StdDuration);
1519
1520impl Sub<Duration> for Date {
1521    type Output = Self;
1522
1523    /// # Panics
1524    ///
1525    /// This may panic if an overflow occurs.
1526    #[inline]
1527    #[track_caller]
1528    fn sub(self, duration: Duration) -> Self::Output {
1529        self.checked_sub(duration)
1530            .expect("overflow subtracting duration from date")
1531    }
1532}
1533
1534impl Sub<StdDuration> for Date {
1535    type Output = Self;
1536
1537    /// # Panics
1538    ///
1539    /// This may panic if an overflow occurs.
1540    #[inline]
1541    #[track_caller]
1542    fn sub(self, duration: StdDuration) -> Self::Output {
1543        self.checked_sub_std(duration)
1544            .expect("overflow subtracting duration from date")
1545    }
1546}
1547
1548impl_sub_assign!(Date: Duration, StdDuration);
1549
1550impl Sub for Date {
1551    type Output = Duration;
1552
1553    #[inline]
1554    fn sub(self, other: Self) -> Self::Output {
1555        Duration::days((self.to_julian_day() - other.to_julian_day()).extend())
1556    }
1557}