1#[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, expect_opt, impl_add_assign,
23 impl_sub_assign,
24};
25#[cfg(feature = "parsing")]
26use crate::parsing::Parsable;
27use crate::util::{days_in_year, is_leap_year, weeks_in_year};
28use crate::{error, Duration, Month, PrimitiveDateTime, Time, Weekday};
29
30type Year = RangedI32<MIN_YEAR, MAX_YEAR>;
31
32 {
34 -999_999
35} else {
36 -9999
37};
38 {
40 999_999
41} else {
42 9999
43};
44
45)]
51pub struct Date {
52 value: NonZero<i32>,
58}
59
60impl Date {
61 #[inline]
68 pub(crate) const fn as_i32(self) -> i32 {
69 self.value.get()
70 }
71
72 pub(crate) const UNIX_EPOCH: Self = unsafe { Self::__from_ordinal_date_unchecked(1970, 1) };
75
76 pub const MIN: Self = unsafe { Self::__from_ordinal_date_unchecked(MIN_YEAR, 1) };
81
82 pub const MAX: Self =
87 unsafe { Self::__from_ordinal_date_unchecked(MAX_YEAR, days_in_year(MAX_YEAR)) };
88
89 #[inline]
97 #[track_caller]
98 const unsafe fn from_parts(year: i32, is_leap_year: bool, ordinal: u16) -> Self {
99 if true {
if !(year >= MIN_YEAR) {
::core::panicking::panic("assertion failed: year >= MIN_YEAR")
};
};debug_assert!(year >= MIN_YEAR);
100 if true {
if !(year <= MAX_YEAR) {
::core::panicking::panic("assertion failed: year <= MAX_YEAR")
};
};debug_assert!(year <= MAX_YEAR);
101 if true {
if !(ordinal != 0) {
::core::panicking::panic("assertion failed: ordinal != 0")
};
};debug_assert!(ordinal != 0);
102 if true {
if !(ordinal <= days_in_year(year)) {
::core::panicking::panic("assertion failed: ordinal <= days_in_year(year)")
};
};debug_assert!(ordinal <= days_in_year(year));
103 if true {
if !(crate::util::is_leap_year(year) == is_leap_year) {
::core::panicking::panic("assertion failed: crate::util::is_leap_year(year) == is_leap_year")
};
};debug_assert!(crate::util::is_leap_year(year) == is_leap_year);
104
105 Self {
106 value: unsafe {
108 NonZero::new_unchecked((year << 10) | ((is_leap_year as i32) << 9) | ordinal as i32)
109 },
110 }
111 }
112
113 #[doc(hidden)]
121 #[inline]
122 #[track_caller]
123 pub const unsafe fn __from_ordinal_date_unchecked(year: i32, ordinal: u16) -> Self {
124 unsafe { Self::from_parts(year, is_leap_year(year), ordinal) }
126 }
127
128 #[inline]
141 pub const fn from_calendar_date(
142 year: i32,
143 month: Month,
144 day: u8,
145 ) -> Result<Self, error::ComponentRange> {
146 const DAYS_CUMULATIVE_COMMON_LEAP: [[u16; 12]; 2] = [
148 [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
149 [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
150 ];
151
152 match <Year>::new(year) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "year",
minimum: <Year>::MIN.get() as i64,
maximum: <Year>::MAX.get() as i64,
value: year as i64,
conditional_message: None,
});
}
};ensure_ranged!(Year: year);
153 match day {
154 1..=28 => {}
155 29..=31 if day <= month.length(year) => {}
156 _ => {
157 return Err(error::ComponentRange {
158 name: "day",
159 minimum: 1,
160 maximum: month.length(year) as i64,
161 value: day as i64,
162 conditional_message: Some("for the given month and year"),
163 });
164 }
165 }
166
167 Ok(unsafe {
169 Self::__from_ordinal_date_unchecked(
170 year,
171 DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year(year) as usize][month as usize - 1]
172 + day as u16,
173 )
174 })
175 }
176
177 #[inline]
190 pub const fn from_ordinal_date(year: i32, ordinal: u16) -> Result<Self, error::ComponentRange> {
191 match <Year>::new(year) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "year",
minimum: <Year>::MIN.get() as i64,
maximum: <Year>::MAX.get() as i64,
value: year as i64,
conditional_message: None,
});
}
};ensure_ranged!(Year: year);
192 match ordinal {
193 1..=365 => {}
194 366 if is_leap_year(year) => {}
195 _ => {
196 return Err(error::ComponentRange {
197 name: "ordinal",
198 minimum: 1,
199 maximum: days_in_year(year) as i64,
200 value: ordinal as i64,
201 conditional_message: Some("for the given year"),
202 });
203 }
204 }
205
206 Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
208 }
209
210 pub const fn from_iso_week_date(
224 year: i32,
225 week: u8,
226 weekday: Weekday,
227 ) -> Result<Self, error::ComponentRange> {
228 match <Year>::new(year) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "year",
minimum: <Year>::MIN.get() as i64,
maximum: <Year>::MAX.get() as i64,
value: year as i64,
conditional_message: None,
});
}
};ensure_ranged!(Year: year);
229 match week {
230 1..=52 => {}
231 53 if week <= weeks_in_year(year) => {}
232 _ => {
233 return Err(error::ComponentRange {
234 name: "week",
235 minimum: 1,
236 maximum: weeks_in_year(year) as i64,
237 value: week as i64,
238 conditional_message: Some("for the given year"),
239 });
240 }
241 }
242
243 let adj_year = year - 1;
244 let raw = 365 * adj_year + match (adj_year, 4) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (crate::size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(adj_year, 4) - match (adj_year, 100) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (crate::size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(adj_year, 100)
245 + match (adj_year, 400) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (crate::size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(adj_year, 400);
246 let jan_4 = match (raw % 7) as i8 {
247 -6 | 1 => 8,
248 -5 | 2 => 9,
249 -4 | 3 => 10,
250 -3 | 4 => 4,
251 -2 | 5 => 5,
252 -1 | 6 => 6,
253 _ => 7,
254 };
255 let ordinal = week as i16 * 7 + weekday.number_from_monday() as i16 - jan_4;
256
257 Ok(if ordinal <= 0 {
258 unsafe {
260 Self::__from_ordinal_date_unchecked(
261 year - 1,
262 (ordinal as u16).wrapping_add(days_in_year(year - 1)),
263 )
264 }
265 } else if ordinal > days_in_year(year) as i16 {
266 unsafe {
268 Self::__from_ordinal_date_unchecked(year + 1, ordinal as u16 - days_in_year(year))
269 }
270 } else {
271 unsafe { Self::__from_ordinal_date_unchecked(year, ordinal as u16) }
273 })
274 }
275
276 #[doc(alias = "from_julian_date")]
290 #[inline]
291 pub const fn from_julian_day(julian_day: i32) -> Result<Self, error::ComponentRange> {
292 type JulianDay = RangedI32<{ Date::MIN.to_julian_day() }, { Date::MAX.to_julian_day() }>;
293 match <JulianDay>::new(julian_day) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "julian_day",
minimum: <JulianDay>::MIN.get() as i64,
maximum: <JulianDay>::MAX.get() as i64,
value: julian_day as i64,
conditional_message: None,
});
}
};ensure_ranged!(JulianDay: julian_day);
294 Ok(unsafe { Self::from_julian_day_unchecked(julian_day) })
296 }
297
298 #[inline]
305 pub(crate) const unsafe fn from_julian_day_unchecked(julian_day: i32) -> Self {
306 if true {
if !(julian_day >= Self::MIN.to_julian_day()) {
::core::panicking::panic("assertion failed: julian_day >= Self::MIN.to_julian_day()")
};
};debug_assert!(julian_day >= Self::MIN.to_julian_day());
307 if true {
if !(julian_day <= Self::MAX.to_julian_day()) {
::core::panicking::panic("assertion failed: julian_day <= Self::MAX.to_julian_day()")
};
};debug_assert!(julian_day <= Self::MAX.to_julian_day());
308
309 const S: i32 = 2_500;
310 const K: i32 = 719_468 + 146_097 * S;
311 const L: i32 = 400 * S;
312
313 let julian_day = julian_day - 2_440_588;
314 let n = (julian_day + K) as u32;
315
316 let n_1 = 4 * n + 3;
317 let c = n_1 / 146_097;
318 let n_c = n_1 % 146_097 / 4;
319
320 let n_2 = 4 * n_c + 3;
321 let p_2 = 2_939_745 * n_2 as u64;
322 let z = (p_2 >> 32) as u32;
323 let n_y = p_2 as u32 / 2_939_745 / 4;
324 let y = 100 * c + z;
325
326 let j = n_y >= 306;
327 let y_g = y as i32 - L + j as i32;
328
329 let is_leap_year = is_leap_year(y_g);
330 let ordinal = if j {
331 n_y - 305
332 } else {
333 n_y + 60 + is_leap_year as u32
334 };
335
336 unsafe { Self::from_parts(y_g, is_leap_year, ordinal as u16) }
339 }
340
341 #[inline]
346 const fn is_in_leap_year(self) -> bool {
347 (self.value.get() >> 9) & 1 == 1
348 }
349
350 #[inline]
359 pub const fn year(self) -> i32 {
360 self.value.get() >> 10
361 }
362
363 #[inline]
372 pub const fn month(self) -> Month {
373 let ordinal = self.ordinal() as u32;
374 let jan_feb_len = 59 + self.is_in_leap_year() as u32;
375
376 let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len {
377 (0, 0)
378 } else {
379 (2, jan_feb_len)
380 };
381
382 let ordinal = ordinal - ordinal_adj;
383 let month = ((ordinal * 268 + 8031) >> 13) + month_adj;
384
385 unsafe {
387 match Month::from_number(NonZero::new_unchecked(month as u8)) {
388 Ok(month) => month,
389 Err(_) => core::hint::unreachable_unchecked(),
390 }
391 }
392 }
393
394 #[inline]
404 pub const fn day(self) -> u8 {
405 let ordinal = self.ordinal() as u32;
406 let jan_feb_len = 59 + self.is_in_leap_year() as u32;
407
408 let ordinal_adj = if ordinal <= jan_feb_len {
409 0
410 } else {
411 jan_feb_len
412 };
413
414 let ordinal = ordinal - ordinal_adj;
415 let month = (ordinal * 268 + 8031) >> 13;
416 let days_in_preceding_months = (month * 3917 - 3866) >> 7;
417 (ordinal - days_in_preceding_months) as u8
418 }
419
420 #[inline]
430 pub const fn ordinal(self) -> u16 {
431 (self.value.get() & 0x1FF) as u16
432 }
433
434 #[inline]
436 pub(crate) const fn iso_year_week(self) -> (i32, u8) {
437 let (year, ordinal) = self.to_ordinal_date();
438
439 match ((ordinal + 10 - self.weekday().number_from_monday() as u16) / 7) as u8 {
440 0 => (year - 1, weeks_in_year(year - 1)),
441 53 if weeks_in_year(year) == 52 => (year + 1, 1),
442 week => (year, week),
443 }
444 }
445
446 #[inline]
459 pub const fn iso_week(self) -> u8 {
460 self.iso_year_week().1
461 }
462
463 #[inline]
475 pub const fn sunday_based_week(self) -> u8 {
476 ((self.ordinal() as i16 - self.weekday().number_days_from_sunday() as i16 + 6) / 7) as u8
477 }
478
479 #[inline]
491 pub const fn monday_based_week(self) -> u8 {
492 ((self.ordinal() as i16 - self.weekday().number_days_from_monday() as i16 + 6) / 7) as u8
493 }
494
495 #[inline]
506 pub const fn to_calendar_date(self) -> (i32, Month, u8) {
507 let (year, ordinal) = self.to_ordinal_date();
508 let ordinal = ordinal as u32;
509 let jan_feb_len = 59 + self.is_in_leap_year() as u32;
510
511 let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len {
512 (0, 0)
513 } else {
514 (2, jan_feb_len)
515 };
516
517 let ordinal = ordinal - ordinal_adj;
518 let month = (ordinal * 268 + 8031) >> 13;
519 let days_in_preceding_months = (month * 3917 - 3866) >> 7;
520 let day = ordinal - days_in_preceding_months;
521 let month = month + month_adj;
522
523 (
524 year,
525 unsafe {
527 match Month::from_number(NonZero::new_unchecked(month as u8)) {
528 Ok(month) => month,
529 Err(_) => core::hint::unreachable_unchecked(),
530 }
531 },
532 day as u8,
533 )
534 }
535
536 #[inline]
543 pub const fn to_ordinal_date(self) -> (i32, u16) {
544 (self.year(), self.ordinal())
545 }
546
547 #[inline]
559 pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
560 let (year, ordinal) = self.to_ordinal_date();
561 let weekday = self.weekday();
562
563 match ((ordinal + 10 - weekday.number_from_monday() as u16) / 7) as u8 {
564 0 => (year - 1, weeks_in_year(year - 1), weekday),
565 53 if weeks_in_year(year) == 52 => (year + 1, 1, weekday),
566 week => (year, week, weekday),
567 }
568 }
569
570 #[inline]
589 pub const fn weekday(self) -> Weekday {
590 match self.to_julian_day() % 7 {
591 -6 | 1 => Weekday::Tuesday,
592 -5 | 2 => Weekday::Wednesday,
593 -4 | 3 => Weekday::Thursday,
594 -3 | 4 => Weekday::Friday,
595 -2 | 5 => Weekday::Saturday,
596 -1 | 6 => Weekday::Sunday,
597 val => {
598 if true {
if !(val == 0) { ::core::panicking::panic("assertion failed: val == 0") };
};debug_assert!(val == 0);
599 Weekday::Monday
600 }
601 }
602 }
603
604 #[inline]
615 pub const fn next_day(self) -> Option<Self> {
616 if self.ordinal() == 366 || (self.ordinal() == 365 && !self.is_in_leap_year()) {
617 if self.value.get() == Self::MAX.value.get() {
618 None
619 } else {
620 unsafe { Some(Self::__from_ordinal_date_unchecked(self.year() + 1, 1)) }
622 }
623 } else {
624 Some(Self {
625 value: unsafe { NonZero::new_unchecked(self.value.get() + 1) },
627 })
628 }
629 }
630
631 #[inline]
642 pub const fn previous_day(self) -> Option<Self> {
643 if self.ordinal() != 1 {
644 Some(Self {
645 value: unsafe { NonZero::new_unchecked(self.value.get() - 1) },
647 })
648 } else if self.value.get() == Self::MIN.value.get() {
649 None
650 } else {
651 Some(unsafe {
653 Self::__from_ordinal_date_unchecked(self.year() - 1, days_in_year(self.year() - 1))
654 })
655 }
656 }
657
658 #[inline]
677 #[track_caller]
678 pub const fn next_occurrence(self, weekday: Weekday) -> Self {
679 match self.checked_next_occurrence(weekday) {
Some(value) => value,
None =>
crate::expect_failed("overflow calculating the next occurrence of a weekday"),
}expect_opt!(
680 self.checked_next_occurrence(weekday),
681 "overflow calculating the next occurrence of a weekday"
682 )
683 }
684
685 #[inline]
704 #[track_caller]
705 pub const fn prev_occurrence(self, weekday: Weekday) -> Self {
706 match self.checked_prev_occurrence(weekday) {
Some(value) => value,
None =>
crate::expect_failed("overflow calculating the previous occurrence of a weekday"),
}expect_opt!(
707 self.checked_prev_occurrence(weekday),
708 "overflow calculating the previous occurrence of a weekday"
709 )
710 }
711
712 #[inline]
731 #[track_caller]
732 pub const fn nth_next_occurrence(self, weekday: Weekday, n: u8) -> Self {
733 match self.checked_nth_next_occurrence(weekday, n) {
Some(value) => value,
None =>
crate::expect_failed("overflow calculating the next occurrence of a weekday"),
}expect_opt!(
734 self.checked_nth_next_occurrence(weekday, n),
735 "overflow calculating the next occurrence of a weekday"
736 )
737 }
738
739 #[inline]
758 #[track_caller]
759 pub const fn nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Self {
760 match self.checked_nth_prev_occurrence(weekday, n) {
Some(value) => value,
None =>
crate::expect_failed("overflow calculating the previous occurrence of a weekday"),
}expect_opt!(
761 self.checked_nth_prev_occurrence(weekday, n),
762 "overflow calculating the previous occurrence of a weekday"
763 )
764 }
765
766 #[inline]
776 pub const fn to_julian_day(self) -> i32 {
777 let (year, ordinal) = self.to_ordinal_date();
778
779 let adj_year = year + 999_999;
782 let century = adj_year / 100;
783
784 let days_before_year = (1461 * adj_year as i64 / 4) as i32 - century + century / 4;
785 days_before_year + ordinal as i32 - 363_521_075
786 }
787
788 #[inline]
820 pub const fn checked_add(self, duration: Duration) -> Option<Self> {
821 let whole_days = duration.whole_days();
822 if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
823 return None;
824 }
825
826 let julian_day = match self.to_julian_day().checked_add(whole_days as i32) {
Some(value) => value,
None => return None,
}const_try_opt!(self.to_julian_day().checked_add(whole_days as i32));
827 if let Ok(date) = Self::from_julian_day(julian_day) {
828 Some(date)
829 } else {
830 None
831 }
832 }
833
834 #[inline]
864 pub const fn checked_add_std(self, duration: StdDuration) -> Option<Self> {
865 let whole_days = duration.as_secs() / Second::per_t::<u64>(Day);
866 if whole_days > i32::MAX as u64 {
867 return None;
868 }
869
870 let julian_day = match self.to_julian_day().checked_add(whole_days as i32) {
Some(value) => value,
None => return None,
}const_try_opt!(self.to_julian_day().checked_add(whole_days as i32));
871 if let Ok(date) = Self::from_julian_day(julian_day) {
872 Some(date)
873 } else {
874 None
875 }
876 }
877
878 #[inline]
910 pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
911 let whole_days = duration.whole_days();
912 if whole_days < i32::MIN as i64 || whole_days > i32::MAX as i64 {
913 return None;
914 }
915
916 let julian_day = match self.to_julian_day().checked_sub(whole_days as i32) {
Some(value) => value,
None => return None,
}const_try_opt!(self.to_julian_day().checked_sub(whole_days as i32));
917 if let Ok(date) = Self::from_julian_day(julian_day) {
918 Some(date)
919 } else {
920 None
921 }
922 }
923
924 #[inline]
954 pub const fn checked_sub_std(self, duration: StdDuration) -> Option<Self> {
955 let whole_days = duration.as_secs() / Second::per_t::<u64>(Day);
956 if whole_days > i32::MAX as u64 {
957 return None;
958 }
959
960 let julian_day = match self.to_julian_day().checked_sub(whole_days as i32) {
Some(value) => value,
None => return None,
}const_try_opt!(self.to_julian_day().checked_sub(whole_days as i32));
961 if let Ok(date) = Self::from_julian_day(julian_day) {
962 Some(date)
963 } else {
964 None
965 }
966 }
967
968 #[inline]
971 pub(crate) const fn checked_next_occurrence(self, weekday: Weekday) -> Option<Self> {
972 let day_diff = match weekday as i8 - self.weekday() as i8 {
973 1 | -6 => 1,
974 2 | -5 => 2,
975 3 | -4 => 3,
976 4 | -3 => 4,
977 5 | -2 => 5,
978 6 | -1 => 6,
979 val => {
980 if true {
if !(val == 0) { ::core::panicking::panic("assertion failed: val == 0") };
};debug_assert!(val == 0);
981 7
982 }
983 };
984
985 self.checked_add(Duration::days(day_diff))
986 }
987
988 #[inline]
991 pub(crate) const fn checked_prev_occurrence(self, weekday: Weekday) -> Option<Self> {
992 let day_diff = match weekday as i8 - self.weekday() as i8 {
993 1 | -6 => 6,
994 2 | -5 => 5,
995 3 | -4 => 4,
996 4 | -3 => 3,
997 5 | -2 => 2,
998 6 | -1 => 1,
999 val => {
1000 if true {
if !(val == 0) { ::core::panicking::panic("assertion failed: val == 0") };
};debug_assert!(val == 0);
1001 7
1002 }
1003 };
1004
1005 self.checked_sub(Duration::days(day_diff))
1006 }
1007
1008 #[inline]
1011 pub(crate) const fn checked_nth_next_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
1012 if n == 0 {
1013 return None;
1014 }
1015
1016 match self.checked_next_occurrence(weekday) {
Some(value) => value,
None => return None,
}const_try_opt!(self.checked_next_occurrence(weekday))
1017 .checked_add(Duration::weeks(n as i64 - 1))
1018 }
1019
1020 #[inline]
1023 pub(crate) const fn checked_nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Option<Self> {
1024 if n == 0 {
1025 return None;
1026 }
1027
1028 match self.checked_prev_occurrence(weekday) {
Some(value) => value,
None => return None,
}const_try_opt!(self.checked_prev_occurrence(weekday))
1029 .checked_sub(Duration::weeks(n as i64 - 1))
1030 }
1031
1032 #[inline]
1062 pub const fn saturating_add(self, duration: Duration) -> Self {
1063 if let Some(datetime) = self.checked_add(duration) {
1064 datetime
1065 } else if duration.is_negative() {
1066 Self::MIN
1067 } else {
1068 if true {
if !duration.is_positive() {
::core::panicking::panic("assertion failed: duration.is_positive()")
};
};debug_assert!(duration.is_positive());
1069 Self::MAX
1070 }
1071 }
1072
1073 #[inline]
1103 pub const fn saturating_sub(self, duration: Duration) -> Self {
1104 if let Some(datetime) = self.checked_sub(duration) {
1105 datetime
1106 } else if duration.is_negative() {
1107 Self::MAX
1108 } else {
1109 if true {
if !duration.is_positive() {
::core::panicking::panic("assertion failed: duration.is_positive()")
};
};debug_assert!(duration.is_positive());
1110 Self::MIN
1111 }
1112 }
1113
1114 #[inline]
1126 #[must_use = "This method does not mutate the original `Date`."]
1127 pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1128 match <Year>::new(year) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "year",
minimum: <Year>::MIN.get() as i64,
maximum: <Year>::MAX.get() as i64,
value: year as i64,
conditional_message: None,
});
}
};ensure_ranged!(Year: year);
1129
1130 let ordinal = self.ordinal();
1131
1132 if ordinal <= 59 {
1134 return Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) });
1136 }
1137
1138 match (self.is_in_leap_year(), is_leap_year(year)) {
1139 (false, false) | (true, true) => {
1140 Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal) })
1142 }
1143 (true, false) if ordinal == 60 => Err(error::ComponentRange {
1145 name: "day",
1146 value: 29,
1147 minimum: 1,
1148 maximum: 28,
1149 conditional_message: Some("for the given month and year"),
1150 }),
1151 (false, true) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal + 1) }),
1155 (true, false) => Ok(unsafe { Self::__from_ordinal_date_unchecked(year, ordinal - 1) }),
1159 }
1160 }
1161
1162 #[inline]
1176 #[must_use = "This method does not mutate the original `Date`."]
1177 pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1178 let (year, _, day) = self.to_calendar_date();
1179 Self::from_calendar_date(year, month, day)
1180 }
1181
1182 #[inline]
1191 #[must_use = "This method does not mutate the original `Date`."]
1192 pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1193 match day {
1194 1..=28 => {}
1195 29..=31 if day <= self.month().length(self.year()) => {}
1196 _ => {
1197 return Err(error::ComponentRange {
1198 name: "day",
1199 minimum: 1,
1200 maximum: self.month().length(self.year()) as i64,
1201 value: day as i64,
1202 conditional_message: Some("for the given month and year"),
1203 });
1204 }
1205 }
1206
1207 Ok(unsafe {
1209 Self::__from_ordinal_date_unchecked(
1210 self.year(),
1211 (self.ordinal() as i16 - self.day() as i16 + day as i16) as u16,
1212 )
1213 })
1214 }
1215
1216 #[inline]
1225 #[must_use = "This method does not mutate the original `Date`."]
1226 pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1227 match ordinal {
1228 1..=365 => {}
1229 366 if self.is_in_leap_year() => {}
1230 _ => {
1231 return Err(error::ComponentRange {
1232 name: "ordinal",
1233 minimum: 1,
1234 maximum: days_in_year(self.year()) as i64,
1235 value: ordinal as i64,
1236 conditional_message: Some("for the given year"),
1237 });
1238 }
1239 }
1240
1241 Ok(unsafe { Self::__from_ordinal_date_unchecked(self.year(), ordinal) })
1243 }
1244}
1245
1246impl Date {
1248 #[inline]
1256 pub const fn midnight(self) -> PrimitiveDateTime {
1257 PrimitiveDateTime::new(self, Time::MIDNIGHT)
1258 }
1259
1260 #[inline]
1270 pub const fn with_time(self, time: Time) -> PrimitiveDateTime {
1271 PrimitiveDateTime::new(self, time)
1272 }
1273
1274 #[inline]
1282 pub const fn with_hms(
1283 self,
1284 hour: u8,
1285 minute: u8,
1286 second: u8,
1287 ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1288 Ok(PrimitiveDateTime::new(
1289 self,
1290 match Time::from_hms(hour, minute, second) {
Ok(value) => value,
Err(error) => return Err(error),
}const_try!(Time::from_hms(hour, minute, second)),
1291 ))
1292 }
1293
1294 #[inline]
1302 pub const fn with_hms_milli(
1303 self,
1304 hour: u8,
1305 minute: u8,
1306 second: u8,
1307 millisecond: u16,
1308 ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1309 Ok(PrimitiveDateTime::new(
1310 self,
1311 match Time::from_hms_milli(hour, minute, second, millisecond) {
Ok(value) => value,
Err(error) => return Err(error),
}const_try!(Time::from_hms_milli(hour, minute, second, millisecond)),
1312 ))
1313 }
1314
1315 #[inline]
1323 pub const fn with_hms_micro(
1324 self,
1325 hour: u8,
1326 minute: u8,
1327 second: u8,
1328 microsecond: u32,
1329 ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1330 Ok(PrimitiveDateTime::new(
1331 self,
1332 match Time::from_hms_micro(hour, minute, second, microsecond) {
Ok(value) => value,
Err(error) => return Err(error),
}const_try!(Time::from_hms_micro(hour, minute, second, microsecond)),
1333 ))
1334 }
1335
1336 #[inline]
1344 pub const fn with_hms_nano(
1345 self,
1346 hour: u8,
1347 minute: u8,
1348 second: u8,
1349 nanosecond: u32,
1350 ) -> Result<PrimitiveDateTime, error::ComponentRange> {
1351 Ok(PrimitiveDateTime::new(
1352 self,
1353 match Time::from_hms_nano(hour, minute, second, nanosecond) {
Ok(value) => value,
Err(error) => return Err(error),
}const_try!(Time::from_hms_nano(hour, minute, second, nanosecond)),
1354 ))
1355 }
1356}
1357
1358#[cfg(feature = "formatting")]
1359impl Date {
1360 #[inline]
1362 pub fn format_into(
1363 self,
1364 output: &mut (impl io::Write + ?Sized),
1365 format: &(impl Formattable + ?Sized),
1366 ) -> Result<usize, error::Format> {
1367 format.format_into(output, Some(self), None, None)
1368 }
1369
1370 #[inline]
1380 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1381 format.format(Some(self), None, None)
1382 }
1383}
1384
1385#[cfg(feature = "parsing")]
1386impl Date {
1387 #[inline]
1398 pub fn parse(
1399 input: &str,
1400 description: &(impl Parsable + ?Sized),
1401 ) -> Result<Self, error::Parse> {
1402 description.parse_date(input.as_bytes())
1403 }
1404}
1405
1406mod private {
1407 #[non_exhaustive]
1408 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for DateMetadata {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field5_finish(f, "DateMetadata",
"year_width", &self.year_width, "display_sign",
&self.display_sign, "year", &self.year, "month", &self.month,
"day", &&self.day)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for DateMetadata {
#[inline]
fn clone(&self) -> DateMetadata {
let _: ::core::clone::AssertParamIsClone<u8>;
let _: ::core::clone::AssertParamIsClone<bool>;
let _: ::core::clone::AssertParamIsClone<i32>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DateMetadata { }Copy)]
1409 pub struct DateMetadata {
1410 pub(super) year_width: u8,
1412 pub(super) display_sign: bool,
1414 pub(super) year: i32,
1415 pub(super) month: u8,
1416 pub(super) day: u8,
1417 }
1418}
1419use private::DateMetadata;
1420
1421impl SmartDisplay for Date {
1422 type Metadata = DateMetadata;
1423
1424 #[inline]
1425 fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
1426 let (year, month, day) = self.to_calendar_date();
1427
1428 let mut year_width = cmp::max(year.unsigned_abs().num_digits(), 4);
1430 let display_sign = if !(0..10_000).contains(&year) {
1431 year_width += 1;
1433 true
1434 } else {
1435 false
1436 };
1437
1438 let formatted_width = year_width.extend::<usize>()
1439 + 0 +
::powerfmt::smart_display::Metadata::padded_width_of(&"-",
::powerfmt::smart_display::FormatterOptions::default()) +
::powerfmt::smart_display::Metadata::padded_width_of(&u8::from(month),
*::powerfmt::smart_display::FormatterOptions::default().with_width(Some(2)))
+
::powerfmt::smart_display::Metadata::padded_width_of(&"-",
::powerfmt::smart_display::FormatterOptions::default()) +
::powerfmt::smart_display::Metadata::padded_width_of(&day,
*::powerfmt::smart_display::FormatterOptions::default().with_width(Some(2)))smart_display::padded_width_of!(
1440 "-",
1441 u8::from(month) => width(2),
1442 "-",
1443 day => width(2),
1444 );
1445
1446 Metadata::new(
1447 formatted_width,
1448 self,
1449 DateMetadata {
1450 year_width,
1451 display_sign,
1452 year,
1453 month: u8::from(month),
1454 day,
1455 },
1456 )
1457 }
1458
1459 #[inline]
1460 fn fmt_with_metadata(
1461 &self,
1462 f: &mut fmt::Formatter<'_>,
1463 metadata: Metadata<Self>,
1464 ) -> fmt::Result {
1465 let DateMetadata {
1466 year_width,
1467 display_sign,
1468 year,
1469 month,
1470 day,
1471 } = *metadata;
1472 let year_width = year_width.extend();
1473
1474 if display_sign {
1475 f.pad_with_width(
1476 metadata.unpadded_width(),
1477 format_args!("{0:+01$}-{2:02}-{3:02}", year, year_width, month, day)format_args!("{year:+0year_width$}-{month:02}-{day:02}"),
1478 )
1479 } else {
1480 f.pad_with_width(
1481 metadata.unpadded_width(),
1482 format_args!("{0:01$}-{2:02}-{3:02}", year, year_width, month, day)format_args!("{year:0year_width$}-{month:02}-{day:02}"),
1483 )
1484 }
1485 }
1486}
1487
1488impl fmt::Display for Date {
1489 #[inline]
1490 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1491 SmartDisplay::fmt(self, f)
1492 }
1493}
1494
1495impl fmt::Debug for Date {
1496 #[inline]
1497 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1498 fmt::Display::fmt(self, f)
1499 }
1500}
1501
1502impl Add<Duration> for Date {
1503 type Output = Self;
1504
1505 #[inline]
1509 #[track_caller]
1510 fn add(self, duration: Duration) -> Self::Output {
1511 self.checked_add(duration)
1512 .expect("overflow adding duration to date")
1513 }
1514}
1515
1516impl Add<StdDuration> for Date {
1517 type Output = Self;
1518
1519 #[inline]
1523 #[track_caller]
1524 fn add(self, duration: StdDuration) -> Self::Output {
1525 self.checked_add_std(duration)
1526 .expect("overflow adding duration to date")
1527 }
1528}
1529
1530#[allow(unused_qualifications)]
impl core::ops::AddAssign<StdDuration> for Date {
#[inline]
fn add_assign(&mut self, rhs: StdDuration) { *self = *self + rhs; }
}impl_add_assign!(Date: Duration, StdDuration);
1531
1532impl Sub<Duration> for Date {
1533 type Output = Self;
1534
1535 #[inline]
1539 #[track_caller]
1540 fn sub(self, duration: Duration) -> Self::Output {
1541 self.checked_sub(duration)
1542 .expect("overflow subtracting duration from date")
1543 }
1544}
1545
1546impl Sub<StdDuration> for Date {
1547 type Output = Self;
1548
1549 #[inline]
1553 #[track_caller]
1554 fn sub(self, duration: StdDuration) -> Self::Output {
1555 self.checked_sub_std(duration)
1556 .expect("overflow subtracting duration from date")
1557 }
1558}
1559
1560#[allow(unused_qualifications)]
impl core::ops::SubAssign<StdDuration> for Date {
#[inline]
fn sub_assign(&mut self, rhs: StdDuration) { *self = *self - rhs; }
}impl_sub_assign!(Date: Duration, StdDuration);
1561
1562impl Sub for Date {
1563 type Output = Duration;
1564
1565 #[inline]
1566 fn sub(self, other: Self) -> Self::Output {
1567 Duration::days((self.to_julian_day() - other.to_julian_day()).extend())
1568 }
1569}