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