Coverage Report

Created: 2025-07-01 06:28

/rust/registry/src/index.crates.io-6f17d22bba15001f/time-0.3.41/src/date.rs
Line
Count
Source (jump to first uncovered line)
1
//! The [`Date`] struct and its associated `impl`s.
2
3
#[cfg(feature = "formatting")]
4
use alloc::string::String;
5
use core::num::{NonZeroI32, NonZeroU8};
6
use core::ops::{Add, Sub};
7
use core::time::Duration as StdDuration;
8
use core::{cmp, fmt};
9
#[cfg(feature = "formatting")]
10
use std::io;
11
12
use deranged::RangedI32;
13
use num_conv::prelude::*;
14
use powerfmt::ext::FormatterExt;
15
use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
16
17
use crate::convert::*;
18
use crate::ext::DigitCount;
19
#[cfg(feature = "formatting")]
20
use crate::formatting::Formattable;
21
use crate::internal_macros::{
22
    const_try, const_try_opt, div_floor, ensure_ranged, expect_opt, impl_add_assign,
23
    impl_sub_assign,
24
};
25
#[cfg(feature = "parsing")]
26
use crate::parsing::Parsable;
27
use crate::util::{days_in_year, is_leap_year, weeks_in_year};
28
use crate::{error, Duration, Month, PrimitiveDateTime, Time, Weekday};
29
30
type Year = RangedI32<MIN_YEAR, MAX_YEAR>;
31
32
/// The minimum valid year.
33
pub(crate) const MIN_YEAR: i32 = if cfg!(feature = "large-dates") {
34
    -999_999
35
} else {
36
    -9999
37
};
38
/// The maximum valid year.
39
pub(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)]
51
pub 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: NonZeroI32,
58
}
59
60
impl Date {
61
    /// The minimum valid `Date`.
62
    ///
63
    /// The value of this may vary depending on the feature flags enabled.
64
    // Safety: `ordinal` is not zero.
65
    #[allow(clippy::undocumented_unsafe_blocks)]
66
    pub const MIN: Self = unsafe { Self::__from_ordinal_date_unchecked(MIN_YEAR, 1) };
67
68
    /// The maximum valid `Date`.
69
    ///
70
    /// The value of this may vary depending on the feature flags enabled.
71
    // Safety: `ordinal` is not zero.
72
    #[allow(clippy::undocumented_unsafe_blocks)]
73
    pub const MAX: Self =
74
        unsafe { Self::__from_ordinal_date_unchecked(MAX_YEAR, days_in_year(MAX_YEAR)) };
75
76
    /// Construct a `Date` from its internal representation, the validity of which must be
77
    /// guaranteed by the caller.
78
    ///
79
    /// # Safety
80
    ///
81
    /// - `ordinal` must be non-zero and at most the number of days in `year`
82
    /// - `is_leap_year` must be `true` if and only if `year` is a leap year
83
9.86k
    const unsafe fn from_parts(year: i32, is_leap_year: bool, ordinal: u16) -> Self {
84
9.86k
        debug_assert!(year >= MIN_YEAR);
85
9.86k
        debug_assert!(year <= MAX_YEAR);
86
9.86k
        debug_assert!(ordinal != 0);
87
9.86k
        debug_assert!(ordinal <= days_in_year(year));
88
9.86k
        debug_assert!(crate::util::is_leap_year(year) == is_leap_year);
89
90
9.86k
        Self {
91
9.86k
            // Safety: `ordinal` is not zero.
92
9.86k
            value: unsafe {
93
9.86k
                NonZeroI32::new_unchecked(
94
9.86k
                    (year << 10) | ((is_leap_year as i32) << 9) | ordinal as i32,
95
9.86k
                )
96
9.86k
            },
97
9.86k
        }
98
9.86k
    }
99
100
    /// Construct a `Date` from the year and ordinal values, the validity of which must be
101
    /// guaranteed by the caller.
102
    ///
103
    /// # Safety
104
    ///
105
    /// `ordinal` must be non-zero and at most the number of days in `year`. `year` should be in the
106
    /// range `MIN_YEAR..=MAX_YEAR`, but this is not a safety invariant.
107
    #[doc(hidden)]
108
8.83k
    pub const unsafe fn __from_ordinal_date_unchecked(year: i32, ordinal: u16) -> Self {
109
8.83k
        // Safety: The caller must guarantee that `ordinal` is not zero.
110
8.83k
        unsafe { Self::from_parts(year, is_leap_year(year), ordinal) }
111
8.83k
    }
112
113
    /// Attempt to create a `Date` from the year, month, and day.
114
    ///
115
    /// ```rust
116
    /// # use time::{Date, Month};
117
    /// assert!(Date::from_calendar_date(2019, Month::January, 1).is_ok());
118
    /// assert!(Date::from_calendar_date(2019, Month::December, 31).is_ok());
119
    /// ```
120
    ///
121
    /// ```rust
122
    /// # use time::{Date, Month};
123
    /// assert!(Date::from_calendar_date(2019, Month::February, 29).is_err()); // 2019 isn't a leap year.
124
    /// ```
125
4.85k
    pub const fn from_calendar_date(
126
4.85k
        year: i32,
127
4.85k
        month: Month,
128
4.85k
        day: u8,
129
4.85k
    ) -> Result<Self, error::ComponentRange> {
130
        /// Cumulative days through the beginning of a month in both common and leap years.
131
        const DAYS_CUMULATIVE_COMMON_LEAP: [[u16; 12]; 2] = [
132
            [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
133
            [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
134
        ];
135
136
4.85k
        ensure_ranged!(Year: year);
137
1.82k
        match day {
138
4.85k
            1..=28 => {}
139
1.83k
            29..=31 if day <= month.length(year) => {}
140
            _ => {
141
11
                return Err(error::ComponentRange {
142
11
                    name: "day",
143
11
                    minimum: 1,
144
11
                    maximum: month.length(year) as i64,
145
11
                    value: day as i64,
146
11
                    conditional_message: Some("for the given month and year"),
147
11
                });
148
            }
149
        }
150
151
        // Safety: `ordinal` is not zero.
152
4.84k
        Ok(unsafe {
153
4.84k
            Self::__from_ordinal_date_unchecked(
154
4.84k
                year,
155
4.84k
                DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year(year) as usize][month as usize - 1]
156
4.84k
                    + day as u16,
157
4.84k
            )
158
4.84k
        })
159
4.85k
    }
160
161
    /// Attempt to create a `Date` from the year and ordinal day number.
162
    ///
163
    /// ```rust
164
    /// # use time::Date;
165
    /// assert!(Date::from_ordinal_date(2019, 1).is_ok());
166
    /// assert!(Date::from_ordinal_date(2019, 365).is_ok());
167
    /// ```
168
    ///
169
    /// ```rust
170
    /// # use time::Date;
171
    /// assert!(Date::from_ordinal_date(2019, 366).is_err()); // 2019 isn't a leap year.
172
    /// ```
173
3.85k
    pub const fn from_ordinal_date(year: i32, ordinal: u16) -> Result<Self, error::ComponentRange> {
174
3.85k
        ensure_ranged!(Year: year);
175
447
        match ordinal {
176
3.85k
            1..=365 => {}
177
447
            366 if is_leap_year(year) => {}
178
            _ => {
179
0
                return Err(error::ComponentRange {
180
0
                    name: "ordinal",
181
0
                    minimum: 1,
182
0
                    maximum: days_in_year(year) as i64,
183
0
                    value: ordinal as i64,
184
0
                    conditional_message: Some("for the given year"),
185
0
                });
186
            }
187
        }
188
189
        // Safety: `ordinal` is not zero.
190
3.85k
        Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
191
3.85k
    }
192
193
    /// Attempt to create a `Date` from the ISO year, week, and weekday.
194
    ///
195
    /// ```rust
196
    /// # use time::{Date, Weekday::*};
197
    /// assert!(Date::from_iso_week_date(2019, 1, Monday).is_ok());
198
    /// assert!(Date::from_iso_week_date(2019, 1, Tuesday).is_ok());
199
    /// assert!(Date::from_iso_week_date(2020, 53, Friday).is_ok());
200
    /// ```
201
    ///
202
    /// ```rust
203
    /// # use time::{Date, Weekday::*};
204
    /// assert!(Date::from_iso_week_date(2019, 53, Monday).is_err()); // 2019 doesn't have 53 weeks.
205
    /// ```
206
0
    pub const fn from_iso_week_date(
207
0
        year: i32,
208
0
        week: u8,
209
0
        weekday: Weekday,
210
0
    ) -> Result<Self, error::ComponentRange> {
211
0
        ensure_ranged!(Year: year);
212
0
        match week {
213
0
            1..=52 => {}
214
0
            53 if week <= weeks_in_year(year) => {}
215
            _ => {
216
0
                return Err(error::ComponentRange {
217
0
                    name: "week",
218
0
                    minimum: 1,
219
0
                    maximum: weeks_in_year(year) as i64,
220
0
                    value: week as i64,
221
0
                    conditional_message: Some("for the given year"),
222
0
                });
223
            }
224
        }
225
226
0
        let adj_year = year - 1;
227
0
        let raw = 365 * adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100)
228
0
            + div_floor!(adj_year, 400);
229
0
        let jan_4 = match (raw % 7) as i8 {
230
0
            -6 | 1 => 8,
231
0
            -5 | 2 => 9,
232
0
            -4 | 3 => 10,
233
0
            -3 | 4 => 4,
234
0
            -2 | 5 => 5,
235
0
            -1 | 6 => 6,
236
0
            _ => 7,
237
        };
238
0
        let ordinal = week as i16 * 7 + weekday.number_from_monday() as i16 - jan_4;
239
0
240
0
        Ok(if ordinal <= 0 {
241
            // Safety: `ordinal` is not zero.
242
            unsafe {
243
0
                Self::__from_ordinal_date_unchecked(
244
0
                    year - 1,
245
0
                    (ordinal as u16).wrapping_add(days_in_year(year - 1)),
246
0
                )
247
            }
248
0
        } else if ordinal > days_in_year(year) as i16 {
249
            // Safety: `ordinal` is not zero.
250
            unsafe {
251
0
                Self::__from_ordinal_date_unchecked(year + 1, ordinal as u16 - days_in_year(year))
252
            }
253
        } else {
254
            // Safety: `ordinal` is not zero.
255
0
            unsafe { Self::__from_ordinal_date_unchecked(year, ordinal as u16) }
256
        })
257
0
    }
258
259
    /// Create a `Date` from the Julian day.
260
    ///
261
    /// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
262
    /// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
263
    ///
264
    /// ```rust
265
    /// # use time::Date;
266
    /// # use time_macros::date;
267
    /// assert_eq!(Date::from_julian_day(0), Ok(date!(-4713 - 11 - 24)));
268
    /// assert_eq!(Date::from_julian_day(2_451_545), Ok(date!(2000-01-01)));
269
    /// assert_eq!(Date::from_julian_day(2_458_485), Ok(date!(2019-01-01)));
270
    /// assert_eq!(Date::from_julian_day(2_458_849), Ok(date!(2019-12-31)));
271
    /// ```
272
    #[doc(alias = "from_julian_date")]
273
1.52k
    pub const fn from_julian_day(julian_day: i32) -> Result<Self, error::ComponentRange> {
274
        type JulianDay = RangedI32<{ Date::MIN.to_julian_day() }, { Date::MAX.to_julian_day() }>;
275
1.52k
        ensure_ranged!(JulianDay: julian_day);
276
        // Safety: The Julian day number is in range.
277
1.03k
        Ok(unsafe { Self::from_julian_day_unchecked(julian_day) })
278
1.52k
    }
279
280
    /// Create a `Date` from the Julian day.
281
    ///
282
    /// # Safety
283
    ///
284
    /// The provided Julian day number must be between `Date::MIN.to_julian_day()` and
285
    /// `Date::MAX.to_julian_day()` inclusive.
286
1.03k
    pub(crate) const unsafe fn from_julian_day_unchecked(julian_day: i32) -> Self {
287
1.03k
        debug_assert!(julian_day >= Self::MIN.to_julian_day());
288
1.03k
        debug_assert!(julian_day <= Self::MAX.to_julian_day());
289
290
        const S: i32 = 2_500;
291
        const K: i32 = 719_468 + 146_097 * S;
292
        const L: i32 = 400 * S;
293
294
1.03k
        let julian_day = julian_day - 2_440_588;
295
1.03k
        let n = (julian_day + K) as u32;
296
1.03k
297
1.03k
        let n_1 = 4 * n + 3;
298
1.03k
        let c = n_1 / 146_097;
299
1.03k
        let n_c = n_1 % 146_097 / 4;
300
1.03k
301
1.03k
        let n_2 = 4 * n_c + 3;
302
1.03k
        let p_2 = 2_939_745 * n_2 as u64;
303
1.03k
        let z = (p_2 >> 32) as u32;
304
1.03k
        let n_y = p_2 as u32 / 2_939_745 / 4;
305
1.03k
        let y = 100 * c + z;
306
1.03k
307
1.03k
        let j = n_y >= 306;
308
1.03k
        let y_g = y as i32 - L + j as i32;
309
1.03k
310
1.03k
        let is_leap_year = is_leap_year(y_g);
311
1.03k
        let ordinal = if j {
312
465
            n_y - 305
313
        } else {
314
565
            n_y + 60 + is_leap_year as u32
315
        };
316
317
        // Safety: `ordinal` is not zero and `is_leap_year` is correct, so long as the Julian day
318
        // number is in range.
319
1.03k
        unsafe { Self::from_parts(y_g, is_leap_year, ordinal as u16) }
320
1.03k
    }
321
322
    /// Whether `is_leap_year(self.year())` is `true`.
323
    ///
324
    /// This method is optimized to take advantage of the fact that the value is pre-computed upon
325
    /// construction and stored in the bitpacked struct.
326
9.68k
    const fn is_in_leap_year(self) -> bool {
327
9.68k
        (self.value.get() >> 9) & 1 == 1
328
9.68k
    }
329
330
    /// Get the year of the date.
331
    ///
332
    /// ```rust
333
    /// # use time_macros::date;
334
    /// assert_eq!(date!(2019-01-01).year(), 2019);
335
    /// assert_eq!(date!(2019-12-31).year(), 2019);
336
    /// assert_eq!(date!(2020-01-01).year(), 2020);
337
    /// ```
338
12.5k
    pub const fn year(self) -> i32 {
339
12.5k
        self.value.get() >> 10
340
12.5k
    }
341
342
    /// Get the month.
343
    ///
344
    /// ```rust
345
    /// # use time::Month;
346
    /// # use time_macros::date;
347
    /// assert_eq!(date!(2019-01-01).month(), Month::January);
348
    /// assert_eq!(date!(2019-12-31).month(), Month::December);
349
    /// ```
350
3.81k
    pub const fn month(self) -> Month {
351
3.81k
        let ordinal = self.ordinal() as u32;
352
3.81k
        let jan_feb_len = 59 + self.is_in_leap_year() as u32;
353
354
3.81k
        let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len {
355
1.44k
            (0, 0)
356
        } else {
357
2.37k
            (2, jan_feb_len)
358
        };
359
360
3.81k
        let ordinal = ordinal - ordinal_adj;
361
3.81k
        let month = ((ordinal * 268 + 8031) >> 13) + month_adj;
362
3.81k
363
3.81k
        // Safety: `month` is guaranteed to be between 1 and 12 inclusive.
364
3.81k
        unsafe {
365
3.81k
            match Month::from_number(NonZeroU8::new_unchecked(month as u8)) {
366
3.81k
                Ok(month) => month,
367
0
                Err(_) => core::hint::unreachable_unchecked(),
368
            }
369
        }
370
3.81k
    }
371
372
    /// Get the day of the month.
373
    ///
374
    /// The returned value will always be in the range `1..=31`.
375
    ///
376
    /// ```rust
377
    /// # use time_macros::date;
378
    /// assert_eq!(date!(2019-01-01).day(), 1);
379
    /// assert_eq!(date!(2019-12-31).day(), 31);
380
    /// ```
381
3.81k
    pub const fn day(self) -> u8 {
382
3.81k
        let ordinal = self.ordinal() as u32;
383
3.81k
        let jan_feb_len = 59 + self.is_in_leap_year() as u32;
384
385
3.81k
        let ordinal_adj = if ordinal <= jan_feb_len {
386
1.44k
            0
387
        } else {
388
2.37k
            jan_feb_len
389
        };
390
391
3.81k
        let ordinal = ordinal - ordinal_adj;
392
3.81k
        let month = (ordinal * 268 + 8031) >> 13;
393
3.81k
        let days_in_preceding_months = (month * 3917 - 3866) >> 7;
394
3.81k
        (ordinal - days_in_preceding_months) as u8
395
3.81k
    }
396
397
    /// Get the day of the year.
398
    ///
399
    /// The returned value will always be in the range `1..=366` (`1..=365` for common years).
400
    ///
401
    /// ```rust
402
    /// # use time_macros::date;
403
    /// assert_eq!(date!(2019-01-01).ordinal(), 1);
404
    /// assert_eq!(date!(2019-12-31).ordinal(), 365);
405
    /// ```
406
20.4k
    pub const fn ordinal(self) -> u16 {
407
20.4k
        (self.value.get() & 0x1FF) as u16
408
20.4k
    }
409
410
    /// Get the ISO 8601 year and week number.
411
0
    pub(crate) const fn iso_year_week(self) -> (i32, u8) {
412
0
        let (year, ordinal) = self.to_ordinal_date();
413
0
414
0
        match ((ordinal + 10 - self.weekday().number_from_monday() as u16) / 7) as u8 {
415
0
            0 => (year - 1, weeks_in_year(year - 1)),
416
0
            53 if weeks_in_year(year) == 52 => (year + 1, 1),
417
0
            week => (year, week),
418
        }
419
0
    }
420
421
    /// Get the ISO week number.
422
    ///
423
    /// The returned value will always be in the range `1..=53`.
424
    ///
425
    /// ```rust
426
    /// # use time_macros::date;
427
    /// assert_eq!(date!(2019-01-01).iso_week(), 1);
428
    /// assert_eq!(date!(2019-10-04).iso_week(), 40);
429
    /// assert_eq!(date!(2020-01-01).iso_week(), 1);
430
    /// assert_eq!(date!(2020-12-31).iso_week(), 53);
431
    /// assert_eq!(date!(2021-01-01).iso_week(), 53);
432
    /// ```
433
0
    pub const fn iso_week(self) -> u8 {
434
0
        self.iso_year_week().1
435
0
    }
436
437
    /// Get the week number where week 1 begins on the first Sunday.
438
    ///
439
    /// The returned value will always be in the range `0..=53`.
440
    ///
441
    /// ```rust
442
    /// # use time_macros::date;
443
    /// assert_eq!(date!(2019-01-01).sunday_based_week(), 0);
444
    /// assert_eq!(date!(2020-01-01).sunday_based_week(), 0);
445
    /// assert_eq!(date!(2020-12-31).sunday_based_week(), 52);
446
    /// assert_eq!(date!(2021-01-01).sunday_based_week(), 0);
447
    /// ```
448
0
    pub const fn sunday_based_week(self) -> u8 {
449
0
        ((self.ordinal() as i16 - self.weekday().number_days_from_sunday() as i16 + 6) / 7) as u8
450
0
    }
451
452
    /// Get the week number where week 1 begins on the first Monday.
453
    ///
454
    /// The returned value will always be in the range `0..=53`.
455
    ///
456
    /// ```rust
457
    /// # use time_macros::date;
458
    /// assert_eq!(date!(2019-01-01).monday_based_week(), 0);
459
    /// assert_eq!(date!(2020-01-01).monday_based_week(), 0);
460
    /// assert_eq!(date!(2020-12-31).monday_based_week(), 52);
461
    /// assert_eq!(date!(2021-01-01).monday_based_week(), 0);
462
    /// ```
463
0
    pub const fn monday_based_week(self) -> u8 {
464
0
        ((self.ordinal() as i16 - self.weekday().number_days_from_monday() as i16 + 6) / 7) as u8
465
0
    }
466
467
    /// Get the year, month, and day.
468
    ///
469
    /// ```rust
470
    /// # use time::Month;
471
    /// # use time_macros::date;
472
    /// assert_eq!(
473
    ///     date!(2019-01-01).to_calendar_date(),
474
    ///     (2019, Month::January, 1)
475
    /// );
476
    /// ```
477
2.05k
    pub const fn to_calendar_date(self) -> (i32, Month, u8) {
478
2.05k
        let (year, ordinal) = self.to_ordinal_date();
479
2.05k
        let ordinal = ordinal as u32;
480
2.05k
        let jan_feb_len = 59 + self.is_in_leap_year() as u32;
481
482
2.05k
        let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len {
483
674
            (0, 0)
484
        } else {
485
1.38k
            (2, jan_feb_len)
486
        };
487
488
2.05k
        let ordinal = ordinal - ordinal_adj;
489
2.05k
        let month = (ordinal * 268 + 8031) >> 13;
490
2.05k
        let days_in_preceding_months = (month * 3917 - 3866) >> 7;
491
2.05k
        let day = ordinal - days_in_preceding_months;
492
2.05k
        let month = month + month_adj;
493
2.05k
494
2.05k
        (
495
2.05k
            year,
496
2.05k
            // Safety: `month` is guaranteed to be between 1 and 12 inclusive.
497
2.05k
            unsafe {
498
2.05k
                match Month::from_number(NonZeroU8::new_unchecked(month as u8)) {
499
2.05k
                    Ok(month) => month,
500
0
                    Err(_) => core::hint::unreachable_unchecked(),
501
                }
502
            },
503
2.05k
            day as u8,
504
2.05k
        )
505
2.05k
    }
506
507
    /// Get the year and ordinal day number.
508
    ///
509
    /// ```rust
510
    /// # use time_macros::date;
511
    /// assert_eq!(date!(2019-01-01).to_ordinal_date(), (2019, 1));
512
    /// ```
513
11.0k
    pub const fn to_ordinal_date(self) -> (i32, u16) {
514
11.0k
        (self.year(), self.ordinal())
515
11.0k
    }
516
517
    /// Get the ISO 8601 year, week number, and weekday.
518
    ///
519
    /// ```rust
520
    /// # use time::Weekday::*;
521
    /// # use time_macros::date;
522
    /// assert_eq!(date!(2019-01-01).to_iso_week_date(), (2019, 1, Tuesday));
523
    /// assert_eq!(date!(2019-10-04).to_iso_week_date(), (2019, 40, Friday));
524
    /// assert_eq!(date!(2020-01-01).to_iso_week_date(), (2020, 1, Wednesday));
525
    /// assert_eq!(date!(2020-12-31).to_iso_week_date(), (2020, 53, Thursday));
526
    /// assert_eq!(date!(2021-01-01).to_iso_week_date(), (2020, 53, Friday));
527
    /// ```
528
0
    pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
529
0
        let (year, ordinal) = self.to_ordinal_date();
530
0
        let weekday = self.weekday();
531
0
532
0
        match ((ordinal + 10 - weekday.number_from_monday() as u16) / 7) as u8 {
533
0
            0 => (year - 1, weeks_in_year(year - 1), weekday),
534
0
            53 if weeks_in_year(year) == 52 => (year + 1, 1, weekday),
535
0
            week => (year, week, weekday),
536
        }
537
0
    }
538
539
    /// Get the weekday.
540
    ///
541
    /// ```rust
542
    /// # use time::Weekday::*;
543
    /// # use time_macros::date;
544
    /// assert_eq!(date!(2019-01-01).weekday(), Tuesday);
545
    /// assert_eq!(date!(2019-02-01).weekday(), Friday);
546
    /// assert_eq!(date!(2019-03-01).weekday(), Friday);
547
    /// assert_eq!(date!(2019-04-01).weekday(), Monday);
548
    /// assert_eq!(date!(2019-05-01).weekday(), Wednesday);
549
    /// assert_eq!(date!(2019-06-01).weekday(), Saturday);
550
    /// assert_eq!(date!(2019-07-01).weekday(), Monday);
551
    /// assert_eq!(date!(2019-08-01).weekday(), Thursday);
552
    /// assert_eq!(date!(2019-09-01).weekday(), Sunday);
553
    /// assert_eq!(date!(2019-10-01).weekday(), Tuesday);
554
    /// assert_eq!(date!(2019-11-01).weekday(), Friday);
555
    /// assert_eq!(date!(2019-12-01).weekday(), Sunday);
556
    /// ```
557
0
    pub const fn weekday(self) -> Weekday {
558
0
        match self.to_julian_day() % 7 {
559
0
            -6 | 1 => Weekday::Tuesday,
560
0
            -5 | 2 => Weekday::Wednesday,
561
0
            -4 | 3 => Weekday::Thursday,
562
0
            -3 | 4 => Weekday::Friday,
563
0
            -2 | 5 => Weekday::Saturday,
564
0
            -1 | 6 => Weekday::Sunday,
565
0
            val => {
566
0
                debug_assert!(val == 0);
567
0
                Weekday::Monday
568
            }
569
        }
570
0
    }
571
572
    /// Get the next calendar date.
573
    ///
574
    /// ```rust
575
    /// # use time::Date;
576
    /// # use time_macros::date;
577
    /// assert_eq!(date!(2019-01-01).next_day(), Some(date!(2019-01-02)));
578
    /// assert_eq!(date!(2019-01-31).next_day(), Some(date!(2019-02-01)));
579
    /// assert_eq!(date!(2019-12-31).next_day(), Some(date!(2020-01-01)));
580
    /// assert_eq!(Date::MAX.next_day(), None);
581
    /// ```
582
0
    pub const fn next_day(self) -> Option<Self> {
583
0
        if self.ordinal() == 366 || (self.ordinal() == 365 && !self.is_in_leap_year()) {
584
0
            if self.value.get() == Self::MAX.value.get() {
585
0
                None
586
            } else {
587
                // Safety: `ordinal` is not zero.
588
0
                unsafe { Some(Self::__from_ordinal_date_unchecked(self.year() + 1, 1)) }
589
            }
590
        } else {
591
0
            Some(Self {
592
0
                // Safety: `ordinal` is not zero.
593
0
                value: unsafe { NonZeroI32::new_unchecked(self.value.get() + 1) },
594
0
            })
595
        }
596
0
    }
597
598
    /// Get the previous calendar date.
599
    ///
600
    /// ```rust
601
    /// # use time::Date;
602
    /// # use time_macros::date;
603
    /// assert_eq!(date!(2019-01-02).previous_day(), Some(date!(2019-01-01)));
604
    /// assert_eq!(date!(2019-02-01).previous_day(), Some(date!(2019-01-31)));
605
    /// assert_eq!(date!(2020-01-01).previous_day(), Some(date!(2019-12-31)));
606
    /// assert_eq!(Date::MIN.previous_day(), None);
607
    /// ```
608
556
    pub const fn previous_day(self) -> Option<Self> {
609
556
        if self.ordinal() != 1 {
610
424
            Some(Self {
611
424
                // Safety: `ordinal` is not zero.
612
424
                value: unsafe { NonZeroI32::new_unchecked(self.value.get() - 1) },
613
424
            })
614
132
        } else if self.value.get() == Self::MIN.value.get() {
615
1
            None
616
        } else {
617
            // Safety: `ordinal` is not zero.
618
131
            Some(unsafe {
619
131
                Self::__from_ordinal_date_unchecked(self.year() - 1, days_in_year(self.year() - 1))
620
131
            })
621
        }
622
556
    }
623
624
    /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
625
    ///
626
    /// # Panics
627
    /// Panics if an overflow occurred.
628
    ///
629
    /// # Examples
630
    /// ```
631
    /// # use time::Weekday;
632
    /// # use time_macros::date;
633
    /// assert_eq!(
634
    ///     date!(2023-06-28).next_occurrence(Weekday::Monday),
635
    ///     date!(2023-07-03)
636
    /// );
637
    /// assert_eq!(
638
    ///     date!(2023-06-19).next_occurrence(Weekday::Monday),
639
    ///     date!(2023-06-26)
640
    /// );
641
    /// ```
642
0
    pub const fn next_occurrence(self, weekday: Weekday) -> Self {
643
0
        expect_opt!(
644
0
            self.checked_next_occurrence(weekday),
645
0
            "overflow calculating the next occurrence of a weekday"
646
        )
647
0
    }
648
649
    /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
650
    ///
651
    /// # Panics
652
    /// Panics if an overflow occurred.
653
    ///
654
    /// # Examples
655
    /// ```
656
    /// # use time::Weekday;
657
    /// # use time_macros::date;
658
    /// assert_eq!(
659
    ///     date!(2023-06-28).prev_occurrence(Weekday::Monday),
660
    ///     date!(2023-06-26)
661
    /// );
662
    /// assert_eq!(
663
    ///     date!(2023-06-19).prev_occurrence(Weekday::Monday),
664
    ///     date!(2023-06-12)
665
    /// );
666
    /// ```
667
0
    pub const fn prev_occurrence(self, weekday: Weekday) -> Self {
668
0
        expect_opt!(
669
0
            self.checked_prev_occurrence(weekday),
670
0
            "overflow calculating the previous occurrence of a weekday"
671
        )
672
0
    }
673
674
    /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
675
    ///
676
    /// # Panics
677
    /// Panics if an overflow occurred or if `n == 0`.
678
    ///
679
    /// # Examples
680
    /// ```
681
    /// # use time::Weekday;
682
    /// # use time_macros::date;
683
    /// assert_eq!(
684
    ///     date!(2023-06-25).nth_next_occurrence(Weekday::Monday, 5),
685
    ///     date!(2023-07-24)
686
    /// );
687
    /// assert_eq!(
688
    ///     date!(2023-06-26).nth_next_occurrence(Weekday::Monday, 5),
689
    ///     date!(2023-07-31)
690
    /// );
691
    /// ```
692
0
    pub const fn nth_next_occurrence(self, weekday: Weekday, n: u8) -> Self {
693
0
        expect_opt!(
694
0
            self.checked_nth_next_occurrence(weekday, n),
695
0
            "overflow calculating the next occurrence of a weekday"
696
        )
697
0
    }
698
699
    /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
700
    ///
701
    /// # Panics
702
    /// Panics if an overflow occurred or if `n == 0`.
703
    ///
704
    /// # Examples
705
    /// ```
706
    /// # use time::Weekday;
707
    /// # use time_macros::date;
708
    /// assert_eq!(
709
    ///     date!(2023-06-27).nth_prev_occurrence(Weekday::Monday, 3),
710
    ///     date!(2023-06-12)
711
    /// );
712
    /// assert_eq!(
713
    ///     date!(2023-06-26).nth_prev_occurrence(Weekday::Monday, 3),
714
    ///     date!(2023-06-05)
715
    /// );
716
    /// ```
717
0
    pub const fn nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Self {
718
0
        expect_opt!(
719
0
            self.checked_nth_prev_occurrence(weekday, n),
720
0
            "overflow calculating the previous occurrence of a weekday"
721
        )
722
0
    }
723
724
    /// Get the Julian day for the date.
725
    ///
726
    /// ```rust
727
    /// # use time_macros::date;
728
    /// assert_eq!(date!(-4713 - 11 - 24).to_julian_day(), 0);
729
    /// assert_eq!(date!(2000-01-01).to_julian_day(), 2_451_545);
730
    /// assert_eq!(date!(2019-01-01).to_julian_day(), 2_458_485);
731
    /// assert_eq!(date!(2019-12-31).to_julian_day(), 2_458_849);
732
    /// ```
733
6.38k
    pub const fn to_julian_day(self) -> i32 {
734
6.38k
        let (year, ordinal) = self.to_ordinal_date();
735
6.38k
736
6.38k
        // The algorithm requires a non-negative year. Add the lowest value to make it so. This is
737
6.38k
        // adjusted for at the end with the final subtraction.
738
6.38k
        let adj_year = year + 999_999;
739
6.38k
        let century = adj_year / 100;
740
6.38k
741
6.38k
        let days_before_year = (1461 * adj_year as i64 / 4) as i32 - century + century / 4;
742
6.38k
        days_before_year + ordinal as i32 - 363_521_075
743
6.38k
    }
744
745
    /// Computes `self + duration`, returning `None` if an overflow occurred.
746
    ///
747
    /// ```rust
748
    /// # use time::{Date, ext::NumericalDuration};
749
    /// # use time_macros::date;
750
    /// assert_eq!(Date::MAX.checked_add(1.days()), None);
751
    /// assert_eq!(Date::MIN.checked_add((-2).days()), None);
752
    /// assert_eq!(
753
    ///     date!(2020-12-31).checked_add(2.days()),
754
    ///     Some(date!(2021-01-02))
755
    /// );
756
    /// ```
757
    ///
758
    /// # Note
759
    ///
760
    /// This function only takes whole days into account.
761
    ///
762
    /// ```rust
763
    /// # use time::{Date, ext::NumericalDuration};
764
    /// # use time_macros::date;
765
    /// assert_eq!(Date::MAX.checked_add(23.hours()), Some(Date::MAX));
766
    /// assert_eq!(Date::MIN.checked_add((-23).hours()), Some(Date::MIN));
767
    /// assert_eq!(
768
    ///     date!(2020-12-31).checked_add(23.hours()),
769
    ///     Some(date!(2020-12-31))
770
    /// );
771
    /// assert_eq!(
772
    ///     date!(2020-12-31).checked_add(47.hours()),
773
    ///     Some(date!(2021-01-01))
774
    /// );
775
    /// ```
776
2.05k
    pub const fn checked_add(self, duration: Duration) -> Option<Self> {
777
2.05k
        let whole_days = duration.whole_days();
778
2.05k
        if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
779
468
            return None;
780
1.59k
        }
781
782
1.59k
        let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days as i32));
783
1.52k
        if let Ok(date) = Self::from_julian_day(julian_day) {
784
1.03k
            Some(date)
785
        } else {
786
492
            None
787
        }
788
2.05k
    }
789
790
    /// Computes `self + duration`, returning `None` if an overflow occurred.
791
    ///
792
    /// ```rust
793
    /// # use time::{Date, ext::NumericalStdDuration};
794
    /// # use time_macros::date;
795
    /// assert_eq!(Date::MAX.checked_add_std(1.std_days()), None);
796
    /// assert_eq!(
797
    ///     date!(2020-12-31).checked_add_std(2.std_days()),
798
    ///     Some(date!(2021-01-02))
799
    /// );
800
    /// ```
801
    ///
802
    /// # Note
803
    ///
804
    /// This function only takes whole days into account.
805
    ///
806
    /// ```rust
807
    /// # use time::{Date, ext::NumericalStdDuration};
808
    /// # use time_macros::date;
809
    /// assert_eq!(Date::MAX.checked_add_std(23.std_hours()), Some(Date::MAX));
810
    /// assert_eq!(
811
    ///     date!(2020-12-31).checked_add_std(23.std_hours()),
812
    ///     Some(date!(2020-12-31))
813
    /// );
814
    /// assert_eq!(
815
    ///     date!(2020-12-31).checked_add_std(47.std_hours()),
816
    ///     Some(date!(2021-01-01))
817
    /// );
818
    /// ```
819
0
    pub const fn checked_add_std(self, duration: StdDuration) -> Option<Self> {
820
0
        let whole_days = duration.as_secs() / Second::per(Day) as u64;
821
0
        if whole_days > i32::MAX as u64 {
822
0
            return None;
823
0
        }
824
825
0
        let julian_day = const_try_opt!(self.to_julian_day().checked_add(whole_days as i32));
826
0
        if let Ok(date) = Self::from_julian_day(julian_day) {
827
0
            Some(date)
828
        } else {
829
0
            None
830
        }
831
0
    }
832
833
    /// Computes `self - duration`, returning `None` if an overflow occurred.
834
    ///
835
    /// ```
836
    /// # use time::{Date, ext::NumericalDuration};
837
    /// # use time_macros::date;
838
    /// assert_eq!(Date::MAX.checked_sub((-2).days()), None);
839
    /// assert_eq!(Date::MIN.checked_sub(1.days()), None);
840
    /// assert_eq!(
841
    ///     date!(2020-12-31).checked_sub(2.days()),
842
    ///     Some(date!(2020-12-29))
843
    /// );
844
    /// ```
845
    ///
846
    /// # Note
847
    ///
848
    /// This function only takes whole days into account.
849
    ///
850
    /// ```
851
    /// # use time::{Date, ext::NumericalDuration};
852
    /// # use time_macros::date;
853
    /// assert_eq!(Date::MAX.checked_sub((-23).hours()), Some(Date::MAX));
854
    /// assert_eq!(Date::MIN.checked_sub(23.hours()), Some(Date::MIN));
855
    /// assert_eq!(
856
    ///     date!(2020-12-31).checked_sub(23.hours()),
857
    ///     Some(date!(2020-12-31))
858
    /// );
859
    /// assert_eq!(
860
    ///     date!(2020-12-31).checked_sub(47.hours()),
861
    ///     Some(date!(2020-12-30))
862
    /// );
863
    /// ```
864
0
    pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
865
0
        let whole_days = duration.whole_days();
866
0
        if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
867
0
            return None;
868
0
        }
869
870
0
        let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days as i32));
871
0
        if let Ok(date) = Self::from_julian_day(julian_day) {
872
0
            Some(date)
873
        } else {
874
0
            None
875
        }
876
0
    }
877
878
    /// Computes `self - duration`, returning `None` if an overflow occurred.
879
    ///
880
    /// ```
881
    /// # use time::{Date, ext::NumericalStdDuration};
882
    /// # use time_macros::date;
883
    /// assert_eq!(Date::MIN.checked_sub_std(1.std_days()), None);
884
    /// assert_eq!(
885
    ///     date!(2020-12-31).checked_sub_std(2.std_days()),
886
    ///     Some(date!(2020-12-29))
887
    /// );
888
    /// ```
889
    ///
890
    /// # Note
891
    ///
892
    /// This function only takes whole days into account.
893
    ///
894
    /// ```
895
    /// # use time::{Date, ext::NumericalStdDuration};
896
    /// # use time_macros::date;
897
    /// assert_eq!(Date::MIN.checked_sub_std(23.std_hours()), Some(Date::MIN));
898
    /// assert_eq!(
899
    ///     date!(2020-12-31).checked_sub_std(23.std_hours()),
900
    ///     Some(date!(2020-12-31))
901
    /// );
902
    /// assert_eq!(
903
    ///     date!(2020-12-31).checked_sub_std(47.std_hours()),
904
    ///     Some(date!(2020-12-30))
905
    /// );
906
    /// ```
907
0
    pub const fn checked_sub_std(self, duration: StdDuration) -> Option<Self> {
908
0
        let whole_days = duration.as_secs() / Second::per(Day) as u64;
909
0
        if whole_days > i32::MAX as u64 {
910
0
            return None;
911
0
        }
912
913
0
        let julian_day = const_try_opt!(self.to_julian_day().checked_sub(whole_days as i32));
914
0
        if let Ok(date) = Self::from_julian_day(julian_day) {
915
0
            Some(date)
916
        } else {
917
0
            None
918
        }
919
0
    }
920
921
    /// Calculates the first occurrence of a weekday that is strictly later than a given `Date`.
922
    /// Returns `None` if an overflow occurred.
923
0
    pub(crate) const fn checked_next_occurrence(self, weekday: Weekday) -> Option<Self> {
924
0
        let day_diff = match weekday as i8 - self.weekday() as i8 {
925
0
            1 | -6 => 1,
926
0
            2 | -5 => 2,
927
0
            3 | -4 => 3,
928
0
            4 | -3 => 4,
929
0
            5 | -2 => 5,
930
0
            6 | -1 => 6,
931
0
            val => {
932
0
                debug_assert!(val == 0);
933
0
                7
934
            }
935
        };
936
937
0
        self.checked_add(Duration::days(day_diff))
938
0
    }
939
940
    /// Calculates the first occurrence of a weekday that is strictly earlier than a given `Date`.
941
    /// Returns `None` if an overflow occurred.
942
0
    pub(crate) const fn checked_prev_occurrence(self, weekday: Weekday) -> Option<Self> {
943
0
        let day_diff = match weekday as i8 - self.weekday() as i8 {
944
0
            1 | -6 => 6,
945
0
            2 | -5 => 5,
946
0
            3 | -4 => 4,
947
0
            4 | -3 => 3,
948
0
            5 | -2 => 2,
949
0
            6 | -1 => 1,
950
0
            val => {
951
0
                debug_assert!(val == 0);
952
0
                7
953
            }
954
        };
955
956
0
        self.checked_sub(Duration::days(day_diff))
957
0
    }
958
959
    /// Calculates the `n`th occurrence of a weekday that is strictly later than a given `Date`.
960
    /// Returns `None` if an overflow occurred or if `n == 0`.
961
0
    pub(crate) const fn checked_nth_next_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
962
0
        if n == 0 {
963
0
            return None;
964
0
        }
965
966
0
        const_try_opt!(self.checked_next_occurrence(weekday))
967
0
            .checked_add(Duration::weeks(n as i64 - 1))
968
0
    }
969
970
    /// Calculates the `n`th occurrence of a weekday that is strictly earlier than a given `Date`.
971
    /// Returns `None` if an overflow occurred or if `n == 0`.
972
0
    pub(crate) const fn checked_nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
973
0
        if n == 0 {
974
0
            return None;
975
0
        }
976
977
0
        const_try_opt!(self.checked_prev_occurrence(weekday))
978
0
            .checked_sub(Duration::weeks(n as i64 - 1))
979
0
    }
980
981
    /// Computes `self + duration`, saturating value on overflow.
982
    ///
983
    /// ```rust
984
    /// # use time::{Date, ext::NumericalDuration};
985
    /// # use time_macros::date;
986
    /// assert_eq!(Date::MAX.saturating_add(1.days()), Date::MAX);
987
    /// assert_eq!(Date::MIN.saturating_add((-2).days()), Date::MIN);
988
    /// assert_eq!(
989
    ///     date!(2020-12-31).saturating_add(2.days()),
990
    ///     date!(2021-01-02)
991
    /// );
992
    /// ```
993
    ///
994
    /// # Note
995
    ///
996
    /// This function only takes whole days into account.
997
    ///
998
    /// ```rust
999
    /// # use time::ext::NumericalDuration;
1000
    /// # use time_macros::date;
1001
    /// assert_eq!(
1002
    ///     date!(2020-12-31).saturating_add(23.hours()),
1003
    ///     date!(2020-12-31)
1004
    /// );
1005
    /// assert_eq!(
1006
    ///     date!(2020-12-31).saturating_add(47.hours()),
1007
    ///     date!(2021-01-01)
1008
    /// );
1009
    /// ```
1010
0
    pub const fn saturating_add(self, duration: Duration) -> Self {
1011
0
        if let Some(datetime) = self.checked_add(duration) {
1012
0
            datetime
1013
0
        } else if duration.is_negative() {
1014
0
            Self::MIN
1015
        } else {
1016
0
            debug_assert!(duration.is_positive());
1017
0
            Self::MAX
1018
        }
1019
0
    }
1020
1021
    /// Computes `self - duration`, saturating value on overflow.
1022
    ///
1023
    /// ```
1024
    /// # use time::{Date, ext::NumericalDuration};
1025
    /// # use time_macros::date;
1026
    /// assert_eq!(Date::MAX.saturating_sub((-2).days()), Date::MAX);
1027
    /// assert_eq!(Date::MIN.saturating_sub(1.days()), Date::MIN);
1028
    /// assert_eq!(
1029
    ///     date!(2020-12-31).saturating_sub(2.days()),
1030
    ///     date!(2020-12-29)
1031
    /// );
1032
    /// ```
1033
    ///
1034
    /// # Note
1035
    ///
1036
    /// This function only takes whole days into account.
1037
    ///
1038
    /// ```
1039
    /// # use time::ext::NumericalDuration;
1040
    /// # use time_macros::date;
1041
    /// assert_eq!(
1042
    ///     date!(2020-12-31).saturating_sub(23.hours()),
1043
    ///     date!(2020-12-31)
1044
    /// );
1045
    /// assert_eq!(
1046
    ///     date!(2020-12-31).saturating_sub(47.hours()),
1047
    ///     date!(2020-12-30)
1048
    /// );
1049
    /// ```
1050
0
    pub const fn saturating_sub(self, duration: Duration) -> Self {
1051
0
        if let Some(datetime) = self.checked_sub(duration) {
1052
0
            datetime
1053
0
        } else if duration.is_negative() {
1054
0
            Self::MAX
1055
        } else {
1056
0
            debug_assert!(duration.is_positive());
1057
0
            Self::MIN
1058
        }
1059
0
    }
1060
1061
    /// Replace the year. The month and day will be unchanged.
1062
    ///
1063
    /// ```rust
1064
    /// # use time_macros::date;
1065
    /// assert_eq!(
1066
    ///     date!(2022-02-18).replace_year(2019),
1067
    ///     Ok(date!(2019-02-18))
1068
    /// );
1069
    /// assert!(date!(2022-02-18).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
1070
    /// assert!(date!(2022-02-18).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
1071
    /// ```
1072
    #[must_use = "This method does not mutate the original `Date`."]
1073
0
    pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1074
0
        ensure_ranged!(Year: year);
1075
1076
0
        let ordinal = self.ordinal();
1077
0
1078
0
        // Dates in January and February are unaffected by leap years.
1079
0
        if ordinal <= 59 {
1080
            // Safety: `ordinal` is not zero.
1081
0
            return Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) });
1082
0
        }
1083
0
1084
0
        match (self.is_in_leap_year(), is_leap_year(year)) {
1085
            (false, false) | (true, true) => {
1086
                // Safety: `ordinal` is not zero.
1087
0
                Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
1088
            }
1089
            // February 29 does not exist in common years.
1090
0
            (true, false) if ordinal == 60 => Err(error::ComponentRange {
1091
0
                name: "day",
1092
0
                value: 29,
1093
0
                minimum: 1,
1094
0
                maximum: 28,
1095
0
                conditional_message: Some("for the given month and year"),
1096
0
            }),
1097
            // We're going from a common year to a leap year. Shift dates in March and later by
1098
            // one day.
1099
            // Safety: `ordinal` is not zero.
1100
0
            (false, true) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal + 1) }),
1101
            // We're going from a leap year to a common year. Shift dates in January and
1102
            // February by one day.
1103
            // Safety: `ordinal` is not zero.
1104
0
            (true, false) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal - 1) }),
1105
        }
1106
0
    }
1107
1108
    /// Replace the month of the year.
1109
    ///
1110
    /// ```rust
1111
    /// # use time_macros::date;
1112
    /// # use time::Month;
1113
    /// assert_eq!(
1114
    ///     date!(2022-02-18).replace_month(Month::January),
1115
    ///     Ok(date!(2022-01-18))
1116
    /// );
1117
    /// assert!(date!(2022-01-30)
1118
    ///     .replace_month(Month::February)
1119
    ///     .is_err()); // 30 isn't a valid day in February
1120
    /// ```
1121
    #[must_use = "This method does not mutate the original `Date`."]
1122
0
    pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1123
0
        let (year, _, day) = self.to_calendar_date();
1124
0
        Self::from_calendar_date(year, month, day)
1125
0
    }
1126
1127
    /// Replace the day of the month.
1128
    ///
1129
    /// ```rust
1130
    /// # use time_macros::date;
1131
    /// assert_eq!(date!(2022-02-18).replace_day(1), Ok(date!(2022-02-01)));
1132
    /// assert!(date!(2022-02-18).replace_day(0).is_err()); // 0 isn't a valid day
1133
    /// assert!(date!(2022-02-18).replace_day(30).is_err()); // 30 isn't a valid day in February
1134
    /// ```
1135
    #[must_use = "This method does not mutate the original `Date`."]
1136
0
    pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1137
0
        match day {
1138
0
            1..=28 => {}
1139
0
            29..=31 if day <= self.month().length(self.year()) => {}
1140
            _ => {
1141
0
                return Err(error::ComponentRange {
1142
0
                    name: "day",
1143
0
                    minimum: 1,
1144
0
                    maximum: self.month().length(self.year()) as i64,
1145
0
                    value: day as i64,
1146
0
                    conditional_message: Some("for the given month and year"),
1147
0
                });
1148
            }
1149
        }
1150
1151
        // Safety: `ordinal` is not zero.
1152
0
        Ok(unsafe {
1153
0
            Self::__from_ordinal_date_unchecked(
1154
0
                self.year(),
1155
0
                (self.ordinal() as i16 - self.day() as i16 + day as i16) as u16,
1156
0
            )
1157
0
        })
1158
0
    }
1159
1160
    /// Replace the day of the year.
1161
    ///
1162
    /// ```rust
1163
    /// # use time_macros::date;
1164
    /// assert_eq!(date!(2022-049).replace_ordinal(1), Ok(date!(2022-001)));
1165
    /// assert!(date!(2022-049).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
1166
    /// assert!(date!(2022-049).replace_ordinal(366).is_err()); // 2022 isn't a leap year
1167
    /// ````
1168
    #[must_use = "This method does not mutate the original `Date`."]
1169
0
    pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1170
0
        match ordinal {
1171
0
            1..=365 => {}
1172
0
            366 if self.is_in_leap_year() => {}
1173
            _ => {
1174
0
                return Err(error::ComponentRange {
1175
0
                    name: "ordinal",
1176
0
                    minimum: 1,
1177
0
                    maximum: days_in_year(self.year()) as i64,
1178
0
                    value: ordinal as i64,
1179
0
                    conditional_message: Some("for the given year"),
1180
0
                });
1181
            }
1182
        }
1183
1184
        // Safety: `ordinal` is in range.
1185
0
        Ok(unsafe { Self::__from_ordinal_date_unchecked(self.year(), ordinal) })
1186
0
    }
1187
}
1188
1189
/// Methods to add a [`Time`] component, resulting in a [`PrimitiveDateTime`].
1190
impl Date {
1191
    /// Create a [`PrimitiveDateTime`] using the existing date. The [`Time`] component will be set
1192
    /// to midnight.
1193
    ///
1194
    /// ```rust
1195
    /// # use time_macros::{date, datetime};
1196
    /// assert_eq!(date!(1970-01-01).midnight(), datetime!(1970-01-01 0:00));
1197
    /// ```
1198
0
    pub const fn midnight(self) -> PrimitiveDateTime {
1199
0
        PrimitiveDateTime::new(self, Time::MIDNIGHT)
1200
0
    }
1201
1202
    /// Create a [`PrimitiveDateTime`] using the existing date and the provided [`Time`].
1203
    ///
1204
    /// ```rust
1205
    /// # use time_macros::{date, datetime, time};
1206
    /// assert_eq!(
1207
    ///     date!(1970-01-01).with_time(time!(0:00)),
1208
    ///     datetime!(1970-01-01 0:00),
1209
    /// );
1210
    /// ```
1211
5.86k
    pub const fn with_time(self, time: Time) -> PrimitiveDateTime {
1212
5.86k
        PrimitiveDateTime::new(self, time)
1213
5.86k
    }
1214
1215
    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1216
    ///
1217
    /// ```rust
1218
    /// # use time_macros::date;
1219
    /// assert!(date!(1970-01-01).with_hms(0, 0, 0).is_ok());
1220
    /// assert!(date!(1970-01-01).with_hms(24, 0, 0).is_err());
1221
    /// ```
1222
0
    pub const fn with_hms(
1223
0
        self,
1224
0
        hour: u8,
1225
0
        minute: u8,
1226
0
        second: u8,
1227
0
    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1228
0
        Ok(PrimitiveDateTime::new(
1229
0
            self,
1230
0
            const_try!(Time::from_hms(hour, minute, second)),
1231
        ))
1232
0
    }
1233
1234
    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1235
    ///
1236
    /// ```rust
1237
    /// # use time_macros::date;
1238
    /// assert!(date!(1970-01-01).with_hms_milli(0, 0, 0, 0).is_ok());
1239
    /// assert!(date!(1970-01-01).with_hms_milli(24, 0, 0, 0).is_err());
1240
    /// ```
1241
0
    pub const fn with_hms_milli(
1242
0
        self,
1243
0
        hour: u8,
1244
0
        minute: u8,
1245
0
        second: u8,
1246
0
        millisecond: u16,
1247
0
    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1248
0
        Ok(PrimitiveDateTime::new(
1249
0
            self,
1250
0
            const_try!(Time::from_hms_milli(hour, minute, second, millisecond)),
1251
        ))
1252
0
    }
1253
1254
    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1255
    ///
1256
    /// ```rust
1257
    /// # use time_macros::date;
1258
    /// assert!(date!(1970-01-01).with_hms_micro(0, 0, 0, 0).is_ok());
1259
    /// assert!(date!(1970-01-01).with_hms_micro(24, 0, 0, 0).is_err());
1260
    /// ```
1261
0
    pub const fn with_hms_micro(
1262
0
        self,
1263
0
        hour: u8,
1264
0
        minute: u8,
1265
0
        second: u8,
1266
0
        microsecond: u32,
1267
0
    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1268
0
        Ok(PrimitiveDateTime::new(
1269
0
            self,
1270
0
            const_try!(Time::from_hms_micro(hour, minute, second, microsecond)),
1271
        ))
1272
0
    }
1273
1274
    /// Attempt to create a [`PrimitiveDateTime`] using the existing date and the provided time.
1275
    ///
1276
    /// ```rust
1277
    /// # use time_macros::date;
1278
    /// assert!(date!(1970-01-01).with_hms_nano(0, 0, 0, 0).is_ok());
1279
    /// assert!(date!(1970-01-01).with_hms_nano(24, 0, 0, 0).is_err());
1280
    /// ```
1281
0
    pub const fn with_hms_nano(
1282
0
        self,
1283
0
        hour: u8,
1284
0
        minute: u8,
1285
0
        second: u8,
1286
0
        nanosecond: u32,
1287
0
    ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1288
0
        Ok(PrimitiveDateTime::new(
1289
0
            self,
1290
0
            const_try!(Time::from_hms_nano(hour, minute, second, nanosecond)),
1291
        ))
1292
0
    }
1293
}
1294
1295
#[cfg(feature = "formatting")]
1296
impl Date {
1297
    /// Format the `Date` using the provided [format description](crate::format_description).
1298
0
    pub fn format_into(
1299
0
        self,
1300
0
        output: &mut (impl io::Write + ?Sized),
1301
0
        format: &(impl Formattable + ?Sized),
1302
0
    ) -> Result<usize, error::Format> {
1303
0
        format.format_into(output, Some(self), None, None)
1304
0
    }
1305
1306
    /// Format the `Date` using the provided [format description](crate::format_description).
1307
    ///
1308
    /// ```rust
1309
    /// # use time::{format_description};
1310
    /// # use time_macros::date;
1311
    /// let format = format_description::parse("[year]-[month]-[day]")?;
1312
    /// assert_eq!(date!(2020-01-02).format(&format)?, "2020-01-02");
1313
    /// # Ok::<_, time::Error>(())
1314
    /// ```
1315
0
    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1316
0
        format.format(Some(self), None, None)
1317
0
    }
1318
}
1319
1320
#[cfg(feature = "parsing")]
1321
impl Date {
1322
    /// Parse a `Date` from the input using the provided [format
1323
    /// description](crate::format_description).
1324
    ///
1325
    /// ```rust
1326
    /// # use time::Date;
1327
    /// # use time_macros::{date, format_description};
1328
    /// let format = format_description!("[year]-[month]-[day]");
1329
    /// assert_eq!(Date::parse("2020-01-02", &format)?, date!(2020-01-02));
1330
    /// # Ok::<_, time::Error>(())
1331
    /// ```
1332
0
    pub fn parse(
1333
0
        input: &str,
1334
0
        description: &(impl Parsable + ?Sized),
1335
0
    ) -> Result<Self, error::Parse> {
1336
0
        description.parse_date(input.as_bytes())
1337
0
    }
1338
}
1339
1340
mod private {
1341
    #[non_exhaustive]
1342
    #[derive(Debug, Clone, Copy)]
1343
    pub struct DateMetadata {
1344
        /// The width of the year component, including the sign.
1345
        pub(super) year_width: u8,
1346
        /// Whether the sign should be displayed.
1347
        pub(super) display_sign: bool,
1348
        pub(super) year: i32,
1349
        pub(super) month: u8,
1350
        pub(super) day: u8,
1351
    }
1352
}
1353
use private::DateMetadata;
1354
1355
impl SmartDisplay for Date {
1356
    type Metadata = DateMetadata;
1357
1358
2.05k
    fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
1359
2.05k
        let (year, month, day) = self.to_calendar_date();
1360
2.05k
1361
2.05k
        // There is a minimum of four digits for any year.
1362
2.05k
        let mut year_width = cmp::max(year.unsigned_abs().num_digits(), 4);
1363
2.05k
        let display_sign = if !(0..10_000).contains(&year) {
1364
            // An extra character is required for the sign.
1365
414
            year_width += 1;
1366
414
            true
1367
        } else {
1368
1.64k
            false
1369
        };
1370
1371
2.05k
        let formatted_width = year_width.extend::<usize>()
1372
2.05k
            + smart_display::padded_width_of!(
1373
2.05k
                "-",
1374
2.05k
                u8::from(month) => width(2),
1375
2.05k
                "-",
1376
2.05k
                day => width(2),
1377
2.05k
            );
1378
2.05k
1379
2.05k
        Metadata::new(
1380
2.05k
            formatted_width,
1381
2.05k
            self,
1382
2.05k
            DateMetadata {
1383
2.05k
                year_width,
1384
2.05k
                display_sign,
1385
2.05k
                year,
1386
2.05k
                month: u8::from(month),
1387
2.05k
                day,
1388
2.05k
            },
1389
2.05k
        )
1390
2.05k
    }
1391
1392
1.02k
    fn fmt_with_metadata(
1393
1.02k
        &self,
1394
1.02k
        f: &mut fmt::Formatter<'_>,
1395
1.02k
        metadata: Metadata<Self>,
1396
1.02k
    ) -> fmt::Result {
1397
1.02k
        let DateMetadata {
1398
1.02k
            year_width,
1399
1.02k
            display_sign,
1400
1.02k
            year,
1401
1.02k
            month,
1402
1.02k
            day,
1403
1.02k
        } = *metadata;
1404
1.02k
        let year_width = year_width.extend();
1405
1.02k
1406
1.02k
        if display_sign {
1407
207
            f.pad_with_width(
1408
207
                metadata.unpadded_width(),
1409
207
                format_args!("{year:+0year_width$}-{month:02}-{day:02}"),
1410
207
            )
1411
        } else {
1412
822
            f.pad_with_width(
1413
822
                metadata.unpadded_width(),
1414
822
                format_args!("{year:0year_width$}-{month:02}-{day:02}"),
1415
822
            )
1416
        }
1417
1.02k
    }
1418
}
1419
1420
impl fmt::Display for Date {
1421
1.02k
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1422
1.02k
        SmartDisplay::fmt(self, f)
1423
1.02k
    }
1424
}
1425
1426
impl fmt::Debug for Date {
1427
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1428
0
        fmt::Display::fmt(self, f)
1429
0
    }
1430
}
1431
1432
impl Add<Duration> for Date {
1433
    type Output = Self;
1434
1435
    /// # Panics
1436
    ///
1437
    /// This may panic if an overflow occurs.
1438
0
    fn add(self, duration: Duration) -> Self::Output {
1439
0
        self.checked_add(duration)
1440
0
            .expect("overflow adding duration to date")
1441
0
    }
1442
}
1443
1444
impl Add<StdDuration> for Date {
1445
    type Output = Self;
1446
1447
    /// # Panics
1448
    ///
1449
    /// This may panic if an overflow occurs.
1450
0
    fn add(self, duration: StdDuration) -> Self::Output {
1451
0
        self.checked_add_std(duration)
1452
0
            .expect("overflow adding duration to date")
1453
0
    }
1454
}
1455
1456
impl_add_assign!(Date: Duration, StdDuration);
1457
1458
impl Sub<Duration> for Date {
1459
    type Output = Self;
1460
1461
    /// # Panics
1462
    ///
1463
    /// This may panic if an overflow occurs.
1464
0
    fn sub(self, duration: Duration) -> Self::Output {
1465
0
        self.checked_sub(duration)
1466
0
            .expect("overflow subtracting duration from date")
1467
0
    }
1468
}
1469
1470
impl Sub<StdDuration> for Date {
1471
    type Output = Self;
1472
1473
    /// # Panics
1474
    ///
1475
    /// This may panic if an overflow occurs.
1476
0
    fn sub(self, duration: StdDuration) -> Self::Output {
1477
0
        self.checked_sub_std(duration)
1478
0
            .expect("overflow subtracting duration from date")
1479
0
    }
1480
}
1481
1482
impl_sub_assign!(Date: Duration, StdDuration);
1483
1484
impl Sub for Date {
1485
    type Output = Duration;
1486
1487
0
    fn sub(self, other: Self) -> Self::Output {
1488
0
        Duration::days((self.to_julian_day() - other.to_julian_day()).extend())
1489
0
    }
1490
}