Skip to main content

time/
date.rs

1//! The [`Date`] struct and its associated `impl`s.
2
3#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::fmt;
6use core::mem::MaybeUninit;
7use core::num::NonZero;
8use core::ops::{Add, AddAssign, Sub, SubAssign};
9use core::time::Duration as StdDuration;
10#[cfg(feature = "formatting")]
11use std::io;
12
13use deranged::{ri32, ru8, ru32};
14use num_conv::prelude::*;
15use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
16
17#[cfg(any(feature = "formatting", feature = "parsing"))]
18use crate::PrivateMethod;
19#[cfg(feature = "formatting")]
20use crate::formatting::Formattable;
21#[cfg(feature = "formatting")]
22use crate::internal_macros::try_likely_ok;
23use crate::internal_macros::{const_try, const_try_opt, div_floor, ensure_ranged};
24use crate::iter::DateIter;
25use crate::num_fmt::{four_to_six_digits, str_from_raw_parts, two_digits_zero_padded};
26#[cfg(feature = "parsing")]
27use crate::parsing::{Parsable, Parsed};
28use crate::unit::*;
29use crate::util::{days_in_month_leap, range_validated, weeks_in_year};
30use crate::{Month, PlainDateTime, SignedDuration, Time, Weekday, error, hint};
31
32type Year = ri32<MIN_YEAR, MAX_YEAR>;
33
34/// The minimum valid year.
35pub(crate) const MIN_YEAR: i32 = if cfg!(feature = "large-dates") {
36    -999_999
37} else {
38    -9999
39};
40/// The maximum valid year.
41pub(crate) const MAX_YEAR: i32 = if cfg!(feature = "large-dates") {
42    999_999
43} else {
44    9999
45};
46
47/// Date in the proleptic Gregorian calendar.
48///
49/// By default, years between ±9999 inclusive are representable. This can be expanded to ±999,999
50/// inclusive by enabling the `large-dates` crate feature. Doing so has performance implications
51/// and introduces some ambiguities when parsing.
52#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
53pub struct Date {
54    /// Bitpacked field containing the year, ordinal, and whether the year is a leap year.
55    // |     x      | xxxxxxxxxxxxxxxxxxxxx |       x       | xxxxxxxxx |
56    // |   1 bit    |        21 bits        |     1 bit     |  9 bits   |
57    // | unassigned |         year          | is leap year? |  ordinal  |
58    // The year is 15 bits when `large-dates` is not enabled.
59    value: NonZero<i32>,
60}
61
62impl Date {
63    /// Provide a representation of `Date` as a `i32`. This value can be used for equality, hashing,
64    /// and ordering.
65    ///
66    /// **Note**: This value is explicitly signed, so do not cast this to or treat this as an
67    /// unsigned integer. Doing so will lead to incorrect results for values with differing
68    /// signs.
69    #[inline]
70    pub(crate) const fn as_i32(self) -> i32 {
71        self.value.get()
72    }
73
74    /// The Unix epoch: 1970-01-01
75    // Safety: `ordinal` is not zero.
76    pub(crate) const UNIX_EPOCH: Self = unsafe { Self::__from_ordinal_date_unchecked(1970, 1) };
77
78    /// The minimum valid `Date`.
79    ///
80    /// The value of this may vary depending on the feature flags enabled.
81    // Safety: `ordinal` is not zero.
82    pub const MIN: Self = unsafe { Self::__from_ordinal_date_unchecked(MIN_YEAR, 1) };
83
84    /// The maximum valid `Date`.
85    ///
86    /// The value of this may vary depending on the feature flags enabled.
87    // Safety: `ordinal` is not zero.
88    pub const MAX: Self = unsafe {
89        Self::__from_ordinal_date_unchecked(MAX_YEAR, range_validated::days_in_year(MAX_YEAR))
90    };
91
92    /// Construct a `Date` from its internal representation, the validity of which must be
93    /// guaranteed by the caller.
94    ///
95    /// # Safety
96    ///
97    /// - `year` must be in the range `MIN_YEAR..=MAX_YEAR`
98    /// - `ordinal` must be non-zero and at most the number of days in `year`
99    /// - `is_leap_year` must be `true` if and only if `year` is a leap year
100    #[inline]
101    #[track_caller]
102    pub(crate) const unsafe fn from_parts(year: i32, is_leap_year: bool, ordinal: u16) -> Self {
103        debug_assert!(year >= MIN_YEAR);
104        debug_assert!(year <= MAX_YEAR);
105        debug_assert!(ordinal != 0);
106        debug_assert!(ordinal <= range_validated::days_in_year(year));
107        debug_assert!(range_validated::is_leap_year(year) == is_leap_year);
108
109        Self {
110            // Safety: `ordinal` is not zero, so the overall value will never be zero.
111            value: unsafe {
112                NonZero::new_unchecked((year << 10) | ((is_leap_year as i32) << 9) | ordinal as i32)
113            },
114        }
115    }
116
117    /// Construct a `Date` from the year and ordinal values, the validity of which must be
118    /// guaranteed by the caller.
119    ///
120    /// # Safety
121    ///
122    /// - `year` must be in the range `MIN_YEAR..=MAX_YEAR`.
123    /// - `ordinal` must be non-zero and at most the number of days in `year`.
124    #[doc(hidden)]
125    #[inline]
126    #[track_caller]
127    pub const unsafe fn __from_ordinal_date_unchecked(year: i32, ordinal: u16) -> Self {
128        // Safety: The caller must guarantee that `year` is in range and `ordinal` is in
129        // `1..=days_in_year(year)`.
130        unsafe { Self::from_parts(year, range_validated::is_leap_year(year), ordinal) }
131    }
132
133    /// Attempt to create a `Date` from the year, month, and day.
134    ///
135    /// ```rust
136    /// # use time::{Date, Month};
137    /// assert!(Date::from_calendar_date(2019, Month::January, 1).is_ok());
138    /// assert!(Date::from_calendar_date(2019, Month::December, 31).is_ok());
139    /// ```
140    ///
141    /// ```rust
142    /// # use time::{Date, Month};
143    /// assert!(Date::from_calendar_date(2019, Month::February, 29).is_err()); // 2019 isn't a leap year.
144    /// ```
145    #[inline]
146    pub const fn from_calendar_date(
147        year: i32,
148        month: Month,
149        day: u8,
150    ) -> Result<Self, error::ComponentRange> {
151        /// Cumulative days through the beginning of a month in both common and leap years.
152        const DAYS_CUMULATIVE_COMMON_LEAP: [[u16; 12]; 2] = [
153            [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
154            [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
155        ];
156
157        ensure_ranged!(Year: year);
158
159        let is_leap_year = range_validated::is_leap_year(year);
160        match day {
161            1..=28 => {}
162            29..=31 if day <= days_in_month_leap(month as u8, is_leap_year) => hint::cold_path(),
163            _ => {
164                hint::cold_path();
165                return Err(error::ComponentRange::conditional("day"));
166            }
167        }
168
169        // Safety: `ordinal` is not zero and `is_leap_year` is correct.
170        Ok(unsafe {
171            Self::from_parts(
172                year,
173                is_leap_year,
174                DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year as usize][month as usize - 1] + day as u16,
175            )
176        })
177    }
178
179    /// Attempt to create a `Date` from the year and ordinal day number.
180    ///
181    /// ```rust
182    /// # use time::Date;
183    /// assert!(Date::from_ordinal_date(2019, 1).is_ok());
184    /// assert!(Date::from_ordinal_date(2019, 365).is_ok());
185    /// ```
186    ///
187    /// ```rust
188    /// # use time::Date;
189    /// assert!(Date::from_ordinal_date(2019, 366).is_err()); // 2019 isn't a leap year.
190    /// ```
191    #[inline]
192    pub const fn from_ordinal_date(year: i32, ordinal: u16) -> Result<Self, error::ComponentRange> {
193        ensure_ranged!(Year: year);
194
195        let is_leap_year = range_validated::is_leap_year(year);
196        match ordinal {
197            1..=365 => {}
198            366 if is_leap_year => hint::cold_path(),
199            _ => {
200                hint::cold_path();
201                return Err(error::ComponentRange::conditional("ordinal"));
202            }
203        }
204
205        // Safety: `ordinal` is not zero.
206        Ok(unsafe { Self::from_parts(year, is_leap_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) => hint::cold_path(),
231            _ => {
232                hint::cold_path();
233                return Err(error::ComponentRange::conditional("week"));
234            }
235        }
236
237        let adj_year = year - 1;
238        let raw = 365 * adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100)
239            + div_floor!(adj_year, 400);
240        let jan_4 = match (raw % 7) as i8 {
241            -6 | 1 => 8,
242            -5 | 2 => 9,
243            -4 | 3 => 10,
244            -3 | 4 => 4,
245            -2 | 5 => 5,
246            -1 | 6 => 6,
247            _ => 7,
248        };
249        let ordinal = week as i16 * 7 + weekday.number_from_monday() as i16 - jan_4;
250
251        if ordinal <= 0 {
252            // Safety: `ordinal` is not zero. For both values of `MIN_YEAR`, this branch is
253            // unreachable, so it is sound to subtract one from it and construct a new value with
254            // that year.
255            return Ok(unsafe {
256                Self::__from_ordinal_date_unchecked(
257                    year - 1,
258                    ordinal
259                        .cast_unsigned()
260                        .wrapping_add(range_validated::days_in_year(year - 1)),
261                )
262            });
263        }
264
265        let is_leap_year = range_validated::is_leap_year(year);
266        let days_in_year = if is_leap_year { 366 } else { 365 };
267        let ordinal = ordinal.cast_unsigned();
268        Ok(if ordinal > days_in_year {
269            // Issue #777
270            if hint::unlikely(year == MAX_YEAR) {
271                return Err(error::ComponentRange::conditional("weekday"));
272            }
273            // Safety: the year is in range and `ordinal` is not zero.
274            unsafe { Self::__from_ordinal_date_unchecked(year + 1, ordinal - days_in_year) }
275        } else {
276            // Safety: `ordinal` is not zero and `is_leap_year` is correct.
277            unsafe { Self::from_parts(year, is_leap_year, ordinal) }
278        })
279    }
280
281    /// Create a `Date` from the Julian day.
282    ///
283    /// ```rust
284    /// # use time::Date;
285    /// # use time_macros::date;
286    /// assert_eq!(Date::from_julian_day(0), Ok(date!(-4713-11-24)));
287    /// assert_eq!(Date::from_julian_day(2_451_545), Ok(date!(2000-01-01)));
288    /// assert_eq!(Date::from_julian_day(2_458_485), Ok(date!(2019-01-01)));
289    /// assert_eq!(Date::from_julian_day(2_458_849), Ok(date!(2019-12-31)));
290    /// ```
291    #[doc(alias = "from_julian_date")]
292    #[inline]
293    pub const fn from_julian_day(julian_day: i32) -> Result<Self, error::ComponentRange> {
294        type JulianDay = ri32<{ Date::MIN.to_julian_day() }, { Date::MAX.to_julian_day() }>;
295        ensure_ranged!(JulianDay: julian_day);
296        // Safety: The Julian day number is in range.
297        Ok(unsafe { Self::from_julian_day_unchecked(julian_day) })
298    }
299
300    /// Create a `Date` from the Julian day.
301    ///
302    /// # Safety
303    ///
304    /// The provided Julian day number must be between `Date::MIN.to_julian_day()` and
305    /// `Date::MAX.to_julian_day()` inclusive.
306    #[inline]
307    pub(crate) const unsafe fn from_julian_day_unchecked(julian_day: i32) -> Self {
308        debug_assert!(julian_day >= Self::MIN.to_julian_day());
309        debug_assert!(julian_day <= Self::MAX.to_julian_day());
310
311        const ERAS: u32 = 5_949;
312        // Rata Die shift:
313        const D_SHIFT: u32 = 146097 * ERAS - 1_721_060;
314        // Year shift:
315        const Y_SHIFT: u32 = 400 * ERAS;
316
317        const CEN_MUL: u32 = ((4u64 << 47) / 146_097) as u32;
318        const JUL_MUL: u32 = ((4u64 << 40) / 1_461 + 1) as u32;
319        const CEN_CUT: u32 = ((365u64 << 32) / 36_525) as u32;
320
321        let day = julian_day.cast_unsigned().wrapping_add(D_SHIFT);
322        let c_n = (day as u64 * CEN_MUL as u64) >> 15;
323        let cen = (c_n >> 32) as u32;
324        let cpt = c_n as u32;
325        let ijy = cpt > CEN_CUT || cen.is_multiple_of(4);
326        let jul = day - cen / 4 + cen;
327        let y_n = (jul as u64 * JUL_MUL as u64) >> 8;
328        let yrs = (y_n >> 32) as u32;
329        let ypt = y_n as u32;
330
331        let year = yrs.wrapping_sub(Y_SHIFT).cast_signed();
332        let ordinal = ((ypt as u64 * 1_461) >> 34) as u32 + ijy as u32;
333        let leap = yrs.is_multiple_of(4) & ijy;
334
335        // Safety: `ordinal` is not zero and `is_leap_year` is correct, so long as the Julian day
336        // number is in range, which is guaranteed by the caller.
337        unsafe { Self::from_parts(year, leap, 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    pub(crate) 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, given the day of the week of `self` is already known.
434    ///
435    /// A `Weekday` is passed as a parameter in order to allow the caller to precompute the value
436    /// and cache it as necessary. If the value is not already known, it can be calculated with
437    /// `self.weekday()`.
438    #[inline]
439    pub(crate) const fn iso_year_week(self, weekday: Weekday) -> (i32, u8) {
440        let (year, ordinal) = self.to_ordinal_date();
441
442        match ((ordinal + 10 - weekday.number_from_monday() as u16) / 7) as u8 {
443            0 => (year - 1, weeks_in_year(year - 1)),
444            53 if weeks_in_year(year) == 52 => (year + 1, 1),
445            week => (year, week),
446        }
447    }
448
449    /// Get the ISO week number.
450    ///
451    /// The returned value will always be in the range `1..=53`.
452    ///
453    /// ```rust
454    /// # use time_macros::date;
455    /// assert_eq!(date!(2019-01-01).iso_week(), 1);
456    /// assert_eq!(date!(2019-10-04).iso_week(), 40);
457    /// assert_eq!(date!(2020-01-01).iso_week(), 1);
458    /// assert_eq!(date!(2020-12-31).iso_week(), 53);
459    /// assert_eq!(date!(2021-01-01).iso_week(), 53);
460    /// ```
461    #[inline]
462    pub const fn iso_week(self) -> u8 {
463        self.iso_year_week(self.weekday()).1
464    }
465
466    /// Get the week number where week 1 begins on the first Sunday.
467    ///
468    /// The returned value will always be in the range `0..=53`.
469    ///
470    /// ```rust
471    /// # use time_macros::date;
472    /// assert_eq!(date!(2019-01-01).sunday_based_week(), 0);
473    /// assert_eq!(date!(2020-01-01).sunday_based_week(), 0);
474    /// assert_eq!(date!(2020-12-31).sunday_based_week(), 52);
475    /// assert_eq!(date!(2021-01-01).sunday_based_week(), 0);
476    /// ```
477    #[inline]
478    pub const fn sunday_based_week(self) -> u8 {
479        ((self.ordinal().cast_signed() - self.weekday().number_days_from_sunday() as i16 + 6) / 7)
480            as u8
481    }
482
483    /// Get the week number where week 1 begins on the first Monday.
484    ///
485    /// The returned value will always be in the range `0..=53`.
486    ///
487    /// ```rust
488    /// # use time_macros::date;
489    /// assert_eq!(date!(2019-01-01).monday_based_week(), 0);
490    /// assert_eq!(date!(2020-01-01).monday_based_week(), 0);
491    /// assert_eq!(date!(2020-12-31).monday_based_week(), 52);
492    /// assert_eq!(date!(2021-01-01).monday_based_week(), 0);
493    /// ```
494    #[inline]
495    pub const fn monday_based_week(self) -> u8 {
496        ((self.ordinal().cast_signed() - self.weekday().number_days_from_monday() as i16 + 6) / 7)
497            as u8
498    }
499
500    /// Get the year, month, and day.
501    ///
502    /// ```rust
503    /// # use time::Month;
504    /// # use time_macros::date;
505    /// assert_eq!(
506    ///     date!(2019-01-01).to_calendar_date(),
507    ///     (2019, Month::January, 1)
508    /// );
509    /// ```
510    #[inline]
511    pub const fn to_calendar_date(self) -> (i32, Month, u8) {
512        let (year, ordinal) = self.to_ordinal_date();
513        let ordinal = ordinal as u32;
514        let jan_feb_len = 59 + self.is_in_leap_year() as u32;
515
516        let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len {
517            (0, 0)
518        } else {
519            (2, jan_feb_len)
520        };
521
522        let ordinal = ordinal - ordinal_adj;
523        let month = (ordinal * 268 + 8031) >> 13;
524        let days_in_preceding_months = (month * 3917 - 3866) >> 7;
525        let day = ordinal - days_in_preceding_months;
526        let month = month + month_adj;
527
528        (
529            year,
530            // Safety: `month` is guaranteed to be between 1 and 12 inclusive.
531            unsafe {
532                match Month::from_number(NonZero::new_unchecked(month as u8)) {
533                    Ok(month) => month,
534                    Err(_) => core::hint::unreachable_unchecked(),
535                }
536            },
537            day as u8,
538        )
539    }
540
541    /// Get the year and ordinal day number.
542    ///
543    /// ```rust
544    /// # use time_macros::date;
545    /// assert_eq!(date!(2019-01-01).to_ordinal_date(), (2019, 1));
546    /// ```
547    #[inline]
548    pub const fn to_ordinal_date(self) -> (i32, u16) {
549        (self.year(), self.ordinal())
550    }
551
552    /// Get the ISO 8601 year, week number, and weekday.
553    ///
554    /// ```rust
555    /// # use time::Weekday::*;
556    /// # use time_macros::date;
557    /// assert_eq!(date!(2019-01-01).to_iso_week_date(), (2019, 1, Tuesday));
558    /// assert_eq!(date!(2019-10-04).to_iso_week_date(), (2019, 40, Friday));
559    /// assert_eq!(date!(2020-01-01).to_iso_week_date(), (2020, 1, Wednesday));
560    /// assert_eq!(date!(2020-12-31).to_iso_week_date(), (2020, 53, Thursday));
561    /// assert_eq!(date!(2021-01-01).to_iso_week_date(), (2020, 53, Friday));
562    /// ```
563    #[inline]
564    pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
565        let (year, ordinal) = self.to_ordinal_date();
566        let weekday = self.weekday();
567
568        match ((ordinal + 10 - weekday.number_from_monday() as u16) / 7) as u8 {
569            0 => (year - 1, weeks_in_year(year - 1), weekday),
570            53 if weeks_in_year(year) == 52 => (year + 1, 1, weekday),
571            week => (year, week, weekday),
572        }
573    }
574
575    /// Get the weekday.
576    ///
577    /// ```rust
578    /// # use time::Weekday::*;
579    /// # use time_macros::date;
580    /// assert_eq!(date!(2019-01-01).weekday(), Tuesday);
581    /// assert_eq!(date!(2019-02-01).weekday(), Friday);
582    /// assert_eq!(date!(2019-03-01).weekday(), Friday);
583    /// assert_eq!(date!(2019-04-01).weekday(), Monday);
584    /// assert_eq!(date!(2019-05-01).weekday(), Wednesday);
585    /// assert_eq!(date!(2019-06-01).weekday(), Saturday);
586    /// assert_eq!(date!(2019-07-01).weekday(), Monday);
587    /// assert_eq!(date!(2019-08-01).weekday(), Thursday);
588    /// assert_eq!(date!(2019-09-01).weekday(), Sunday);
589    /// assert_eq!(date!(2019-10-01).weekday(), Tuesday);
590    /// assert_eq!(date!(2019-11-01).weekday(), Friday);
591    /// assert_eq!(date!(2019-12-01).weekday(), Sunday);
592    /// ```
593    #[inline]
594    pub const fn weekday(self) -> Weekday {
595        match self.to_julian_day() % 7 {
596            -6 | 1 => Weekday::Tuesday,
597            -5 | 2 => Weekday::Wednesday,
598            -4 | 3 => Weekday::Thursday,
599            -3 | 4 => Weekday::Friday,
600            -2 | 5 => Weekday::Saturday,
601            -1 | 6 => Weekday::Sunday,
602            val => {
603                debug_assert!(val == 0);
604                Weekday::Monday
605            }
606        }
607    }
608
609    /// Get the next calendar date.
610    ///
611    /// ```rust
612    /// # use time::Date;
613    /// # use time_macros::date;
614    /// assert_eq!(date!(2019-01-01).next_day(), Some(date!(2019-01-02)));
615    /// assert_eq!(date!(2019-01-31).next_day(), Some(date!(2019-02-01)));
616    /// assert_eq!(date!(2019-12-31).next_day(), Some(date!(2020-01-01)));
617    /// assert_eq!(Date::MAX.next_day(), None);
618    /// ```
619    #[inline]
620    pub const fn next_day(self) -> Option<Self> {
621        let is_last_day_of_year = matches!(self.value.get() & 0x3FF, 365 | 878);
622        if hint::unlikely(is_last_day_of_year) {
623            if self.value.get() == Self::MAX.value.get() {
624                None
625            } else {
626                // Safety: `ordinal` is not zero.
627                unsafe { Some(Self::__from_ordinal_date_unchecked(self.year() + 1, 1)) }
628            }
629        } else {
630            // Safety: `self` is not the last day of the year.
631            Some(unsafe { self.add_days_unchecked(1) })
632        }
633    }
634
635    /// Get the previous calendar date.
636    ///
637    /// ```rust
638    /// # use time::Date;
639    /// # use time_macros::date;
640    /// assert_eq!(date!(2019-01-02).previous_day(), Some(date!(2019-01-01)));
641    /// assert_eq!(date!(2019-02-01).previous_day(), Some(date!(2019-01-31)));
642    /// assert_eq!(date!(2020-01-01).previous_day(), Some(date!(2019-12-31)));
643    /// assert_eq!(Date::MIN.previous_day(), None);
644    /// ```
645    #[inline]
646    pub const fn previous_day(self) -> Option<Self> {
647        if hint::likely(self.ordinal() != 1) {
648            // Safety: `self` is not the first day of the year.
649            Some(unsafe { self.add_days_unchecked(-1) })
650        } else if self.value.get() == Self::MIN.value.get() {
651            None
652        } else {
653            let year = self.year() - 1;
654            let is_leap_year = range_validated::is_leap_year(year);
655            let ordinal = if is_leap_year { 366 } else { 365 };
656            // Safety: `ordinal` is not zero, `is_leap_year` is correct.
657            Some(unsafe { Self::from_parts(year, is_leap_year, ordinal) })
658        }
659    }
660
661    /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
662    ///
663    /// # Panics
664    /// Panics if an overflow occurred.
665    ///
666    /// # Examples
667    /// ```
668    /// # use time::Weekday;
669    /// # use time_macros::date;
670    /// assert_eq!(
671    ///     date!(2023-06-28).next_occurrence(Weekday::Monday),
672    ///     date!(2023-07-03)
673    /// );
674    /// assert_eq!(
675    ///     date!(2023-06-19).next_occurrence(Weekday::Monday),
676    ///     date!(2023-06-26)
677    /// );
678    /// ```
679    #[inline]
680    #[track_caller]
681    pub const fn next_occurrence(self, weekday: Weekday) -> Self {
682        self.checked_next_occurrence(weekday)
683            .expect("overflow calculating the next occurrence of a weekday")
684    }
685
686    /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
687    ///
688    /// # Panics
689    /// Panics if an overflow occurred.
690    ///
691    /// # Examples
692    /// ```
693    /// # use time::Weekday;
694    /// # use time_macros::date;
695    /// assert_eq!(
696    ///     date!(2023-06-28).prev_occurrence(Weekday::Monday),
697    ///     date!(2023-06-26)
698    /// );
699    /// assert_eq!(
700    ///     date!(2023-06-19).prev_occurrence(Weekday::Monday),
701    ///     date!(2023-06-12)
702    /// );
703    /// ```
704    #[inline]
705    #[track_caller]
706    pub const fn prev_occurrence(self, weekday: Weekday) -> Self {
707        self.checked_prev_occurrence(weekday)
708            .expect("overflow calculating the previous occurrence of a weekday")
709    }
710
711    /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
712    ///
713    /// # Panics
714    /// Panics if an overflow occurred or if `n == 0`.
715    ///
716    /// # Examples
717    /// ```
718    /// # use time::Weekday;
719    /// # use time_macros::date;
720    /// assert_eq!(
721    ///     date!(2023-06-25).nth_next_occurrence(Weekday::Monday, 5),
722    ///     date!(2023-07-24)
723    /// );
724    /// assert_eq!(
725    ///     date!(2023-06-26).nth_next_occurrence(Weekday::Monday, 5),
726    ///     date!(2023-07-31)
727    /// );
728    /// ```
729    #[inline]
730    #[track_caller]
731    pub const fn nth_next_occurrence(self, weekday: Weekday, n: u8) -> Self {
732        self.checked_nth_next_occurrence(weekday, n)
733            .expect("overflow calculating the next occurrence of a weekday")
734    }
735
736    /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
737    ///
738    /// # Panics
739    /// Panics if an overflow occurred or if `n == 0`.
740    ///
741    /// # Examples
742    /// ```
743    /// # use time::Weekday;
744    /// # use time_macros::date;
745    /// assert_eq!(
746    ///     date!(2023-06-27).nth_prev_occurrence(Weekday::Monday, 3),
747    ///     date!(2023-06-12)
748    /// );
749    /// assert_eq!(
750    ///     date!(2023-06-26).nth_prev_occurrence(Weekday::Monday, 3),
751    ///     date!(2023-06-05)
752    /// );
753    /// ```
754    #[inline]
755    #[track_caller]
756    pub const fn nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Self {
757        self.checked_nth_prev_occurrence(weekday, n)
758            .expect("overflow calculating the previous occurrence of a weekday")
759    }
760
761    /// Create an iterator of dates from `self` to `end` inclusive.
762    ///
763    /// ```rust
764    /// # use time_macros::date;
765    /// let mut iter = date!(2019-01-01).iter_to(date!(2019-01-03));
766    /// assert_eq!(iter.next(), Some(date!(2019-01-01)));
767    /// assert_eq!(iter.next(), Some(date!(2019-01-02)));
768    /// assert_eq!(iter.next(), Some(date!(2019-01-03)));
769    /// assert_eq!(iter.next(), None);
770    /// ```
771    #[inline]
772    pub const fn iter_to(self, end: Self) -> DateIter {
773        DateIter::new(self, end)
774    }
775
776    /// Get the Julian day for the date.
777    ///
778    /// ```rust
779    /// # use time_macros::date;
780    /// assert_eq!(date!(-4713-11-24).to_julian_day(), 0);
781    /// assert_eq!(date!(2000-01-01).to_julian_day(), 2_451_545);
782    /// assert_eq!(date!(2019-01-01).to_julian_day(), 2_458_485);
783    /// assert_eq!(date!(2019-12-31).to_julian_day(), 2_458_849);
784    /// ```
785    #[inline]
786    pub const fn to_julian_day(self) -> i32 {
787        let (year, ordinal) = self.to_ordinal_date();
788
789        // The algorithm requires a non-negative year. Add the lowest value to make it so. This is
790        // adjusted for at the end with the final subtraction.
791        let adj_year = year + 999_999;
792        let century = adj_year / 100;
793
794        let days_before_year = (1461 * adj_year as i64 / 4) as i32 - century + century / 4;
795        days_before_year + ordinal as i32 - 363_521_075
796    }
797
798    /// Add a number of days to the date without checking for overflow.
799    ///
800    /// # Safety
801    ///
802    /// `self.ordinal() + days` must be in the range `1..=366` for leap years and `1..=365` for
803    /// common years.
804    #[inline]
805    pub(crate) const unsafe fn add_days_unchecked(mut self, days: i32) -> Self {
806        // Safety: asserted by caller
807        self.value = unsafe { NonZero::new_unchecked(self.value.get() + days) };
808        self
809    }
810
811    /// Computes `self + duration`, returning `None` if an overflow occurred.
812    ///
813    /// ```rust
814    /// # use time::{Date, ext::NumericalDuration};
815    /// # use time_macros::date;
816    /// assert_eq!(Date::MAX.checked_add(1.days()), None);
817    /// assert_eq!(Date::MIN.checked_add((-2).days()), None);
818    /// assert_eq!(
819    ///     date!(2020-12-31).checked_add(2.days()),
820    ///     Some(date!(2021-01-02))
821    /// );
822    /// ```
823    ///
824    /// # Note
825    ///
826    /// This function only takes whole days into account.
827    ///
828    /// ```rust
829    /// # use time::{Date, ext::NumericalDuration};
830    /// # use time_macros::date;
831    /// assert_eq!(Date::MAX.checked_add(23.hours()), Some(Date::MAX));
832    /// assert_eq!(Date::MIN.checked_add((-23).hours()), Some(Date::MIN));
833    /// assert_eq!(
834    ///     date!(2020-12-31).checked_add(23.hours()),
835    ///     Some(date!(2020-12-31))
836    /// );
837    /// assert_eq!(
838    ///     date!(2020-12-31).checked_add(47.hours()),
839    ///     Some(date!(2021-01-01))
840    /// );
841    /// ```
842    #[inline]
843    pub const fn checked_add(self, duration: SignedDuration) -> Option<Self> {
844        let whole_days = duration.whole_days();
845        if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
846            return None;
847        }
848
849        let year = self.year();
850        let is_leap_year = self.is_in_leap_year();
851        let ordinal = self.ordinal() as i32;
852
853        let days_in_year = if is_leap_year { 366 } else { 365 };
854        let whole_days = whole_days as i32;
855
856        // Fast path for when the result is in the same year.
857        if let Some(new_ordinal) = ordinal.checked_add(whole_days)
858            && new_ordinal >= 1
859            && new_ordinal <= days_in_year
860        {
861            // Safety: `new_ordinal` is in range and `is_leap_year` is correct
862            return Some(unsafe { Self::from_parts(year, is_leap_year, new_ordinal as u16) });
863        }
864
865        let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days));
866        if let Ok(date) = Self::from_julian_day(julian_day) {
867            Some(date)
868        } else {
869            None
870        }
871    }
872
873    /// Computes `self + duration`, returning `None` if an overflow occurred.
874    ///
875    /// ```rust
876    /// # use time::{Date, ext::NumericalStdDuration};
877    /// # use time_macros::date;
878    /// assert_eq!(Date::MAX.checked_add_std(1.std_days()), None);
879    /// assert_eq!(
880    ///     date!(2020-12-31).checked_add_std(2.std_days()),
881    ///     Some(date!(2021-01-02))
882    /// );
883    /// ```
884    ///
885    /// # Note
886    ///
887    /// This function only takes whole days into account.
888    ///
889    /// ```rust
890    /// # use time::{Date, ext::NumericalStdDuration};
891    /// # use time_macros::date;
892    /// assert_eq!(Date::MAX.checked_add_std(23.std_hours()), Some(Date::MAX));
893    /// assert_eq!(
894    ///     date!(2020-12-31).checked_add_std(23.std_hours()),
895    ///     Some(date!(2020-12-31))
896    /// );
897    /// assert_eq!(
898    ///     date!(2020-12-31).checked_add_std(47.std_hours()),
899    ///     Some(date!(2021-01-01))
900    /// );
901    /// ```
902    #[inline]
903    pub const fn checked_add_std(self, duration: StdDuration) -> Option<Self> {
904        let whole_days = duration.as_secs() / Second::per_t::<u64>(Day);
905        if whole_days > i32::MAX as u64 {
906            return None;
907        }
908
909        let year = self.year();
910        let is_leap_year = self.is_in_leap_year();
911        let ordinal = self.ordinal() as i32;
912
913        let days_in_year = if is_leap_year { 366 } else { 365 };
914        let whole_days = whole_days as i32;
915
916        // Fast path for when the result is in the same year.
917        if let Some(new_ordinal) = ordinal.checked_add(whole_days)
918            && new_ordinal >= 1
919            && new_ordinal <= days_in_year
920        {
921            // Safety: `new_ordinal` is in range and `is_leap_year` is correct
922            return Some(unsafe { Self::from_parts(year, is_leap_year, new_ordinal as u16) });
923        }
924
925        let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days));
926        if let Ok(date) = Self::from_julian_day(julian_day) {
927            Some(date)
928        } else {
929            None
930        }
931    }
932
933    /// Computes `self - duration`, returning `None` if an overflow occurred.
934    ///
935    /// ```
936    /// # use time::{Date, ext::NumericalDuration};
937    /// # use time_macros::date;
938    /// assert_eq!(Date::MAX.checked_sub((-2).days()), None);
939    /// assert_eq!(Date::MIN.checked_sub(1.days()), None);
940    /// assert_eq!(
941    ///     date!(2020-12-31).checked_sub(2.days()),
942    ///     Some(date!(2020-12-29))
943    /// );
944    /// ```
945    ///
946    /// # Note
947    ///
948    /// This function only takes whole days into account.
949    ///
950    /// ```
951    /// # use time::{Date, ext::NumericalDuration};
952    /// # use time_macros::date;
953    /// assert_eq!(Date::MAX.checked_sub((-23).hours()), Some(Date::MAX));
954    /// assert_eq!(Date::MIN.checked_sub(23.hours()), Some(Date::MIN));
955    /// assert_eq!(
956    ///     date!(2020-12-31).checked_sub(23.hours()),
957    ///     Some(date!(2020-12-31))
958    /// );
959    /// assert_eq!(
960    ///     date!(2020-12-31).checked_sub(47.hours()),
961    ///     Some(date!(2020-12-30))
962    /// );
963    /// ```
964    #[inline]
965    pub const fn checked_sub(self, duration: SignedDuration) -> Option<Self> {
966        let whole_days = duration.whole_days();
967        if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
968            return None;
969        }
970
971        let year = self.year();
972        let is_leap_year = self.is_in_leap_year();
973        let ordinal = self.ordinal() as i32;
974
975        let days_in_year = if is_leap_year { 366 } else { 365 };
976        let whole_days = whole_days as i32;
977
978        // Fast path for when the result is in the same year.
979        if let Some(new_ordinal) = ordinal.checked_sub(whole_days)
980            && new_ordinal >= 1
981            && new_ordinal <= days_in_year
982        {
983            // Safety: `new_ordinal` is in range and `is_leap_year` is correct
984            return Some(unsafe { Self::from_parts(year, is_leap_year, new_ordinal as u16) });
985        }
986
987        let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days));
988        if let Ok(date) = Self::from_julian_day(julian_day) {
989            Some(date)
990        } else {
991            None
992        }
993    }
994
995    /// Computes `self - duration`, returning `None` if an overflow occurred.
996    ///
997    /// ```
998    /// # use time::{Date, ext::NumericalStdDuration};
999    /// # use time_macros::date;
1000    /// assert_eq!(Date::MIN.checked_sub_std(1.std_days()), None);
1001    /// assert_eq!(
1002    ///     date!(2020-12-31).checked_sub_std(2.std_days()),
1003    ///     Some(date!(2020-12-29))
1004    /// );
1005    /// ```
1006    ///
1007    /// # Note
1008    ///
1009    /// This function only takes whole days into account.
1010    ///
1011    /// ```
1012    /// # use time::{Date, ext::NumericalStdDuration};
1013    /// # use time_macros::date;
1014    /// assert_eq!(Date::MIN.checked_sub_std(23.std_hours()), Some(Date::MIN));
1015    /// assert_eq!(
1016    ///     date!(2020-12-31).checked_sub_std(23.std_hours()),
1017    ///     Some(date!(2020-12-31))
1018    /// );
1019    /// assert_eq!(
1020    ///     date!(2020-12-31).checked_sub_std(47.std_hours()),
1021    ///     Some(date!(2020-12-30))
1022    /// );
1023    /// ```
1024    #[inline]
1025    pub const fn checked_sub_std(self, duration: StdDuration) -> Option<Self> {
1026        let whole_days = duration.as_secs() / Second::per_t::<u64>(Day);
1027        if whole_days > i32::MAX as u64 {
1028            return None;
1029        }
1030
1031        let year = self.year();
1032        let is_leap_year = self.is_in_leap_year();
1033        let ordinal = self.ordinal() as i32;
1034
1035        let days_in_year = if is_leap_year { 366 } else { 365 };
1036        let whole_days = whole_days as i32;
1037
1038        // Fast path for when the result is in the same year.
1039        if let Some(new_ordinal) = ordinal.checked_sub(whole_days)
1040            && new_ordinal >= 1
1041            && new_ordinal <= days_in_year
1042        {
1043            // Safety: `new_ordinal` is in range and `is_leap_year` is correct
1044            return Some(unsafe { Self::from_parts(year, is_leap_year, new_ordinal as u16) });
1045        }
1046
1047        let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days));
1048        if let Ok(date) = Self::from_julian_day(julian_day) {
1049            Some(date)
1050        } else {
1051            None
1052        }
1053    }
1054
1055    /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
1056    /// Returns `None` if an overflow occurred.
1057    #[inline]
1058    pub(crate) const fn checked_next_occurrence(self, weekday: Weekday) -> Option<Self> {
1059        let day_diff = match weekday as i8 - self.weekday() as i8 {
1060            1 | -6 => 1,
1061            2 | -5 => 2,
1062            3 | -4 => 3,
1063            4 | -3 => 4,
1064            5 | -2 => 5,
1065            6 | -1 => 6,
1066            val => {
1067                debug_assert!(val == 0);
1068                7
1069            }
1070        };
1071
1072        self.checked_add(SignedDuration::days(day_diff))
1073    }
1074
1075    /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
1076    /// Returns `None` if an overflow occurred.
1077    #[inline]
1078    pub(crate) const fn checked_prev_occurrence(self, weekday: Weekday) -> Option<Self> {
1079        let day_diff = match weekday as i8 - self.weekday() as i8 {
1080            1 | -6 => 6,
1081            2 | -5 => 5,
1082            3 | -4 => 4,
1083            4 | -3 => 3,
1084            5 | -2 => 2,
1085            6 | -1 => 1,
1086            val => {
1087                debug_assert!(val == 0);
1088                7
1089            }
1090        };
1091
1092        self.checked_sub(SignedDuration::days(day_diff))
1093    }
1094
1095    /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
1096    /// Returns `None` if an overflow occurred or if `n == 0`.
1097    #[inline]
1098    pub(crate) const fn checked_nth_next_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
1099        if n == 0 {
1100            return None;
1101        }
1102
1103        const_try_opt!(self.checked_next_occurrence(weekday))
1104            .checked_add(SignedDuration::weeks(n as i64 - 1))
1105    }
1106
1107    /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
1108    /// Returns `None` if an overflow occurred or if `n == 0`.
1109    #[inline]
1110    pub(crate) const fn checked_nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
1111        if n == 0 {
1112            return None;
1113        }
1114
1115        const_try_opt!(self.checked_prev_occurrence(weekday))
1116            .checked_sub(SignedDuration::weeks(n as i64 - 1))
1117    }
1118
1119    /// Computes `self + duration`, saturating value on overflow.
1120    ///
1121    /// ```rust
1122    /// # use time::{Date, ext::NumericalDuration};
1123    /// # use time_macros::date;
1124    /// assert_eq!(Date::MAX.saturating_add(1.days()), Date::MAX);
1125    /// assert_eq!(Date::MIN.saturating_add((-2).days()), Date::MIN);
1126    /// assert_eq!(
1127    ///     date!(2020-12-31).saturating_add(2.days()),
1128    ///     date!(2021-01-02)
1129    /// );
1130    /// ```
1131    ///
1132    /// # Note
1133    ///
1134    /// This function only takes whole days into account.
1135    ///
1136    /// ```rust
1137    /// # use time::ext::NumericalDuration;
1138    /// # use time_macros::date;
1139    /// assert_eq!(
1140    ///     date!(2020-12-31).saturating_add(23.hours()),
1141    ///     date!(2020-12-31)
1142    /// );
1143    /// assert_eq!(
1144    ///     date!(2020-12-31).saturating_add(47.hours()),
1145    ///     date!(2021-01-01)
1146    /// );
1147    /// ```
1148    #[inline]
1149    pub const fn saturating_add(self, duration: SignedDuration) -> Self {
1150        if let Some(datetime) = self.checked_add(duration) {
1151            datetime
1152        } else if duration.is_negative() {
1153            Self::MIN
1154        } else {
1155            debug_assert!(duration.is_positive());
1156            Self::MAX
1157        }
1158    }
1159
1160    /// Computes `self - duration`, saturating value on overflow.
1161    ///
1162    /// ```
1163    /// # use time::{Date, ext::NumericalDuration};
1164    /// # use time_macros::date;
1165    /// assert_eq!(Date::MAX.saturating_sub((-2).days()), Date::MAX);
1166    /// assert_eq!(Date::MIN.saturating_sub(1.days()), Date::MIN);
1167    /// assert_eq!(
1168    ///     date!(2020-12-31).saturating_sub(2.days()),
1169    ///     date!(2020-12-29)
1170    /// );
1171    /// ```
1172    ///
1173    /// # Note
1174    ///
1175    /// This function only takes whole days into account.
1176    ///
1177    /// ```
1178    /// # use time::ext::NumericalDuration;
1179    /// # use time_macros::date;
1180    /// assert_eq!(
1181    ///     date!(2020-12-31).saturating_sub(23.hours()),
1182    ///     date!(2020-12-31)
1183    /// );
1184    /// assert_eq!(
1185    ///     date!(2020-12-31).saturating_sub(47.hours()),
1186    ///     date!(2020-12-30)
1187    /// );
1188    /// ```
1189    #[inline]
1190    pub const fn saturating_sub(self, duration: SignedDuration) -> Self {
1191        if let Some(datetime) = self.checked_sub(duration) {
1192            datetime
1193        } else if duration.is_negative() {
1194            Self::MAX
1195        } else {
1196            debug_assert!(duration.is_positive());
1197            Self::MIN
1198        }
1199    }
1200
1201    /// Replace the year. The month and day will be unchanged.
1202    ///
1203    /// ```rust
1204    /// # use time_macros::date;
1205    /// assert_eq!(
1206    ///     date!(2022-02-18).replace_year(2019),
1207    ///     Ok(date!(2019-02-18))
1208    /// );
1209    /// assert!(date!(2022-02-18).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
1210    /// assert!(date!(2022-02-18).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
1211    /// ```
1212    #[inline]
1213    #[must_use = "This method does not mutate the original `Date`."]
1214    pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1215        ensure_ranged!(Year: year);
1216
1217        let new_is_leap_year = range_validated::is_leap_year(year);
1218        let ordinal = self.ordinal();
1219
1220        // Dates in January and February are unaffected by leap years.
1221        if ordinal <= 59 {
1222            // Safety: `ordinal` is not zero and `is_leap_year` is correct.
1223            return Ok(unsafe { Self::from_parts(year, new_is_leap_year, ordinal) });
1224        }
1225
1226        match (self.is_in_leap_year(), new_is_leap_year) {
1227            (false, false) | (true, true) => {
1228                Ok(Self {
1229                    // Safety: Whether the year is leap or common, the ordinal are unchanged, with
1230                    // only the year being replaced.
1231                    value: unsafe {
1232                        NonZero::new_unchecked((year << 10) | (self.value.get() & 0x3FF))
1233                    },
1234                })
1235            }
1236            // February 29 does not exist in common years.
1237            (true, false) if ordinal == 60 => Err(error::ComponentRange::conditional("day")),
1238            // We're going from a common year to a leap year. Shift dates in March and later back by
1239            // one day because February 29 now exists in the leap year.
1240            // Safety: `ordinal` is not zero and `is_leap_year` is correct.
1241            (false, true) => Ok(unsafe { Self::from_parts(year, true, ordinal + 1) }),
1242            // We're going from a leap year to a common year. Shift dates in March and later up by
1243            // one day because February 29 does not exist in common years.
1244            // Safety: `ordinal` is not zero and `is_leap_year` is correct.
1245            (true, false) => Ok(unsafe { Self::from_parts(year, false, ordinal - 1) }),
1246        }
1247    }
1248
1249    /// Replace the month of the year.
1250    ///
1251    /// ```rust
1252    /// # use time_macros::date;
1253    /// # use time::Month;
1254    /// assert_eq!(
1255    ///     date!(2022-02-18).replace_month(Month::January),
1256    ///     Ok(date!(2022-01-18))
1257    /// );
1258    /// assert!(date!(2022-01-30)
1259    ///     .replace_month(Month::February)
1260    ///     .is_err()); // 30 isn't a valid day in February
1261    /// ```
1262    #[inline]
1263    #[must_use = "This method does not mutate the original `Date`."]
1264    pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1265        /// Cumulative days through the beginning of a month in both common and leap years.
1266        const DAYS_CUMULATIVE_COMMON_LEAP: [[u16; 12]; 2] = [
1267            [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
1268            [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
1269        ];
1270
1271        let (year, ordinal) = self.to_ordinal_date();
1272        let mut ordinal = ordinal as u32;
1273        let is_leap_year = self.is_in_leap_year();
1274        let jan_feb_len = 59 + is_leap_year as u32;
1275
1276        if ordinal > jan_feb_len {
1277            ordinal -= jan_feb_len;
1278        }
1279        let current_month = (ordinal * 268 + 8031) >> 13;
1280        let days_in_preceding_months = (current_month * 3917 - 3866) >> 7;
1281        let day = (ordinal - days_in_preceding_months) as u8;
1282
1283        match day {
1284            1..=28 => {}
1285            29..=31 if day <= days_in_month_leap(month as u8, is_leap_year) => hint::cold_path(),
1286            _ => {
1287                hint::cold_path();
1288                return Err(error::ComponentRange::conditional("day"));
1289            }
1290        }
1291
1292        // Safety: `ordinal` is not zero and `is_leap_year` is correct.
1293        Ok(unsafe {
1294            Self::from_parts(
1295                year,
1296                is_leap_year,
1297                DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year as usize][month as usize - 1] + day as u16,
1298            )
1299        })
1300    }
1301
1302    /// Replace the day of the month.
1303    ///
1304    /// ```rust
1305    /// # use time_macros::date;
1306    /// assert_eq!(date!(2022-02-18).replace_day(1), Ok(date!(2022-02-01)));
1307    /// assert!(date!(2022-02-18).replace_day(0).is_err()); // 0 isn't a valid day
1308    /// assert!(date!(2022-02-18).replace_day(30).is_err()); // 30 isn't a valid day in February
1309    /// ```
1310    #[inline]
1311    #[must_use = "This method does not mutate the original `Date`."]
1312    pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1313        let is_leap_year = self.is_in_leap_year();
1314        match day {
1315            1..=28 => {}
1316            29..=31 if day <= days_in_month_leap(self.month() as u8, is_leap_year) => {
1317                hint::cold_path()
1318            }
1319            _ => {
1320                hint::cold_path();
1321                return Err(error::ComponentRange::conditional("day"));
1322            }
1323        }
1324
1325        // Safety: `ordinal` is not zero and `is_leap_year` is correct.
1326        Ok(unsafe {
1327            Self::from_parts(
1328                self.year(),
1329                is_leap_year,
1330                (self.ordinal().cast_signed() - self.day() as i16 + day as i16).cast_unsigned(),
1331            )
1332        })
1333    }
1334
1335    /// Replace the day of the year.
1336    ///
1337    /// ```rust
1338    /// # use time_macros::date;
1339    /// assert_eq!(date!(2022-049).replace_ordinal(1), Ok(date!(2022-001)));
1340    /// assert!(date!(2022-049).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
1341    /// assert!(date!(2022-049).replace_ordinal(366).is_err()); // 2022 isn't a leap year
1342    /// ```
1343    #[inline]
1344    #[must_use = "This method does not mutate the original `Date`."]
1345    pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1346        let is_leap_year = self.is_in_leap_year();
1347        match ordinal {
1348            1..=365 => {}
1349            366 if is_leap_year => hint::cold_path(),
1350            _ => {
1351                hint::cold_path();
1352                return Err(error::ComponentRange::conditional("ordinal"));
1353            }
1354        }
1355
1356        // Safety: `ordinal` is in range and `is_leap_year` is correct.
1357        Ok(unsafe { Self::from_parts(self.year(), is_leap_year, ordinal) })
1358    }
1359}
1360
1361/// Methods to add a [`Time`] component, resulting in a [`PlainDateTime`].
1362impl Date {
1363    /// Create a [`PlainDateTime`] using the existing date. The [`Time`] component will be set to
1364    /// midnight.
1365    ///
1366    /// ```rust
1367    /// # use time_macros::{date, datetime};
1368    /// assert_eq!(date!(1970-01-01).midnight(), datetime!(1970-01-01 0:00));
1369    /// ```
1370    #[inline]
1371    pub const fn midnight(self) -> PlainDateTime {
1372        PlainDateTime::new(self, Time::MIDNIGHT)
1373    }
1374
1375    /// Create a [`PlainDateTime`] using the existing date and the provided [`Time`].
1376    ///
1377    /// ```rust
1378    /// # use time_macros::{date, datetime, time};
1379    /// assert_eq!(
1380    ///     date!(1970-01-01).with_time(time!(0:00)),
1381    ///     datetime!(1970-01-01 0:00),
1382    /// );
1383    /// ```
1384    #[inline]
1385    pub const fn with_time(self, time: Time) -> PlainDateTime {
1386        PlainDateTime::new(self, time)
1387    }
1388
1389    /// Attempt to create a [`PlainDateTime`] using the existing date and the provided time.
1390    ///
1391    /// ```rust
1392    /// # use time_macros::date;
1393    /// assert!(date!(1970-01-01).with_hms(0, 0, 0).is_ok());
1394    /// assert!(date!(1970-01-01).with_hms(24, 0, 0).is_err());
1395    /// ```
1396    #[inline]
1397    pub const fn with_hms(
1398        self,
1399        hour: u8,
1400        minute: u8,
1401        second: u8,
1402    ) -> Result<PlainDateTime, error::ComponentRange> {
1403        Ok(PlainDateTime::new(
1404            self,
1405            const_try!(Time::from_hms(hour, minute, second)),
1406        ))
1407    }
1408
1409    /// Attempt to create a [`PlainDateTime`] using the existing date and the provided time.
1410    ///
1411    /// ```rust
1412    /// # use time_macros::date;
1413    /// assert!(date!(1970-01-01).with_hms_milli(0, 0, 0, 0).is_ok());
1414    /// assert!(date!(1970-01-01).with_hms_milli(24, 0, 0, 0).is_err());
1415    /// ```
1416    #[inline]
1417    pub const fn with_hms_milli(
1418        self,
1419        hour: u8,
1420        minute: u8,
1421        second: u8,
1422        millisecond: u16,
1423    ) -> Result<PlainDateTime, error::ComponentRange> {
1424        Ok(PlainDateTime::new(
1425            self,
1426            const_try!(Time::from_hms_milli(hour, minute, second, millisecond)),
1427        ))
1428    }
1429
1430    /// Attempt to create a [`PlainDateTime`] using the existing date and the provided time.
1431    ///
1432    /// ```rust
1433    /// # use time_macros::date;
1434    /// assert!(date!(1970-01-01).with_hms_micro(0, 0, 0, 0).is_ok());
1435    /// assert!(date!(1970-01-01).with_hms_micro(24, 0, 0, 0).is_err());
1436    /// ```
1437    #[inline]
1438    pub const fn with_hms_micro(
1439        self,
1440        hour: u8,
1441        minute: u8,
1442        second: u8,
1443        microsecond: u32,
1444    ) -> Result<PlainDateTime, error::ComponentRange> {
1445        Ok(PlainDateTime::new(
1446            self,
1447            const_try!(Time::from_hms_micro(hour, minute, second, microsecond)),
1448        ))
1449    }
1450
1451    /// Attempt to create a [`PlainDateTime`] using the existing date and the provided time.
1452    ///
1453    /// ```rust
1454    /// # use time_macros::date;
1455    /// assert!(date!(1970-01-01).with_hms_nano(0, 0, 0, 0).is_ok());
1456    /// assert!(date!(1970-01-01).with_hms_nano(24, 0, 0, 0).is_err());
1457    /// ```
1458    #[inline]
1459    pub const fn with_hms_nano(
1460        self,
1461        hour: u8,
1462        minute: u8,
1463        second: u8,
1464        nanosecond: u32,
1465    ) -> Result<PlainDateTime, error::ComponentRange> {
1466        Ok(PlainDateTime::new(
1467            self,
1468            const_try!(Time::from_hms_nano(hour, minute, second, nanosecond)),
1469        ))
1470    }
1471}
1472
1473#[cfg(feature = "formatting")]
1474impl Date {
1475    /// Format the `Date` using the provided [format description](crate::format_description).
1476    #[inline]
1477    pub fn format_into(
1478        self,
1479        output: &mut (impl io::Write + ?Sized),
1480        format: &(impl Formattable + ?Sized),
1481    ) -> Result<usize, error::Format> {
1482        let mut output = crate::formatting::Output {
1483            bytes_written: 0,
1484            output,
1485        };
1486        try_likely_ok!(format.format_into(
1487            &mut output,
1488            &self,
1489            &mut Default::default(),
1490            PrivateMethod,
1491        ));
1492        Ok(output.bytes_written)
1493    }
1494
1495    /// Format the `Date` using the provided [format description](crate::format_description).
1496    ///
1497    /// ```rust
1498    /// # use time::format_description;
1499    /// # use time_macros::date;
1500    /// let format = format_description::parse_borrowed::<3>("[year]-[month]-[day]")?;
1501    /// assert_eq!(date!(2020-01-02).format(&format)?, "2020-01-02");
1502    /// # Ok::<_, time::Error>(())
1503    /// ```
1504    #[inline]
1505    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1506        format.format(&self, &mut Default::default(), PrivateMethod)
1507    }
1508}
1509
1510#[cfg(feature = "parsing")]
1511impl Date {
1512    /// Parse a `Date` from the input using the provided [format
1513    /// description](crate::format_description).
1514    ///
1515    /// ```rust
1516    /// # use time::Date;
1517    /// # use time_macros::{date, format_description};
1518    /// let format = format_description!("[year]-[month]-[day]");
1519    /// assert_eq!(Date::parse("2020-01-02", &format)?, date!(2020-01-02));
1520    /// # Ok::<_, time::Error>(())
1521    /// ```
1522    #[inline]
1523    pub fn parse(
1524        input: &str,
1525        description: &(impl Parsable + ?Sized),
1526    ) -> Result<Self, error::Parse> {
1527        description.parse_date(input.as_bytes(), None, PrivateMethod)
1528    }
1529
1530    /// Parse a `Date` from the input using the provided [format
1531    /// description](crate::format_description) and default values.
1532    ///
1533    /// ```rust
1534    /// # use time::Date;
1535    /// # use time::parsing::Parsed;
1536    /// # use time_macros::{date, format_description};
1537    /// let format = format_description!("[month]-[day]");
1538    /// let defaults = Parsed::new().with_year(2020).expect("2020 is a valid year");
1539    /// assert_eq!(
1540    ///     Date::parse_with_defaults(b"01-15", &format, defaults)?,
1541    ///     date!(2020-01-15)
1542    /// );
1543    /// # Ok::<_, time::Error>(())
1544    /// ```
1545    #[inline]
1546    pub fn parse_with_defaults(
1547        input: &[u8],
1548        description: &(impl Parsable + ?Sized),
1549        defaults: Parsed,
1550    ) -> Result<Self, error::Parse> {
1551        description.parse_date(input, Some(defaults), PrivateMethod)
1552    }
1553}
1554
1555// This no longer needs special handling, as the format is fixed and doesn't require anything
1556// advanced. Trait impls can't be deprecated and the info is still useful for other types
1557// implementing `SmartDisplay`, so leave it as-is for now.
1558impl SmartDisplay for Date {
1559    type Metadata = ();
1560
1561    #[inline]
1562    fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
1563        use crate::ext::DigitCount as _;
1564
1565        let year_sign_width =
1566            if self.year() < 0 || (cfg!(feature = "large-dates") && self.year() >= 10_000) {
1567                1
1568            } else {
1569                0
1570            };
1571        let year_width = self.year().unsigned_abs().num_digits().clamp(4, 6);
1572        let formatted_width = year_sign_width + year_width + 6; // include two dashes and two digits each for month and day
1573
1574        Metadata::new(formatted_width as usize, self, ())
1575    }
1576
1577    #[inline]
1578    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1579        fmt::Display::fmt(self, f)
1580    }
1581}
1582
1583impl Date {
1584    /// The maximum number of bytes that the `fmt_into_buffer` method will write, which is also used
1585    /// for the `Display` implementation.
1586    pub(crate) const DISPLAY_BUFFER_SIZE: usize = 13;
1587
1588    /// Format the `Date` into the provided buffer, returning the number of bytes written.
1589    #[inline]
1590    pub(crate) fn fmt_into_buffer(
1591        self,
1592        buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
1593    ) -> usize {
1594        let mut idx = 0;
1595        let (year, month, day) = self.to_calendar_date();
1596
1597        // Compute the sign of the integer, if any. Doing this in a branchless manner gives a
1598        // significant performance improvement.
1599        let neg = year.is_negative() as u8;
1600        let pos = (cfg!(feature = "large-dates") && year - 10_000 >= 0) as u8;
1601        let sign = b'+' + 2 * neg; // b'-' if `neg` is true, b'+' otherwise
1602        // Always write the computed byte, even if it's later overwritten by the first digit of the
1603        // year.
1604        buf[idx] = MaybeUninit::new(sign);
1605        idx += (neg | pos) as usize;
1606
1607        // Safety: `year.unsigned_abs()` is less than 1,000,000.
1608        let [first_two, second_two, third_two] =
1609            four_to_six_digits(unsafe { ru32::new_unchecked(year.unsigned_abs()) });
1610        // Safety:
1611        // - both `first_two` and `buf` are valid for reads and writes of up to 2 bytes.
1612        // - `u8` is 1-aligned, so that is not a concern.
1613        // - `first_two` points to static memory, while `buf` is a local variable, so they do not
1614        //   overlap.
1615        unsafe {
1616            first_two
1617                .as_ptr()
1618                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), first_two.len());
1619        }
1620        idx += first_two.len();
1621        // Safety: See above.
1622        unsafe {
1623            second_two
1624                .as_ptr()
1625                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2);
1626        }
1627        idx += 2;
1628        // Safety: See above.
1629        unsafe {
1630            third_two
1631                .as_ptr()
1632                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2);
1633        }
1634        idx += 2;
1635
1636        buf[idx] = MaybeUninit::new(b'-');
1637        idx += 1;
1638
1639        // Safety: See above for `copy_to_nonoverlapping`. `month` is in the range 1..=12.
1640        unsafe {
1641            two_digits_zero_padded(ru8::new_unchecked(u8::from(month)))
1642                .as_ptr()
1643                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2);
1644        }
1645        idx += 2;
1646
1647        buf[idx] = MaybeUninit::new(b'-');
1648        idx += 1;
1649
1650        // Safety: See above for `copy_to_nonoverlapping`. `day` is in the range 1..=31.
1651        unsafe {
1652            two_digits_zero_padded(ru8::new_unchecked(day))
1653                .as_ptr()
1654                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2);
1655        }
1656        idx += 2;
1657
1658        idx
1659    }
1660}
1661
1662impl fmt::Display for Date {
1663    #[inline]
1664    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1665        let mut buf = [MaybeUninit::uninit(); 13];
1666        let len = self.fmt_into_buffer(&mut buf);
1667        // Safety: All bytes up to `len` have been initialized with ASCII characters.
1668        let s = unsafe { str_from_raw_parts((&raw const buf).cast(), len) };
1669        f.pad(s)
1670    }
1671}
1672
1673impl fmt::Debug for Date {
1674    #[inline]
1675    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1676        fmt::Display::fmt(self, f)
1677    }
1678}
1679
1680impl Add<SignedDuration> for Date {
1681    type Output = Self;
1682
1683    /// # Panics
1684    ///
1685    /// This may panic if an overflow occurs.
1686    #[inline]
1687    #[track_caller]
1688    fn add(self, duration: SignedDuration) -> Self::Output {
1689        self.checked_add(duration)
1690            .expect("overflow adding duration to date")
1691    }
1692}
1693
1694impl Add<StdDuration> for Date {
1695    type Output = Self;
1696
1697    /// # Panics
1698    ///
1699    /// This may panic if an overflow occurs.
1700    #[inline]
1701    #[track_caller]
1702    fn add(self, duration: StdDuration) -> Self::Output {
1703        self.checked_add_std(duration)
1704            .expect("overflow adding duration to date")
1705    }
1706}
1707
1708impl AddAssign<SignedDuration> for Date {
1709    /// # Panics
1710    ///
1711    /// This may panic if an overflow occurs.
1712    #[inline]
1713    #[track_caller]
1714    fn add_assign(&mut self, rhs: SignedDuration) {
1715        *self = *self + rhs;
1716    }
1717}
1718
1719impl AddAssign<StdDuration> for Date {
1720    /// # Panics
1721    ///
1722    /// This may panic if an overflow occurs.
1723    #[inline]
1724    #[track_caller]
1725    fn add_assign(&mut self, rhs: StdDuration) {
1726        *self = *self + rhs;
1727    }
1728}
1729
1730impl Sub<SignedDuration> for Date {
1731    type Output = Self;
1732
1733    /// # Panics
1734    ///
1735    /// This may panic if an overflow occurs.
1736    #[inline]
1737    #[track_caller]
1738    fn sub(self, duration: SignedDuration) -> Self::Output {
1739        self.checked_sub(duration)
1740            .expect("overflow subtracting duration from date")
1741    }
1742}
1743
1744impl Sub<StdDuration> for Date {
1745    type Output = Self;
1746
1747    /// # Panics
1748    ///
1749    /// This may panic if an overflow occurs.
1750    #[inline]
1751    #[track_caller]
1752    fn sub(self, duration: StdDuration) -> Self::Output {
1753        self.checked_sub_std(duration)
1754            .expect("overflow subtracting duration from date")
1755    }
1756}
1757
1758impl SubAssign<SignedDuration> for Date {
1759    /// # Panics
1760    ///
1761    /// This may panic if an overflow occurs.
1762    #[inline]
1763    #[track_caller]
1764    fn sub_assign(&mut self, rhs: SignedDuration) {
1765        *self = *self - rhs;
1766    }
1767}
1768
1769impl SubAssign<StdDuration> for Date {
1770    /// # Panics
1771    ///
1772    /// This may panic if an overflow occurs.
1773    #[inline]
1774    #[track_caller]
1775    fn sub_assign(&mut self, rhs: StdDuration) {
1776        *self = *self - rhs;
1777    }
1778}
1779
1780impl Sub for Date {
1781    type Output = SignedDuration;
1782
1783    #[inline]
1784    fn sub(self, other: Self) -> Self::Output {
1785        SignedDuration::days((self.to_julian_day() - other.to_julian_day()).widen())
1786    }
1787}