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