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