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