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