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, Duration, Month, OffsetDateTime, Time, UtcDateTime, UtcOffset, Weekday, error, util,
30};
31
32type Seconds = ri64<{ UtcDateTime::MIN.unix_timestamp() }, { UtcDateTime::MAX.unix_timestamp() }>;
33type Nanoseconds = ru32<0, 999_999_999>;
34
35const _: () = {
38 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());
39 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());
40};
41
42#[repr(u32)]
45#[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)]
46enum Padding {
47 #[allow(clippy::missing_docs_in_private_items)]
48 Optimize,
49}
50
51#[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)]
56#[cfg_attr(not(docsrs), repr(C))]
57pub struct Timestamp {
58 #[cfg(target_endian = "big")]
59 seconds: Seconds,
60 #[cfg(target_endian = "big")]
61 nanoseconds: Nanoseconds,
62 #[cfg(target_endian = "big")]
63 padding: Padding,
64
65 #[cfg(target_endian = "little")]
66 padding: Padding,
67 #[cfg(target_endian = "little")]
68 nanoseconds: Nanoseconds,
69 #[cfg(target_endian = "little")]
70 seconds: Seconds,
71}
72
73impl Hash for Timestamp {
74 #[inline]
75 fn hash<H: Hasher>(&self, state: &mut H) {
76 state.write_i128(self.as_i128());
77 }
78}
79
80impl PartialEq for Timestamp {
81 #[inline]
82 fn eq(&self, other: &Self) -> bool {
83 self.as_i128() == other.as_i128()
84 }
85}
86
87impl PartialOrd for Timestamp {
88 #[inline]
89 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
90 Some(self.cmp(other))
91 }
92}
93
94impl Ord for Timestamp {
95 #[inline]
96 fn cmp(&self, other: &Self) -> Ordering {
97 self.as_i128().cmp(&other.as_i128())
98 }
99}
100
101impl Timestamp {
102 #[inline]
103 const fn as_i128(self) -> i128 {
104 unsafe { core::mem::transmute(self) }
108 }
109
110 pub const UNIX_EPOCH: Self =
112 Self::new_ranged(Seconds::new_static::<0>(), Nanoseconds::new_static::<0>());
113
114 pub const MIN: Self = Self::new_ranged(Seconds::MIN, Nanoseconds::MIN);
119
120 pub const MAX: Self = Self::new_ranged(Seconds::MAX, Nanoseconds::MAX);
125
126 #[cfg(feature = "std")]
133 #[inline]
134 pub fn now() -> Self {
135 SystemTime::now().into()
136 }
137
138 #[doc(hidden)]
145 #[inline]
146 #[track_caller]
147 pub const unsafe fn __new_unchecked(seconds: i64, nanoseconds: u32) -> Self {
148 unsafe {
150 Self::new_ranged(
151 Seconds::new_unchecked(seconds),
152 Nanoseconds::new_unchecked(nanoseconds),
153 )
154 }
155 }
156
157 #[inline]
160 pub(crate) const fn new_ranged(seconds: Seconds, nanoseconds: Nanoseconds) -> Self {
161 Self {
162 seconds,
163 nanoseconds,
164 padding: Padding::Optimize,
165 }
166 }
167
168 #[inline]
177 pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Self, error::ComponentRange> {
178 Ok(Self::new_ranged(
179 match <Seconds>::new(seconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("seconds"));
}
}ensure_ranged!(Seconds: seconds),
180 match <Nanoseconds>::new(nanoseconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("nanoseconds"));
}
}ensure_ranged!(Nanoseconds: nanoseconds),
181 ))
182 }
183
184 #[inline]
193 pub const fn from_seconds(seconds: i64) -> Result<Self, error::ComponentRange> {
194 Ok(Self::new_ranged(
195 match <Seconds>::new(seconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("seconds"));
}
}ensure_ranged!(Seconds: seconds),
196 Nanoseconds::new_static::<0>(),
197 ))
198 }
199
200 #[inline]
209 pub const fn from_milliseconds(milliseconds: i64) -> Result<Self, error::ComponentRange> {
210 const MAX: i64 = Seconds::MAX.get() * Millisecond::per_t::<i64>(Second)
211 + (Nanoseconds::MAX.get() as i64) / Nanosecond::per_t::<i64>(Millisecond);
212 const MIN: i64 = Seconds::MIN.get() * Millisecond::per_t::<i64>(Second)
213 + (Nanoseconds::MIN.get() as i64) / Nanosecond::per_t::<i64>(Millisecond);
214
215 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);
216
217 let mut seconds = milliseconds / Millisecond::per_t::<i64>(Second);
218 let nanoseconds = (milliseconds.rem_euclid(Millisecond::per_t(Second))
219 * Nanosecond::per_t::<i64>(Millisecond)) as u32;
220
221 if milliseconds < 0 && nanoseconds != 0 {
222 seconds -= 1;
223 }
224
225 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
227 }
228
229 #[inline]
238 pub const fn from_microseconds(microseconds: i128) -> Result<Self, error::ComponentRange> {
239 const MAX: i128 = Seconds::MAX.get() as i128 * Microsecond::per_t::<i128>(Second)
240 + (Nanoseconds::MAX.get() as i128) / Nanosecond::per_t::<i128>(Microsecond);
241 const MIN: i128 = Seconds::MIN.get() as i128 * Microsecond::per_t::<i128>(Second)
242 + (Nanoseconds::MIN.get() as i128) / Nanosecond::per_t::<i128>(Microsecond);
243
244 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);
245
246 let mut seconds = (microseconds / Microsecond::per_t::<i128>(Second)) as i64;
247 let nanoseconds = (microseconds.rem_euclid(Microsecond::per_t(Second))
248 * Nanosecond::per_t::<i128>(Microsecond)) as u32;
249
250 if microseconds < 0 && nanoseconds != 0 {
251 seconds -= 1;
252 }
253
254 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
256 }
257
258 #[inline]
267 pub const fn from_nanoseconds(nanoseconds: i128) -> Result<Self, error::ComponentRange> {
268 const MAX: i128 = Seconds::MAX.get() as i128 * Nanosecond::per_t::<i128>(Second)
269 + Nanoseconds::MAX.get() as i128;
270 const MIN: i128 = Seconds::MIN.get() as i128 * Nanosecond::per_t::<i128>(Second)
271 + Nanoseconds::MIN.get() as i128;
272
273 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);
274
275 let input_is_negative = nanoseconds < 0;
276 let mut seconds = (nanoseconds / Nanosecond::per_t::<i128>(Second)) as i64;
277 let nanoseconds = nanoseconds.rem_euclid(Nanosecond::per_t(Second)) as u32;
278
279 if input_is_negative && nanoseconds != 0 {
280 seconds -= 1;
281 }
282
283 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
285 }
286
287 #[inline]
300 pub const fn to_offset(self, offset: UtcOffset) -> OffsetDateTime {
301 self.to_utc().to_offset(offset)
302 }
303
304 #[inline]
316 pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<OffsetDateTime> {
317 self.to_utc().checked_to_offset(offset)
318 }
319
320 #[inline]
327 pub const fn to_utc(self) -> UtcDateTime {
328 let Ok(utc_dt) = UtcDateTime::from_unix_timestamp(self.seconds.get()) else {
329 {
crate::hint::cold_path();
{
::core::panicking::panic_fmt(format_args!("internal error: timestamp was invalid beforehand"));
}
};bug!("timestamp was invalid beforehand");
330 };
331 let Ok(utc_dt) = utc_dt.replace_nanosecond(self.nanoseconds.get()) else {
332 {
crate::hint::cold_path();
{
::core::panicking::panic_fmt(format_args!("internal error: nanosecond was invalid beforehand"));
}
};bug!("nanosecond was invalid beforehand");
333 };
334
335 utc_dt
336 }
337
338 #[inline]
340 pub(crate) const fn as_parts_ranged(self) -> (Seconds, Nanoseconds) {
341 (self.seconds, self.nanoseconds)
342 }
343
344 #[inline]
353 pub const fn as_seconds(self) -> i64 {
354 self.seconds.get()
355 }
356
357 #[inline]
369 pub const fn as_milliseconds(self) -> i64 {
370 self.seconds.get() * Millisecond::per_t::<i64>(Second)
371 + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as i64
372 }
373
374 #[inline]
386 pub const fn as_microseconds(self) -> i128 {
387 self.seconds.get() as i128 * Microsecond::per_t::<i128>(Second)
388 + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)) as i128
389 }
390
391 #[inline]
403 pub const fn as_nanoseconds(self) -> i128 {
404 self.seconds.get() as i128 * Nanosecond::per_t::<i128>(Second)
405 + self.nanoseconds.get() as i128
406 }
407
408 #[inline]
415 pub const fn date(self) -> Date {
416 self.to_utc().date()
417 }
418
419 #[inline]
426 pub const fn time(self) -> Time {
427 let within_day = self.as_seconds().rem_euclid(Second::per_t::<i64>(Day)) as u32;
428
429 let hour = within_day / Second::per_t::<u32>(Hour);
430 let minute =
431 (within_day - hour * Second::per_t::<u32>(Hour)) / Second::per_t::<u32>(Minute);
432 let second =
433 within_day - hour * Second::per_t::<u32>(Hour) - minute * Second::per_t::<u32>(Minute);
434
435 unsafe {
437 Time::__from_hms_nanos_unchecked(
438 hour as u8,
439 minute as u8,
440 second as u8,
441 self.nanosecond(),
442 )
443 }
444 }
445
446 #[inline]
452 const fn year_leap_ordinal(self) -> (i32, bool, u16) {
453 const ERAS: u32 = 5_949;
454 const D_SHIFT: u32 = 146097 * ERAS + 719_528;
455 const Y_SHIFT: u32 = 400 * ERAS;
456
457 const CEN_MUL: u32 = ((4u64 << 47) / 146_097) as u32;
458 const JUL_MUL: u32 = ((4u64 << 40) / 1_461 + 1) as u32;
459 const CEN_CUT: u32 = ((365u64 << 32) / 36_525) as u32;
460
461 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;
462
463 let day = raw_day.cast_unsigned().wrapping_add(D_SHIFT);
464 let c_n = (day as u64 * CEN_MUL as u64) >> 15;
465 let cen = (c_n >> 32) as u32;
466 let cpt = c_n as u32;
467 let ijy = cpt > CEN_CUT || cen.is_multiple_of(4);
468 let jul = day - cen / 4 + cen;
469 let y_n = (jul as u64 * JUL_MUL as u64) >> 8;
470 let yrs = (y_n >> 32) as u32;
471 let ypt = y_n as u32;
472
473 let year = yrs.wrapping_sub(Y_SHIFT).cast_signed();
474 let ordinal = ((ypt as u64 * 1_461) >> 34) as u32 + ijy as u32;
475 let leap = yrs.is_multiple_of(4) & ijy;
476
477 (year, leap, ordinal as u16)
478 }
479
480 #[inline]
487 pub const fn year(self) -> i32 {
488 self.year_leap_ordinal().0
489 }
490
491 #[inline]
499 pub const fn month(self) -> Month {
500 let (_, leap, ordinal) = self.year_leap_ordinal();
501 util::leap_ordinal_to_month_day(leap, ordinal).0
502 }
503
504 #[inline]
513 pub const fn day(self) -> u8 {
514 let (_, leap, ordinal) = self.year_leap_ordinal();
515 util::leap_ordinal_to_month_day(leap, ordinal).1
516 }
517
518 #[inline]
527 pub const fn ordinal(self) -> u16 {
528 self.year_leap_ordinal().2
529 }
530
531 #[inline]
540 pub const fn iso_week(self) -> u8 {
541 self.date().iso_week()
542 }
543
544 #[inline]
553 pub const fn sunday_based_week(self) -> u8 {
554 self.date().sunday_based_week()
555 }
556
557 #[inline]
566 pub const fn monday_based_week(self) -> u8 {
567 self.date().monday_based_week()
568 }
569
570 #[inline]
581 pub const fn to_calendar_date(self) -> (i32, Month, u8) {
582 let (year, leap, ordinal) = self.year_leap_ordinal();
583 let (month, day) = util::leap_ordinal_to_month_day(leap, ordinal);
584 (year, month, day)
585 }
586
587 #[inline]
594 pub const fn to_ordinal_date(self) -> (i32, u16) {
595 let (year, _, ordinal) = self.year_leap_ordinal();
596 (year, ordinal)
597 }
598
599 #[inline]
610 pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
611 self.date().to_iso_week_date()
612 }
613
614 #[inline]
622 pub const fn weekday(self) -> Weekday {
623 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 {
629 0 => Weekday::Monday,
630 1 => Weekday::Tuesday,
631 2 => Weekday::Wednesday,
632 3 => Weekday::Thursday,
633 4 => Weekday::Friday,
634 5 => Weekday::Saturday,
635 6 => Weekday::Sunday,
636 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
637 }
638 }
639
640 #[inline]
647 pub const fn to_julian_day(self) -> i32 {
648 const UNIX_EPOCH_JULIAN_DAY: i32 = Date::UNIX_EPOCH.to_julian_day();
649 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
650 }
651
652 #[inline]
659 pub const fn as_hms(self) -> (u8, u8, u8) {
660 self.time().as_hms()
661 }
662
663 #[inline]
670 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
671 self.time().as_hms_milli()
672 }
673
674 #[inline]
684 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
685 self.time().as_hms_micro()
686 }
687
688 #[inline]
698 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
699 self.time().as_hms_nano()
700 }
701
702 #[inline]
709 pub const fn hour(self) -> u8 {
710 self.time().hour()
711 }
712
713 #[inline]
720 pub const fn minute(self) -> u8 {
721 (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)))
722 .rem_euclid(Minute::per_t(Hour)) as u8
723 }
724
725 #[inline]
732 pub const fn second(self) -> u8 {
733 self.seconds.get().rem_euclid(Second::per_t(Minute)) as u8
734 }
735
736 #[inline]
743 pub const fn millisecond(self) -> u16 {
744 (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
745 }
746
747 #[inline]
754 pub const fn microsecond(self) -> u32 {
755 self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)
756 }
757
758 #[inline]
768 pub const fn nanosecond(self) -> u32 {
769 self.nanoseconds.get()
770 }
771
772 #[inline]
775 const fn add(self, duration: Duration) -> Result<Self, Overflow> {
776 let (second_adj, nanoseconds) = if duration.is_negative() {
777 let nanos = self.nanoseconds.get() as i32 + duration.subsec_nanoseconds();
778 if nanos < 0 {
779 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
780 } else {
781 (0, nanos as u32)
782 }
783 } else {
784 let nanos = self.nanoseconds.get() + duration.subsec_nanoseconds() as u32;
785 if nanos >= Nanosecond::per_t(Second) {
786 (1, nanos - Nanosecond::per_t::<u32>(Second))
787 } else {
788 (0, nanos)
789 }
790 };
791
792 let seconds = match self.seconds.get().checked_add(duration.whole_seconds()) {
793 Some(seconds) => seconds,
794 None if duration.is_negative() => return Err(Overflow::Negative),
795 None => return Err(Overflow::Positive),
796 };
797 let seconds = match seconds.checked_add(second_adj) {
798 Some(seconds) => seconds,
799 None if second_adj < 0 => return Err(Overflow::Negative),
800 None => return Err(Overflow::Positive),
801 };
802
803 if seconds < Seconds::MIN.get() {
805 return Err(Overflow::Negative);
806 } else if seconds > Seconds::MAX.get() {
807 return Err(Overflow::Positive);
808 }
809
810 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
812 }
813
814 #[inline]
817 const fn sub(self, duration: Duration) -> Result<Self, Overflow> {
818 let nanos = self.nanoseconds.get() as i32 - duration.subsec_nanoseconds();
819 let (second_adj, nanoseconds) = if duration.is_negative() {
820 if nanos >= Nanosecond::per_t::<i32>(Second) {
821 (1, (nanos - Nanosecond::per_t::<i32>(Second)) as u32)
822 } else if nanos < 0 {
823 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
824 } else {
825 (0, nanos as u32)
826 }
827 } else {
828 if nanos < 0 {
829 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
830 } else {
831 (0, nanos as u32)
832 }
833 };
834
835 let seconds = match self.seconds.get().checked_sub(duration.whole_seconds()) {
836 Some(seconds) => seconds,
837 None if duration.is_negative() => return Err(Overflow::Positive),
838 None => return Err(Overflow::Negative),
839 };
840 let seconds = match seconds.checked_add(second_adj) {
841 Some(seconds) => seconds,
842 None if second_adj < 0 => return Err(Overflow::Negative),
843 None => return Err(Overflow::Positive),
844 };
845
846 if seconds < Seconds::MIN.get() {
848 return Err(Overflow::Negative);
849 } else if seconds > Seconds::MAX.get() {
850 return Err(Overflow::Positive);
851 }
852
853 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
855 }
856
857 #[inline]
860 const fn add_std(self, duration: StdDuration) -> Result<Self, Overflow> {
861 let Some(mut seconds) = self.seconds.get().checked_add_unsigned(duration.as_secs()) else {
862 return Err(Overflow::Positive);
863 };
864 let mut nanoseconds = self.nanoseconds.get() + duration.subsec_nanos();
865
866 if nanoseconds >= Nanosecond::per_t(Second) {
867 nanoseconds -= Nanosecond::per_t::<u32>(Second);
868 let Some(new_seconds) = seconds.checked_add(1) else {
869 return Err(Overflow::Positive);
870 };
871 seconds = new_seconds;
872 }
873
874 if seconds < Seconds::MIN.get() {
876 return Err(Overflow::Negative);
877 } else if seconds > Seconds::MAX.get() {
878 return Err(Overflow::Positive);
879 }
880
881 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
883 }
884
885 #[inline]
888 const fn sub_std(self, duration: StdDuration) -> Result<Self, Overflow> {
889 let Some(mut seconds) = self.seconds.get().checked_sub_unsigned(duration.as_secs()) else {
890 return Err(Overflow::Negative);
891 };
892 let mut nanoseconds = self.nanoseconds.get() as i32 - duration.subsec_nanos() as i32;
893
894 if nanoseconds < 0 {
895 nanoseconds += Nanosecond::per_t::<i32>(Second);
896 let Some(new_seconds) = seconds.checked_sub(1) else {
897 return Err(Overflow::Negative);
898 };
899 seconds = new_seconds;
900 }
901
902 if seconds < Seconds::MIN.get() {
904 return Err(Overflow::Negative);
905 } else if seconds > Seconds::MAX.get() {
906 return Err(Overflow::Positive);
907 }
908
909 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds as u32) })
911 }
912
913 #[inline]
928 pub const fn checked_add(self, duration: Duration) -> Option<Self> {
929 match self.add(duration) {
930 Ok(timestamp) => Some(timestamp),
931 Err(Overflow::Positive | Overflow::Negative) => None,
932 }
933 }
934
935 #[inline]
950 pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
951 match self.sub(duration) {
952 Ok(timestamp) => Some(timestamp),
953 Err(Overflow::Positive | Overflow::Negative) => None,
954 }
955 }
956
957 #[inline]
973 pub const fn saturating_add(self, duration: Duration) -> Self {
974 match self.add(duration) {
975 Ok(timestamp) => timestamp,
976 Err(Overflow::Positive) => Self::MAX,
977 Err(Overflow::Negative) => Self::MIN,
978 }
979 }
980
981 #[inline]
997 pub const fn saturating_sub(self, duration: Duration) -> Self {
998 match self.sub(duration) {
999 Ok(timestamp) => timestamp,
1000 Err(Overflow::Positive) => Self::MAX,
1001 Err(Overflow::Negative) => Self::MIN,
1002 }
1003 }
1004}
1005
1006impl Timestamp {
1008 #[inline]
1018 #[must_use = "This method does not mutate the original `Timestamp`."]
1019 pub const fn replace_time(self, time: Time) -> Self {
1020 let seconds_since_midnight = time.hour() as i64 * Second::per_t::<i64>(Hour)
1021 + time.minute() as i64 * Second::per_t::<i64>(Minute)
1022 + time.second() as i64;
1023 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))
1024 * Second::per_t::<i64>(Day)
1025 + seconds_since_midnight;
1026 unsafe { Self::__new_unchecked(seconds, time.nanosecond()) }
1030 }
1031
1032 #[inline]
1042 #[must_use = "This method does not mutate the original `Timestamp`."]
1043 pub const fn replace_date(mut self, date: Date) -> Self {
1044 let seconds_after_midnight = self.seconds.get().rem_euclid(Second::per_t(Day));
1045 let seconds = (date.to_julian_day() as i64
1046 - UtcDateTime::UNIX_EPOCH.to_julian_day() as i64)
1047 * Second::per_t::<i64>(Day)
1048 + seconds_after_midnight;
1049 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1052 self
1053 }
1054
1055 #[inline]
1068 #[must_use = "This method does not mutate the original `Timestamp`."]
1069 pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1070 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));
1071 Ok(self.replace_date(date))
1072 }
1073
1074 #[inline]
1091 #[must_use = "This method does not mutate the original `Timestamp`."]
1092 pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1093 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));
1094 Ok(self.replace_date(date))
1095 }
1096
1097 #[inline]
1109 #[must_use = "This method does not mutate the original `Timestamp`."]
1110 pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1111 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));
1112 Ok(self.replace_date(date))
1113 }
1114
1115 #[inline]
1127 #[must_use = "This method does not mutate the original `Timestamp`."]
1128 pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1129 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));
1130 Ok(self.replace_date(date))
1131 }
1132
1133 #[inline]
1144 #[must_use = "This method does not mutate the original `Timestamp`."]
1145 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
1146 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);
1147 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))
1148 * Second::per_t::<i64>(Day)
1149 + hour as i64 * Second::per_t::<i64>(Hour)
1150 + self.minute() as i64 * Second::per_t::<i64>(Minute)
1151 + self.second() as i64;
1152 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1154 Ok(self)
1155 }
1156
1157 #[inline]
1168 #[must_use = "This method does not mutate the original `Timestamp`."]
1169 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
1170 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);
1171 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))
1172 * Second::per_t::<i64>(Hour)
1173 + minute as i64 * Second::per_t::<i64>(Minute)
1174 + self.second() as i64;
1175 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1177 Ok(self)
1178 }
1179
1180 #[inline]
1191 #[must_use = "This method does not mutate the original `Timestamp`."]
1192 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
1193 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);
1194 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))
1195 * Second::per_t::<i64>(Minute)
1196 + second as i64;
1197 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1199 Ok(self)
1200 }
1201
1202 #[inline]
1217 #[must_use = "This method does not mutate the original `Timestamp`."]
1218 pub const fn replace_millisecond(
1219 self,
1220 millisecond: u16,
1221 ) -> Result<Self, error::ComponentRange> {
1222 let nanos =
1223 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));
1224 Ok(self.replace_nanosecond_ranged(nanos))
1225 }
1226
1227 #[inline]
1242 #[must_use = "This method does not mutate the original `Timestamp`."]
1243 pub const fn replace_microsecond(
1244 self,
1245 microsecond: u32,
1246 ) -> Result<Self, error::ComponentRange> {
1247 let nanos =
1248 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));
1249 Ok(self.replace_nanosecond_ranged(nanos))
1250 }
1251
1252 #[inline]
1267 #[must_use = "This method does not mutate the original `Timestamp`."]
1268 pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1269 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);
1270 Ok(self.replace_nanosecond_ranged(nanos))
1271 }
1272
1273 #[inline]
1276 const fn replace_nanosecond_ranged(self, new_nanos: Nanoseconds) -> Self {
1277 let (seconds, nanoseconds) = self.as_parts_ranged();
1278
1279 if seconds.get() >= 0 || nanoseconds.get() == 0 {
1280 Self::new_ranged(seconds, new_nanos)
1281 } else if new_nanos.get() == 0 {
1282 Self::new_ranged(unsafe { seconds.unchecked_add(1) }, new_nanos)
1286 } else {
1287 Self::new_ranged(seconds, unsafe {
1290 Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - new_nanos.get())
1291 })
1292 }
1293 }
1294}
1295
1296#[cfg(feature = "formatting")]
1297impl Timestamp {
1298 #[inline]
1300 pub fn format_into(
1301 self,
1302 output: &mut (impl io::Write + ?Sized),
1303 format: &(impl Formattable + ?Sized),
1304 ) -> Result<usize, error::Format> {
1305 format.format_into(output, &self, &mut Default::default(), PrivateMethod)
1306 }
1307
1308 #[inline]
1317 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1318 format.format(&self, &mut Default::default(), PrivateMethod)
1319 }
1320}
1321
1322#[cfg(feature = "parsing")]
1323impl Timestamp {
1324 #[inline]
1338 pub fn parse(
1339 input: &str,
1340 description: &(impl Parsable + ?Sized),
1341 ) -> Result<Self, error::Parse> {
1342 description.parse_timestamp(input.as_bytes(), None, PrivateMethod)
1343 }
1344
1345 #[inline]
1361 pub fn parse_with_defaults(
1362 input: &[u8],
1363 description: &(impl Parsable + ?Sized),
1364 defaults: Parsed,
1365 ) -> Result<Self, error::Parse> {
1366 description.parse_timestamp(input, Some(defaults), PrivateMethod)
1367 }
1368}
1369
1370impl Timestamp {
1371 const DISPLAY_BUFFER_SIZE: usize = 25;
1374
1375 pub(crate) fn fmt_into_buffer(
1377 self,
1378 buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
1379 ) -> usize {
1380 let mut idx = 0;
1381
1382 let mut second = self.seconds.get();
1383 let mut nanosecond = self.nanoseconds;
1384
1385 if second < 0 {
1386 buf[idx] = MaybeUninit::new(b'-');
1387 idx += 1;
1388
1389 second = -second;
1390
1391 if nanosecond != Nanoseconds::new_static::<0>() {
1392 second -= 1;
1393 nanosecond = unsafe {
1397 Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - nanosecond.get())
1398 };
1399 }
1400 }
1401
1402 let seconds_str = u64_pad_none(second.cast_unsigned());
1403 let seconds_len = seconds_str.len();
1404 unsafe {
1406 seconds_str
1407 .as_ptr()
1408 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), seconds_len);
1409 }
1410 idx += seconds_len;
1411
1412 if nanosecond != Nanoseconds::new_static::<0>() {
1413 buf[idx] = MaybeUninit::new(b'.');
1414 idx += 1;
1415
1416 let subsecond = truncated_subsecond_from_nanos(nanosecond);
1417 unsafe {
1419 subsecond
1420 .as_ptr()
1421 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len());
1422 }
1423 idx += subsecond.len();
1424 }
1425
1426 idx
1427 }
1428}
1429
1430impl fmt::Display for Timestamp {
1431 #[inline]
1432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1433 let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1434 let len = self.fmt_into_buffer(&mut buf);
1435 let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1437 f.pad(s)
1438 }
1439}
1440
1441impl fmt::Debug for Timestamp {
1442 #[inline]
1443 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1444 fmt::Display::fmt(self, f)
1445 }
1446}
1447
1448impl Add<Duration> for Timestamp {
1449 type Output = Self;
1450
1451 #[inline]
1455 #[track_caller]
1456 fn add(self, rhs: Duration) -> Self::Output {
1457 self.checked_add(rhs)
1458 .expect("resulting value is out of range")
1459 }
1460}
1461
1462impl Add<StdDuration> for Timestamp {
1463 type Output = Self;
1464
1465 #[inline]
1469 #[track_caller]
1470 fn add(self, rhs: StdDuration) -> Self::Output {
1471 self.add_std(rhs).expect("resulting value is out of range")
1472 }
1473}
1474
1475impl AddAssign<Duration> for Timestamp {
1476 #[inline]
1480 #[track_caller]
1481 fn add_assign(&mut self, rhs: Duration) {
1482 *self = *self + rhs;
1483 }
1484}
1485
1486impl AddAssign<StdDuration> for Timestamp {
1487 #[inline]
1491 #[track_caller]
1492 fn add_assign(&mut self, rhs: StdDuration) {
1493 *self = *self + rhs;
1494 }
1495}
1496
1497impl Sub<Duration> for Timestamp {
1498 type Output = Self;
1499
1500 #[inline]
1504 #[track_caller]
1505 fn sub(self, rhs: Duration) -> Self::Output {
1506 self.checked_sub(rhs)
1507 .expect("resulting value is out of range")
1508 }
1509}
1510
1511impl Sub<StdDuration> for Timestamp {
1512 type Output = Self;
1513
1514 #[inline]
1518 #[track_caller]
1519 fn sub(self, rhs: StdDuration) -> Self::Output {
1520 self.sub_std(rhs).expect("resulting value is out of range")
1521 }
1522}
1523
1524impl SubAssign<Duration> for Timestamp {
1525 #[inline]
1529 #[track_caller]
1530 fn sub_assign(&mut self, rhs: Duration) {
1531 *self = *self - rhs;
1532 }
1533}
1534
1535impl SubAssign<StdDuration> for Timestamp {
1536 #[inline]
1540 #[track_caller]
1541 fn sub_assign(&mut self, rhs: StdDuration) {
1542 *self = *self - rhs;
1543 }
1544}
1545
1546impl Sub for Timestamp {
1547 type Output = Duration;
1548
1549 #[inline]
1550 fn sub(self, rhs: Self) -> Self::Output {
1551 let seconds = self.seconds.get() - rhs.seconds.get();
1552 let nanoseconds = self.nanoseconds.get() as i32 - rhs.nanoseconds.get() as i32;
1553
1554 if nanoseconds < 0 {
1555 Duration::new(seconds - 1, nanoseconds + Nanosecond::per_t::<i32>(Second))
1556 } else {
1557 Duration::new(seconds, nanoseconds)
1558 }
1559 }
1560}