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