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