Coverage Report

Created: 2026-02-26 07:32

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