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