1#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::cmp::Ordering;
6use core::fmt;
7use core::hash::{Hash, Hasher};
8use core::mem::MaybeUninit;
9use core::ops::{Add, AddAssign, Sub, SubAssign};
10use core::time::Duration as StdDuration;
11#[cfg(feature = "formatting")]
12use std::io;
13#[cfg(feature = "std")]
14use std::time::SystemTime;
15
16use deranged::{ri64, ri128, ru8, ru32};
17
18#[cfg(any(feature = "formatting", feature = "parsing"))]
19use crate::PrivateMethod;
20#[cfg(feature = "formatting")]
21use crate::formatting::Formattable;
22use crate::internal_macros::{bug, const_try, div_floor, ensure_ranged};
23use crate::num_fmt::{str_from_raw_parts, truncated_subsecond_from_nanos, u64_pad_none};
24#[cfg(feature = "parsing")]
25use crate::parsing::{Parsable, Parsed};
26use crate::unit::*;
27use crate::util::Overflow;
28use crate::{
29 Date, Month, OffsetDateTime, SignedDuration, Time, UtcDateTime, UtcOffset, Weekday, error, util,
30};
31
32pub(crate) type Seconds =
34 ri64<{ UtcDateTime::MIN.unix_timestamp() }, { UtcDateTime::MAX.unix_timestamp() }>;
35type Nanoseconds = ru32<0, 999_999_999>;
36
37const _: () = {
40 if !(Timestamp::MIN.time().as_u64() == Time::MIDNIGHT.as_u64()) {
::core::panicking::panic("assertion failed: Timestamp::MIN.time().as_u64() == Time::MIDNIGHT.as_u64()")
};assert!(Timestamp::MIN.time().as_u64() == Time::MIDNIGHT.as_u64());
41 if !(Timestamp::MAX.time().as_u64() == Time::MAX.as_u64()) {
::core::panicking::panic("assertion failed: Timestamp::MAX.time().as_u64() == Time::MAX.as_u64()")
};assert!(Timestamp::MAX.time().as_u64() == Time::MAX.as_u64());
42};
43
44#[repr(u32)]
47#[derive(#[automatically_derived]
impl ::core::clone::Clone for Padding {
#[inline]
fn clone(&self) -> Padding { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Padding { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for Padding {
#[inline]
fn eq(&self, other: &Padding) -> bool { true }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Padding {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
48enum Padding {
49 #[allow(clippy::missing_docs_in_private_items)]
50 Optimize,
51}
52
53#[derive(#[automatically_derived]
impl ::core::clone::Clone for Timestamp {
#[inline]
fn clone(&self) -> Timestamp {
let _: ::core::clone::AssertParamIsClone<Padding>;
let _: ::core::clone::AssertParamIsClone<Nanoseconds>;
let _: ::core::clone::AssertParamIsClone<Seconds>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Timestamp { }Copy, #[automatically_derived]
impl ::core::cmp::Eq for Timestamp {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Padding>;
let _: ::core::cmp::AssertParamIsEq<Nanoseconds>;
let _: ::core::cmp::AssertParamIsEq<Seconds>;
}
}Eq)]
58#[cfg_attr(not(docsrs), repr(C))]
59pub struct Timestamp {
60 #[cfg(target_endian = "big")]
61 seconds: Seconds,
62 #[cfg(target_endian = "big")]
63 nanoseconds: Nanoseconds,
64 #[cfg(target_endian = "big")]
65 padding: Padding,
66
67 #[cfg(target_endian = "little")]
68 padding: Padding,
69 #[cfg(target_endian = "little")]
70 nanoseconds: Nanoseconds,
71 #[cfg(target_endian = "little")]
72 seconds: Seconds,
73}
74
75impl Hash for Timestamp {
76 #[inline]
77 fn hash<H: Hasher>(&self, state: &mut H) {
78 state.write_i128(self.as_i128());
79 }
80}
81
82impl PartialEq for Timestamp {
83 #[inline]
84 fn eq(&self, other: &Self) -> bool {
85 self.as_i128() == other.as_i128()
86 }
87}
88
89impl PartialOrd for Timestamp {
90 #[inline]
91 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
92 Some(self.cmp(other))
93 }
94}
95
96impl Ord for Timestamp {
97 #[inline]
98 fn cmp(&self, other: &Self) -> Ordering {
99 self.as_i128().cmp(&other.as_i128())
100 }
101}
102
103impl Timestamp {
104 #[inline]
105 const fn as_i128(self) -> i128 {
106 unsafe { core::mem::transmute(self) }
110 }
111
112 pub const UNIX_EPOCH: Self =
114 Self::new_ranged(Seconds::new_static::<0>(), Nanoseconds::new_static::<0>());
115
116 pub const MIN: Self = Self::new_ranged(Seconds::MIN, Nanoseconds::MIN);
121
122 pub const MAX: Self = Self::new_ranged(Seconds::MAX, Nanoseconds::MAX);
127
128 #[cfg(feature = "std")]
135 #[inline]
136 pub fn now() -> Self {
137 SystemTime::now().into()
138 }
139
140 #[doc(hidden)]
147 #[inline]
148 #[track_caller]
149 pub const unsafe fn __new_unchecked(seconds: i64, nanoseconds: u32) -> Self {
150 unsafe {
152 Self::new_ranged(
153 Seconds::new_unchecked(seconds),
154 Nanoseconds::new_unchecked(nanoseconds),
155 )
156 }
157 }
158
159 #[inline]
162 pub(crate) const fn new_ranged(seconds: Seconds, nanoseconds: Nanoseconds) -> Self {
163 Self {
164 seconds,
165 nanoseconds,
166 padding: Padding::Optimize,
167 }
168 }
169
170 #[inline]
179 pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Self, error::ComponentRange> {
180 Ok(Self::new_ranged(
181 match <Seconds>::new(seconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("seconds"));
}
}ensure_ranged!(Seconds: seconds),
182 match <Nanoseconds>::new(nanoseconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("nanoseconds"));
}
}ensure_ranged!(Nanoseconds: nanoseconds),
183 ))
184 }
185
186 #[inline]
195 pub const fn from_seconds(seconds: i64) -> Result<Self, error::ComponentRange> {
196 Ok(Self::new_ranged(
197 match <Seconds>::new(seconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("seconds"));
}
}ensure_ranged!(Seconds: seconds),
198 Nanoseconds::new_static::<0>(),
199 ))
200 }
201
202 #[inline]
211 pub const fn from_milliseconds(milliseconds: i64) -> Result<Self, error::ComponentRange> {
212 const MAX: i64 = Seconds::MAX.get() * Millisecond::per_t::<i64>(Second)
213 + (Nanoseconds::MAX.get() as i64) / Nanosecond::per_t::<i64>(Millisecond);
214 const MIN: i64 = Seconds::MIN.get() * Millisecond::per_t::<i64>(Second)
215 + (Nanoseconds::MIN.get() as i64) / Nanosecond::per_t::<i64>(Millisecond);
216
217 match <ri64<MIN, MAX>>::new(milliseconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("milliseconds"));
}
};ensure_ranged!(ri64<MIN, MAX>: milliseconds);
218
219 let mut seconds = milliseconds / Millisecond::per_t::<i64>(Second);
220 let nanoseconds = (milliseconds.rem_euclid(Millisecond::per_t(Second))
221 * Nanosecond::per_t::<i64>(Millisecond)) as u32;
222
223 if milliseconds < 0 && nanoseconds != 0 {
224 seconds -= 1;
225 }
226
227 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
229 }
230
231 #[inline]
240 pub const fn from_microseconds(microseconds: i128) -> Result<Self, error::ComponentRange> {
241 const MAX: i128 = Seconds::MAX.get() as i128 * Microsecond::per_t::<i128>(Second)
242 + (Nanoseconds::MAX.get() as i128) / Nanosecond::per_t::<i128>(Microsecond);
243 const MIN: i128 = Seconds::MIN.get() as i128 * Microsecond::per_t::<i128>(Second)
244 + (Nanoseconds::MIN.get() as i128) / Nanosecond::per_t::<i128>(Microsecond);
245
246 match <ri128<MIN, MAX>>::new(microseconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("microseconds"));
}
};ensure_ranged!(ri128<MIN, MAX>: microseconds);
247
248 let mut seconds = (microseconds / Microsecond::per_t::<i128>(Second)) as i64;
249 let nanoseconds = (microseconds.rem_euclid(Microsecond::per_t(Second))
250 * Nanosecond::per_t::<i128>(Microsecond)) as u32;
251
252 if microseconds < 0 && nanoseconds != 0 {
253 seconds -= 1;
254 }
255
256 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
258 }
259
260 #[inline]
269 pub const fn from_nanoseconds(nanoseconds: i128) -> Result<Self, error::ComponentRange> {
270 const MAX: i128 = Seconds::MAX.get() as i128 * Nanosecond::per_t::<i128>(Second)
271 + Nanoseconds::MAX.get() as i128;
272 const MIN: i128 = Seconds::MIN.get() as i128 * Nanosecond::per_t::<i128>(Second)
273 + Nanoseconds::MIN.get() as i128;
274
275 match <ri128<MIN, MAX>>::new(nanoseconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("nanoseconds"));
}
};ensure_ranged!(ri128<MIN, MAX>: nanoseconds);
276
277 let input_is_negative = nanoseconds < 0;
278 let mut seconds = (nanoseconds / Nanosecond::per_t::<i128>(Second)) as i64;
279 let nanoseconds = nanoseconds.rem_euclid(Nanosecond::per_t(Second)) as u32;
280
281 if input_is_negative && nanoseconds != 0 {
282 seconds -= 1;
283 }
284
285 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
287 }
288
289 #[inline]
302 pub const fn to_offset(self, offset: UtcOffset) -> OffsetDateTime {
303 self.to_utc().to_offset(offset)
304 }
305
306 #[inline]
318 pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<OffsetDateTime> {
319 self.to_utc().checked_to_offset(offset)
320 }
321
322 #[inline]
329 pub const fn to_utc(self) -> UtcDateTime {
330 let Ok(utc_dt) = UtcDateTime::from_unix_timestamp(self.seconds.get()) else {
331 {
crate::hint::cold_path();
{
::core::panicking::panic_fmt(format_args!("internal error: timestamp was invalid beforehand"));
}
};bug!("timestamp was invalid beforehand");
332 };
333 let Ok(utc_dt) = utc_dt.replace_nanosecond(self.nanoseconds.get()) else {
334 {
crate::hint::cold_path();
{
::core::panicking::panic_fmt(format_args!("internal error: nanosecond was invalid beforehand"));
}
};bug!("nanosecond was invalid beforehand");
335 };
336
337 utc_dt
338 }
339
340 #[inline]
342 pub(crate) const fn as_parts_ranged(self) -> (Seconds, Nanoseconds) {
343 (self.seconds, self.nanoseconds)
344 }
345
346 #[inline]
355 pub const fn as_seconds(self) -> i64 {
356 self.seconds.get()
357 }
358
359 #[inline]
371 pub const fn as_milliseconds(self) -> i64 {
372 self.seconds.get() * Millisecond::per_t::<i64>(Second)
373 + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as i64
374 }
375
376 #[inline]
388 pub const fn as_microseconds(self) -> i128 {
389 self.seconds.get() as i128 * Microsecond::per_t::<i128>(Second)
390 + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)) as i128
391 }
392
393 #[inline]
405 pub const fn as_nanoseconds(self) -> i128 {
406 self.seconds.get() as i128 * Nanosecond::per_t::<i128>(Second)
407 + self.nanoseconds.get() as i128
408 }
409
410 #[inline]
417 pub const fn date(self) -> Date {
418 self.to_utc().date()
419 }
420
421 #[inline]
428 pub const fn time(self) -> Time {
429 let within_day = self.as_seconds().rem_euclid(Second::per_t::<i64>(Day)) as u32;
430
431 let hour = within_day / Second::per_t::<u32>(Hour);
432 let minute =
433 (within_day - hour * Second::per_t::<u32>(Hour)) / Second::per_t::<u32>(Minute);
434 let second =
435 within_day - hour * Second::per_t::<u32>(Hour) - minute * Second::per_t::<u32>(Minute);
436
437 unsafe {
439 Time::__from_hms_nanos_unchecked(
440 hour as u8,
441 minute as u8,
442 second as u8,
443 self.nanosecond(),
444 )
445 }
446 }
447
448 #[inline]
454 const fn year_leap_ordinal(self) -> (i32, bool, u16) {
455 const ERAS: u32 = 5_949;
456 const D_SHIFT: u32 = 146097 * ERAS + 719_528;
457 const Y_SHIFT: u32 = 400 * ERAS;
458
459 const CEN_MUL: u32 = ((4u64 << 47) / 146_097) as u32;
460 const JUL_MUL: u32 = ((4u64 << 40) / 1_461 + 1) as u32;
461 const CEN_CUT: u32 = ((365u64 << 32) / 36_525) as u32;
462
463 let raw_day = match (self.as_seconds(), Second::per_t::<i64>(Day)) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(self.as_seconds(), Second::per_t::<i64>(Day)) as i32;
464
465 let day = raw_day.cast_unsigned().wrapping_add(D_SHIFT);
466 let c_n = (day as u64 * CEN_MUL as u64) >> 15;
467 let cen = (c_n >> 32) as u32;
468 let cpt = c_n as u32;
469 let ijy = cpt > CEN_CUT || cen.is_multiple_of(4);
470 let jul = day - cen / 4 + cen;
471 let y_n = (jul as u64 * JUL_MUL as u64) >> 8;
472 let yrs = (y_n >> 32) as u32;
473 let ypt = y_n as u32;
474
475 let year = yrs.wrapping_sub(Y_SHIFT).cast_signed();
476 let ordinal = ((ypt as u64 * 1_461) >> 34) as u32 + ijy as u32;
477 let leap = yrs.is_multiple_of(4) & ijy;
478
479 (year, leap, ordinal as u16)
480 }
481
482 #[inline]
489 pub const fn year(self) -> i32 {
490 self.year_leap_ordinal().0
491 }
492
493 #[inline]
501 pub const fn month(self) -> Month {
502 let (_, leap, ordinal) = self.year_leap_ordinal();
503 util::leap_ordinal_to_month_day(leap, ordinal).0
504 }
505
506 #[inline]
515 pub const fn day(self) -> u8 {
516 let (_, leap, ordinal) = self.year_leap_ordinal();
517 util::leap_ordinal_to_month_day(leap, ordinal).1
518 }
519
520 #[inline]
529 pub const fn ordinal(self) -> u16 {
530 self.year_leap_ordinal().2
531 }
532
533 #[inline]
542 pub const fn iso_week(self) -> u8 {
543 self.date().iso_week()
544 }
545
546 #[inline]
555 pub const fn sunday_based_week(self) -> u8 {
556 self.date().sunday_based_week()
557 }
558
559 #[inline]
568 pub const fn monday_based_week(self) -> u8 {
569 self.date().monday_based_week()
570 }
571
572 #[inline]
583 pub const fn to_calendar_date(self) -> (i32, Month, u8) {
584 let (year, leap, ordinal) = self.year_leap_ordinal();
585 let (month, day) = util::leap_ordinal_to_month_day(leap, ordinal);
586 (year, month, day)
587 }
588
589 #[inline]
596 pub const fn to_ordinal_date(self) -> (i32, u16) {
597 let (year, _, ordinal) = self.year_leap_ordinal();
598 (year, ordinal)
599 }
600
601 #[inline]
612 pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
613 self.date().to_iso_week_date()
614 }
615
616 #[inline]
624 pub const fn weekday(self) -> Weekday {
625 match (match (self.seconds.get(), 86_400) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(self.seconds.get(), 86_400) + 365_961_669) % 7 {
631 0 => Weekday::Monday,
632 1 => Weekday::Tuesday,
633 2 => Weekday::Wednesday,
634 3 => Weekday::Thursday,
635 4 => Weekday::Friday,
636 5 => Weekday::Saturday,
637 6 => Weekday::Sunday,
638 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
639 }
640 }
641
642 #[inline]
649 pub const fn to_julian_day(self) -> i32 {
650 const UNIX_EPOCH_JULIAN_DAY: i32 = Date::UNIX_EPOCH.to_julian_day();
651 match (self.seconds.get(), 86_400) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(self.seconds.get(), 86_400) as i32 + UNIX_EPOCH_JULIAN_DAY
652 }
653
654 #[inline]
661 pub const fn as_hms(self) -> (u8, u8, u8) {
662 self.time().as_hms()
663 }
664
665 #[inline]
672 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
673 self.time().as_hms_milli()
674 }
675
676 #[inline]
686 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
687 self.time().as_hms_micro()
688 }
689
690 #[inline]
700 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
701 self.time().as_hms_nano()
702 }
703
704 #[inline]
711 pub const fn hour(self) -> u8 {
712 self.time().hour()
713 }
714
715 #[inline]
722 pub const fn minute(self) -> u8 {
723 (match (self.seconds.get(), Second::per_t::<i64>(Minute)) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute)))
724 .rem_euclid(Minute::per_t(Hour)) as u8
725 }
726
727 #[inline]
734 pub const fn second(self) -> u8 {
735 self.seconds.get().rem_euclid(Second::per_t(Minute)) as u8
736 }
737
738 #[inline]
745 pub const fn millisecond(self) -> u16 {
746 (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
747 }
748
749 #[inline]
756 pub const fn microsecond(self) -> u32 {
757 self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)
758 }
759
760 #[inline]
770 pub const fn nanosecond(self) -> u32 {
771 self.nanoseconds.get()
772 }
773
774 #[inline]
777 const fn add(self, duration: SignedDuration) -> Result<Self, Overflow> {
778 let (second_adj, nanoseconds) = if duration.is_negative() {
779 let nanos = self.nanoseconds.get() as i32 + duration.subsec_nanoseconds();
780 if nanos < 0 {
781 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
782 } else {
783 (0, nanos as u32)
784 }
785 } else {
786 let nanos = self.nanoseconds.get() + duration.subsec_nanoseconds() as u32;
787 if nanos >= Nanosecond::per_t(Second) {
788 (1, nanos - Nanosecond::per_t::<u32>(Second))
789 } else {
790 (0, nanos)
791 }
792 };
793
794 let seconds = match self.seconds.get().checked_add(duration.whole_seconds()) {
795 Some(seconds) => seconds,
796 None if duration.is_negative() => return Err(Overflow::Negative),
797 None => return Err(Overflow::Positive),
798 };
799 let seconds = match seconds.checked_add(second_adj) {
800 Some(seconds) => seconds,
801 None if second_adj < 0 => return Err(Overflow::Negative),
802 None => return Err(Overflow::Positive),
803 };
804
805 if seconds < Seconds::MIN.get() {
807 return Err(Overflow::Negative);
808 } else if seconds > Seconds::MAX.get() {
809 return Err(Overflow::Positive);
810 }
811
812 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
814 }
815
816 #[inline]
819 const fn sub(self, duration: SignedDuration) -> Result<Self, Overflow> {
820 let nanos = self.nanoseconds.get() as i32 - duration.subsec_nanoseconds();
821 let (second_adj, nanoseconds) = if duration.is_negative() {
822 if nanos >= Nanosecond::per_t::<i32>(Second) {
823 (1, (nanos - Nanosecond::per_t::<i32>(Second)) as u32)
824 } else if nanos < 0 {
825 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
826 } else {
827 (0, nanos as u32)
828 }
829 } else {
830 if nanos < 0 {
831 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
832 } else {
833 (0, nanos as u32)
834 }
835 };
836
837 let seconds = match self.seconds.get().checked_sub(duration.whole_seconds()) {
838 Some(seconds) => seconds,
839 None if duration.is_negative() => return Err(Overflow::Positive),
840 None => return Err(Overflow::Negative),
841 };
842 let seconds = match seconds.checked_add(second_adj) {
843 Some(seconds) => seconds,
844 None if second_adj < 0 => return Err(Overflow::Negative),
845 None => return Err(Overflow::Positive),
846 };
847
848 if seconds < Seconds::MIN.get() {
850 return Err(Overflow::Negative);
851 } else if seconds > Seconds::MAX.get() {
852 return Err(Overflow::Positive);
853 }
854
855 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
857 }
858
859 #[inline]
862 const fn add_std(self, duration: StdDuration) -> Result<Self, Overflow> {
863 let Some(mut seconds) = self.seconds.get().checked_add_unsigned(duration.as_secs()) else {
864 return Err(Overflow::Positive);
865 };
866 let mut nanoseconds = self.nanoseconds.get() + duration.subsec_nanos();
867
868 if nanoseconds >= Nanosecond::per_t(Second) {
869 nanoseconds -= Nanosecond::per_t::<u32>(Second);
870 let Some(new_seconds) = seconds.checked_add(1) else {
871 return Err(Overflow::Positive);
872 };
873 seconds = new_seconds;
874 }
875
876 if seconds < Seconds::MIN.get() {
878 return Err(Overflow::Negative);
879 } else if seconds > Seconds::MAX.get() {
880 return Err(Overflow::Positive);
881 }
882
883 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
885 }
886
887 #[inline]
890 const fn sub_std(self, duration: StdDuration) -> Result<Self, Overflow> {
891 let Some(mut seconds) = self.seconds.get().checked_sub_unsigned(duration.as_secs()) else {
892 return Err(Overflow::Negative);
893 };
894 let mut nanoseconds = self.nanoseconds.get() as i32 - duration.subsec_nanos() as i32;
895
896 if nanoseconds < 0 {
897 nanoseconds += Nanosecond::per_t::<i32>(Second);
898 let Some(new_seconds) = seconds.checked_sub(1) else {
899 return Err(Overflow::Negative);
900 };
901 seconds = new_seconds;
902 }
903
904 if seconds < Seconds::MIN.get() {
906 return Err(Overflow::Negative);
907 } else if seconds > Seconds::MAX.get() {
908 return Err(Overflow::Positive);
909 }
910
911 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds as u32) })
913 }
914
915 #[inline]
930 pub const fn checked_add(self, duration: SignedDuration) -> Option<Self> {
931 match self.add(duration) {
932 Ok(timestamp) => Some(timestamp),
933 Err(Overflow::Positive | Overflow::Negative) => None,
934 }
935 }
936
937 #[inline]
952 pub const fn checked_sub(self, duration: SignedDuration) -> Option<Self> {
953 match self.sub(duration) {
954 Ok(timestamp) => Some(timestamp),
955 Err(Overflow::Positive | Overflow::Negative) => None,
956 }
957 }
958
959 #[inline]
975 pub const fn saturating_add(self, duration: SignedDuration) -> Self {
976 match self.add(duration) {
977 Ok(timestamp) => timestamp,
978 Err(Overflow::Positive) => Self::MAX,
979 Err(Overflow::Negative) => Self::MIN,
980 }
981 }
982
983 #[inline]
999 pub const fn saturating_sub(self, duration: SignedDuration) -> Self {
1000 match self.sub(duration) {
1001 Ok(timestamp) => timestamp,
1002 Err(Overflow::Positive) => Self::MAX,
1003 Err(Overflow::Negative) => Self::MIN,
1004 }
1005 }
1006}
1007
1008impl Timestamp {
1010 #[inline]
1020 #[must_use = "This method does not mutate the original `Timestamp`."]
1021 pub const fn replace_time(self, time: Time) -> Self {
1022 let seconds_since_midnight = time.hour() as i64 * Second::per_t::<i64>(Hour)
1023 + time.minute() as i64 * Second::per_t::<i64>(Minute)
1024 + time.second() as i64;
1025 let seconds = match (self.seconds.get(), Second::per_t::<i64>(Day)) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(self.seconds.get(), Second::per_t::<i64>(Day))
1026 * Second::per_t::<i64>(Day)
1027 + seconds_since_midnight;
1028 unsafe { Self::__new_unchecked(seconds, time.nanosecond()) }
1032 }
1033
1034 #[inline]
1044 #[must_use = "This method does not mutate the original `Timestamp`."]
1045 pub const fn replace_date(mut self, date: Date) -> Self {
1046 let seconds_after_midnight = self.seconds.get().rem_euclid(Second::per_t(Day));
1047 let seconds = (date.to_julian_day() as i64
1048 - UtcDateTime::UNIX_EPOCH.to_julian_day() as i64)
1049 * Second::per_t::<i64>(Day)
1050 + seconds_after_midnight;
1051 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1054 self
1055 }
1056
1057 #[inline]
1070 #[must_use = "This method does not mutate the original `Timestamp`."]
1071 pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1072 let date = match self.date().replace_year(year) {
Ok(value) => value,
Err(error) => { crate::hint::cold_path(); return Err(error); }
}const_try!(self.date().replace_year(year));
1073 Ok(self.replace_date(date))
1074 }
1075
1076 #[inline]
1093 #[must_use = "This method does not mutate the original `Timestamp`."]
1094 pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1095 let date = match self.date().replace_month(month) {
Ok(value) => value,
Err(error) => { crate::hint::cold_path(); return Err(error); }
}const_try!(self.date().replace_month(month));
1096 Ok(self.replace_date(date))
1097 }
1098
1099 #[inline]
1111 #[must_use = "This method does not mutate the original `Timestamp`."]
1112 pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1113 let date = match self.date().replace_day(day) {
Ok(value) => value,
Err(error) => { crate::hint::cold_path(); return Err(error); }
}const_try!(self.date().replace_day(day));
1114 Ok(self.replace_date(date))
1115 }
1116
1117 #[inline]
1129 #[must_use = "This method does not mutate the original `Timestamp`."]
1130 pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1131 let date = match self.date().replace_ordinal(ordinal) {
Ok(value) => value,
Err(error) => { crate::hint::cold_path(); return Err(error); }
}const_try!(self.date().replace_ordinal(ordinal));
1132 Ok(self.replace_date(date))
1133 }
1134
1135 #[inline]
1146 #[must_use = "This method does not mutate the original `Timestamp`."]
1147 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
1148 match <ru8<0, 23>>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
};ensure_ranged!(ru8<0, 23>: hour);
1149 let seconds = match (self.seconds.get(), Second::per_t::<i64>(Day)) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(self.seconds.get(), Second::per_t::<i64>(Day))
1150 * Second::per_t::<i64>(Day)
1151 + hour as i64 * Second::per_t::<i64>(Hour)
1152 + self.minute() as i64 * Second::per_t::<i64>(Minute)
1153 + self.second() as i64;
1154 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1156 Ok(self)
1157 }
1158
1159 #[inline]
1170 #[must_use = "This method does not mutate the original `Timestamp`."]
1171 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
1172 match <ru8<0, 59>>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
};ensure_ranged!(ru8<0, 59>: minute);
1173 let seconds = match (self.seconds.get(), Second::per_t::<i64>(Hour)) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(self.seconds.get(), Second::per_t::<i64>(Hour))
1174 * Second::per_t::<i64>(Hour)
1175 + minute as i64 * Second::per_t::<i64>(Minute)
1176 + self.second() as i64;
1177 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1179 Ok(self)
1180 }
1181
1182 #[inline]
1193 #[must_use = "This method does not mutate the original `Timestamp`."]
1194 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
1195 match <ru8<0, 59>>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
};ensure_ranged!(ru8<0, 59>: second);
1196 let seconds = match (self.seconds.get(), Second::per_t::<i64>(Minute)) {
(this, rhs) => {
let d = this / rhs;
let r = this % rhs;
let correction = (this ^ rhs) >> (size_of_val(&this) * 8 - 1);
if r != 0 { d + correction } else { d }
}
}div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute))
1197 * Second::per_t::<i64>(Minute)
1198 + second as i64;
1199 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1201 Ok(self)
1202 }
1203
1204 #[inline]
1219 #[must_use = "This method does not mutate the original `Timestamp`."]
1220 pub const fn replace_millisecond(
1221 self,
1222 millisecond: u16,
1223 ) -> Result<Self, error::ComponentRange> {
1224 let nanos =
1225 match (millisecond as u32).checked_mul(Nanosecond::per_t::<u32>(Millisecond))
{
Some(val) =>
match <Nanoseconds>::new(val) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("millisecond"));
}
},
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("millisecond"));
}
}ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
1226 Ok(self.replace_nanosecond_ranged(nanos))
1227 }
1228
1229 #[inline]
1244 #[must_use = "This method does not mutate the original `Timestamp`."]
1245 pub const fn replace_microsecond(
1246 self,
1247 microsecond: u32,
1248 ) -> Result<Self, error::ComponentRange> {
1249 let nanos =
1250 match (microsecond).checked_mul(Nanosecond::per_t::<u32>(Microsecond)) {
Some(val) =>
match <Nanoseconds>::new(val) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("microsecond"));
}
},
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("microsecond"));
}
}ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
1251 Ok(self.replace_nanosecond_ranged(nanos))
1252 }
1253
1254 #[inline]
1269 #[must_use = "This method does not mutate the original `Timestamp`."]
1270 pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1271 let nanos = match <Nanoseconds>::new(nanosecond) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("nanosecond"));
}
}ensure_ranged!(Nanoseconds: nanosecond);
1272 Ok(self.replace_nanosecond_ranged(nanos))
1273 }
1274
1275 #[inline]
1278 const fn replace_nanosecond_ranged(self, new_nanos: Nanoseconds) -> Self {
1279 let (seconds, nanoseconds) = self.as_parts_ranged();
1280
1281 if seconds.get() >= 0 || nanoseconds.get() == 0 {
1282 Self::new_ranged(seconds, new_nanos)
1283 } else if new_nanos.get() == 0 {
1284 Self::new_ranged(unsafe { seconds.unchecked_add(1) }, new_nanos)
1288 } else {
1289 Self::new_ranged(seconds, unsafe {
1292 Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - new_nanos.get())
1293 })
1294 }
1295 }
1296}
1297
1298#[cfg(feature = "formatting")]
1299impl Timestamp {
1300 #[inline]
1302 pub fn format_into(
1303 self,
1304 output: &mut (impl io::Write + ?Sized),
1305 format: &(impl Formattable + ?Sized),
1306 ) -> Result<usize, error::Format> {
1307 format.format_into(output, &self, &mut Default::default(), PrivateMethod)
1308 }
1309
1310 #[inline]
1319 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1320 format.format(&self, &mut Default::default(), PrivateMethod)
1321 }
1322}
1323
1324#[cfg(feature = "parsing")]
1325impl Timestamp {
1326 #[inline]
1340 pub fn parse(
1341 input: &str,
1342 description: &(impl Parsable + ?Sized),
1343 ) -> Result<Self, error::Parse> {
1344 description.parse_timestamp(input.as_bytes(), None, PrivateMethod)
1345 }
1346
1347 #[inline]
1363 pub fn parse_with_defaults(
1364 input: &[u8],
1365 description: &(impl Parsable + ?Sized),
1366 defaults: Parsed,
1367 ) -> Result<Self, error::Parse> {
1368 description.parse_timestamp(input, Some(defaults), PrivateMethod)
1369 }
1370}
1371
1372impl Timestamp {
1373 const DISPLAY_BUFFER_SIZE: usize = 25;
1376
1377 pub(crate) fn fmt_into_buffer(
1379 self,
1380 buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
1381 ) -> usize {
1382 let mut idx = 0;
1383
1384 let mut second = self.seconds.get();
1385 let mut nanosecond = self.nanoseconds;
1386
1387 if second < 0 {
1388 buf[idx] = MaybeUninit::new(b'-');
1389 idx += 1;
1390
1391 second = -second;
1392
1393 if nanosecond != Nanoseconds::new_static::<0>() {
1394 second -= 1;
1395 nanosecond = unsafe {
1399 Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - nanosecond.get())
1400 };
1401 }
1402 }
1403
1404 let seconds_str = u64_pad_none(second.cast_unsigned());
1405 let seconds_len = seconds_str.len();
1406 unsafe {
1408 seconds_str
1409 .as_ptr()
1410 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), seconds_len);
1411 }
1412 idx += seconds_len;
1413
1414 if nanosecond != Nanoseconds::new_static::<0>() {
1415 buf[idx] = MaybeUninit::new(b'.');
1416 idx += 1;
1417
1418 let subsecond = truncated_subsecond_from_nanos(nanosecond);
1419 unsafe {
1421 subsecond
1422 .as_ptr()
1423 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len());
1424 }
1425 idx += subsecond.len();
1426 }
1427
1428 idx
1429 }
1430}
1431
1432impl fmt::Display for Timestamp {
1433 #[inline]
1434 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1435 let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1436 let len = self.fmt_into_buffer(&mut buf);
1437 let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1439 f.pad(s)
1440 }
1441}
1442
1443impl fmt::Debug for Timestamp {
1444 #[inline]
1445 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1446 fmt::Display::fmt(self, f)
1447 }
1448}
1449
1450impl Add<SignedDuration> for Timestamp {
1451 type Output = Self;
1452
1453 #[inline]
1457 #[track_caller]
1458 fn add(self, rhs: SignedDuration) -> Self::Output {
1459 self.checked_add(rhs)
1460 .expect("resulting value is out of range")
1461 }
1462}
1463
1464impl Add<StdDuration> for Timestamp {
1465 type Output = Self;
1466
1467 #[inline]
1471 #[track_caller]
1472 fn add(self, rhs: StdDuration) -> Self::Output {
1473 self.add_std(rhs).expect("resulting value is out of range")
1474 }
1475}
1476
1477impl AddAssign<SignedDuration> for Timestamp {
1478 #[inline]
1482 #[track_caller]
1483 fn add_assign(&mut self, rhs: SignedDuration) {
1484 *self = *self + rhs;
1485 }
1486}
1487
1488impl AddAssign<StdDuration> for Timestamp {
1489 #[inline]
1493 #[track_caller]
1494 fn add_assign(&mut self, rhs: StdDuration) {
1495 *self = *self + rhs;
1496 }
1497}
1498
1499impl Sub<SignedDuration> for Timestamp {
1500 type Output = Self;
1501
1502 #[inline]
1506 #[track_caller]
1507 fn sub(self, rhs: SignedDuration) -> Self::Output {
1508 self.checked_sub(rhs)
1509 .expect("resulting value is out of range")
1510 }
1511}
1512
1513impl Sub<StdDuration> for Timestamp {
1514 type Output = Self;
1515
1516 #[inline]
1520 #[track_caller]
1521 fn sub(self, rhs: StdDuration) -> Self::Output {
1522 self.sub_std(rhs).expect("resulting value is out of range")
1523 }
1524}
1525
1526impl SubAssign<SignedDuration> for Timestamp {
1527 #[inline]
1531 #[track_caller]
1532 fn sub_assign(&mut self, rhs: SignedDuration) {
1533 *self = *self - rhs;
1534 }
1535}
1536
1537impl SubAssign<StdDuration> for Timestamp {
1538 #[inline]
1542 #[track_caller]
1543 fn sub_assign(&mut self, rhs: StdDuration) {
1544 *self = *self - rhs;
1545 }
1546}
1547
1548impl Sub for Timestamp {
1549 type Output = SignedDuration;
1550
1551 #[inline]
1552 fn sub(self, rhs: Self) -> Self::Output {
1553 let seconds = self.seconds.get() - rhs.seconds.get();
1554 let nanoseconds = self.nanoseconds.get() as i32 - rhs.nanoseconds.get() as i32;
1555
1556 if nanoseconds < 0 {
1557 SignedDuration::new(seconds - 1, nanoseconds + Nanosecond::per_t::<i32>(Second))
1558 } else {
1559 SignedDuration::new(seconds, nanoseconds)
1560 }
1561 }
1562}