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