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