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(feature = "formatting")]
19use crate::formatting::Formattable;
20use crate::internal_macros::{bug, const_try, div_floor, ensure_ranged};
21use crate::num_fmt::{str_from_raw_parts, truncated_subsecond_from_nanos, u64_pad_none};
22#[cfg(feature = "parsing")]
23use crate::parsing::Parsable;
24use crate::unit::*;
25use crate::util::Overflow;
26use crate::{
27 Date, Duration, Month, OffsetDateTime, Time, UtcDateTime, UtcOffset, Weekday, error, util,
28};
29
30type Seconds = ri64<{ UtcDateTime::MIN.unix_timestamp() }, { UtcDateTime::MAX.unix_timestamp() }>;
31type Nanoseconds = ru32<0, 999_999_999>;
32
33const _: () = {
36 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());
37 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());
38};
39
40#[repr(u32)]
43#[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)]
44enum Padding {
45 #[allow(clippy::missing_docs_in_private_items)]
46 Optimize,
47}
48
49#[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)]
54#[cfg_attr(not(docsrs), repr(C))]
55pub struct Timestamp {
56 #[cfg(target_endian = "big")]
57 seconds: Seconds,
58 #[cfg(target_endian = "big")]
59 nanoseconds: Nanoseconds,
60 #[cfg(target_endian = "big")]
61 padding: Padding,
62
63 #[cfg(target_endian = "little")]
64 padding: Padding,
65 #[cfg(target_endian = "little")]
66 nanoseconds: Nanoseconds,
67 #[cfg(target_endian = "little")]
68 seconds: Seconds,
69}
70
71impl Hash for Timestamp {
72 #[inline]
73 fn hash<H: Hasher>(&self, state: &mut H) {
74 state.write_i128(self.as_i128());
75 }
76}
77
78impl PartialEq for Timestamp {
79 #[inline]
80 fn eq(&self, other: &Self) -> bool {
81 self.as_i128() == other.as_i128()
82 }
83}
84
85impl PartialOrd for Timestamp {
86 #[inline]
87 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
88 Some(self.cmp(other))
89 }
90}
91
92impl Ord for Timestamp {
93 #[inline]
94 fn cmp(&self, other: &Self) -> Ordering {
95 self.as_i128().cmp(&other.as_i128())
96 }
97}
98
99impl Timestamp {
100 #[inline]
101 const fn as_i128(self) -> i128 {
102 unsafe { core::mem::transmute(self) }
106 }
107
108 pub const UNIX_EPOCH: Self =
110 Self::new_ranged(Seconds::new_static::<0>(), Nanoseconds::new_static::<0>());
111
112 pub const MIN: Self = Self::new_ranged(Seconds::MIN, Nanoseconds::MIN);
117
118 pub const MAX: Self = Self::new_ranged(Seconds::MAX, Nanoseconds::MAX);
123
124 #[cfg(feature = "std")]
131 #[inline]
132 pub fn now() -> Self {
133 SystemTime::now().into()
134 }
135
136 #[doc(hidden)]
143 #[inline]
144 #[track_caller]
145 pub const unsafe fn __new_unchecked(seconds: i64, nanoseconds: u32) -> Self {
146 unsafe {
148 Self::new_ranged(
149 Seconds::new_unchecked(seconds),
150 Nanoseconds::new_unchecked(nanoseconds),
151 )
152 }
153 }
154
155 #[inline]
158 pub(crate) const fn new_ranged(seconds: Seconds, nanoseconds: Nanoseconds) -> Self {
159 Self {
160 seconds,
161 nanoseconds,
162 padding: Padding::Optimize,
163 }
164 }
165
166 #[inline]
175 pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Self, error::ComponentRange> {
176 Ok(Self::new_ranged(
177 match <Seconds>::new(seconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("seconds"));
}
}ensure_ranged!(Seconds: seconds),
178 match <Nanoseconds>::new(nanoseconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("nanoseconds"));
}
}ensure_ranged!(Nanoseconds: nanoseconds),
179 ))
180 }
181
182 #[inline]
191 pub const fn from_seconds(seconds: i64) -> Result<Self, error::ComponentRange> {
192 Ok(Self::new_ranged(
193 match <Seconds>::new(seconds) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("seconds"));
}
}ensure_ranged!(Seconds: seconds),
194 Nanoseconds::new_static::<0>(),
195 ))
196 }
197
198 #[inline]
207 pub const fn from_milliseconds(milliseconds: i64) -> Result<Self, error::ComponentRange> {
208 const MAX: i64 = Seconds::MAX.get() * Millisecond::per_t::<i64>(Second)
209 + (Nanoseconds::MAX.get() as i64) / Nanosecond::per_t::<i64>(Millisecond);
210 const MIN: i64 = Seconds::MIN.get() * Millisecond::per_t::<i64>(Second)
211 + (Nanoseconds::MIN.get() as i64) / Nanosecond::per_t::<i64>(Millisecond);
212
213 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);
214
215 let mut seconds = milliseconds / Millisecond::per_t::<i64>(Second);
216 let nanoseconds = (milliseconds.rem_euclid(Millisecond::per_t(Second))
217 * Nanosecond::per_t::<i64>(Millisecond)) as u32;
218
219 if milliseconds < 0 && nanoseconds != 0 {
220 seconds -= 1;
221 }
222
223 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
225 }
226
227 #[inline]
236 pub const fn from_microseconds(microseconds: i128) -> Result<Self, error::ComponentRange> {
237 const MAX: i128 = Seconds::MAX.get() as i128 * Microsecond::per_t::<i128>(Second)
238 + (Nanoseconds::MAX.get() as i128) / Nanosecond::per_t::<i128>(Microsecond);
239 const MIN: i128 = Seconds::MIN.get() as i128 * Microsecond::per_t::<i128>(Second)
240 + (Nanoseconds::MIN.get() as i128) / Nanosecond::per_t::<i128>(Microsecond);
241
242 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);
243
244 let mut seconds = (microseconds / Microsecond::per_t::<i128>(Second)) as i64;
245 let nanoseconds = (microseconds.rem_euclid(Microsecond::per_t(Second))
246 * Nanosecond::per_t::<i128>(Microsecond)) as u32;
247
248 if microseconds < 0 && nanoseconds != 0 {
249 seconds -= 1;
250 }
251
252 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
254 }
255
256 #[inline]
265 pub const fn from_nanoseconds(nanoseconds: i128) -> Result<Self, error::ComponentRange> {
266 const MAX: i128 = Seconds::MAX.get() as i128 * Nanosecond::per_t::<i128>(Second)
267 + Nanoseconds::MAX.get() as i128;
268 const MIN: i128 = Seconds::MIN.get() as i128 * Nanosecond::per_t::<i128>(Second)
269 + Nanoseconds::MIN.get() as i128;
270
271 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);
272
273 let input_is_negative = nanoseconds < 0;
274 let mut seconds = (nanoseconds / Nanosecond::per_t::<i128>(Second)) as i64;
275 let nanoseconds = nanoseconds.rem_euclid(Nanosecond::per_t(Second)) as u32;
276
277 if input_is_negative && nanoseconds != 0 {
278 seconds -= 1;
279 }
280
281 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
283 }
284
285 #[inline]
298 pub const fn to_offset(self, offset: UtcOffset) -> OffsetDateTime {
299 self.to_utc().to_offset(offset)
300 }
301
302 #[inline]
314 pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<OffsetDateTime> {
315 self.to_utc().checked_to_offset(offset)
316 }
317
318 #[inline]
325 pub const fn to_utc(self) -> UtcDateTime {
326 let Ok(utc_dt) = UtcDateTime::from_unix_timestamp(self.seconds.get()) else {
327 {
crate::hint::cold_path();
{
::core::panicking::panic_fmt(format_args!("internal error: timestamp was invalid beforehand"));
}
};bug!("timestamp was invalid beforehand");
328 };
329 let Ok(utc_dt) = utc_dt.replace_nanosecond(self.nanoseconds.get()) else {
330 {
crate::hint::cold_path();
{
::core::panicking::panic_fmt(format_args!("internal error: nanosecond was invalid beforehand"));
}
};bug!("nanosecond was invalid beforehand");
331 };
332
333 utc_dt
334 }
335
336 #[inline]
338 pub(crate) const fn as_parts_ranged(self) -> (Seconds, Nanoseconds) {
339 (self.seconds, self.nanoseconds)
340 }
341
342 #[inline]
351 pub const fn as_seconds(self) -> i64 {
352 self.seconds.get()
353 }
354
355 #[inline]
367 pub const fn as_milliseconds(self) -> i64 {
368 self.seconds.get() * Millisecond::per_t::<i64>(Second)
369 + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as i64
370 }
371
372 #[inline]
384 pub const fn as_microseconds(self) -> i128 {
385 self.seconds.get() as i128 * Microsecond::per_t::<i128>(Second)
386 + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)) as i128
387 }
388
389 #[inline]
401 pub const fn as_nanoseconds(self) -> i128 {
402 self.seconds.get() as i128 * Nanosecond::per_t::<i128>(Second)
403 + self.nanoseconds.get() as i128
404 }
405
406 #[inline]
413 pub const fn date(self) -> Date {
414 self.to_utc().date()
415 }
416
417 #[inline]
424 pub const fn time(self) -> Time {
425 let within_day = self.as_seconds().rem_euclid(Second::per_t::<i64>(Day)) as u32;
426
427 let hour = within_day / Second::per_t::<u32>(Hour);
428 let minute =
429 (within_day - hour * Second::per_t::<u32>(Hour)) / Second::per_t::<u32>(Minute);
430 let second =
431 within_day - hour * Second::per_t::<u32>(Hour) - minute * Second::per_t::<u32>(Minute);
432
433 unsafe {
435 Time::__from_hms_nanos_unchecked(
436 hour as u8,
437 minute as u8,
438 second as u8,
439 self.nanosecond(),
440 )
441 }
442 }
443
444 #[inline]
450 const fn year_leap_ordinal(self) -> (i32, bool, u16) {
451 const ERAS: u32 = 5_949;
452 const D_SHIFT: u32 = 146097 * ERAS + 719_528;
453 const Y_SHIFT: u32 = 400 * ERAS;
454
455 const CEN_MUL: u32 = ((4u64 << 47) / 146_097) as u32;
456 const JUL_MUL: u32 = ((4u64 << 40) / 1_461 + 1) as u32;
457 const CEN_CUT: u32 = ((365u64 << 32) / 36_525) as u32;
458
459 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;
460
461 let day = raw_day.cast_unsigned().wrapping_add(D_SHIFT);
462 let c_n = (day as u64 * CEN_MUL as u64) >> 15;
463 let cen = (c_n >> 32) as u32;
464 let cpt = c_n as u32;
465 let ijy = cpt > CEN_CUT || cen.is_multiple_of(4);
466 let jul = day - cen / 4 + cen;
467 let y_n = (jul as u64 * JUL_MUL as u64) >> 8;
468 let yrs = (y_n >> 32) as u32;
469 let ypt = y_n as u32;
470
471 let year = yrs.wrapping_sub(Y_SHIFT).cast_signed();
472 let ordinal = ((ypt as u64 * 1_461) >> 34) as u32 + ijy as u32;
473 let leap = yrs.is_multiple_of(4) & ijy;
474
475 (year, leap, ordinal as u16)
476 }
477
478 #[inline]
485 pub const fn year(self) -> i32 {
486 self.year_leap_ordinal().0
487 }
488
489 #[inline]
497 pub const fn month(self) -> Month {
498 let (_, leap, ordinal) = self.year_leap_ordinal();
499 util::leap_ordinal_to_month_day(leap, ordinal).0
500 }
501
502 #[inline]
511 pub const fn day(self) -> u8 {
512 let (_, leap, ordinal) = self.year_leap_ordinal();
513 util::leap_ordinal_to_month_day(leap, ordinal).1
514 }
515
516 #[inline]
525 pub const fn ordinal(self) -> u16 {
526 self.year_leap_ordinal().2
527 }
528
529 #[inline]
538 pub const fn iso_week(self) -> u8 {
539 self.date().iso_week()
540 }
541
542 #[inline]
546 pub const fn sunday_based_week(self) -> u8 {
547 self.date().sunday_based_week()
548 }
549
550 #[inline]
554 pub const fn monday_based_week(self) -> u8 {
555 self.date().monday_based_week()
556 }
557
558 #[inline]
569 pub const fn to_calendar_date(self) -> (i32, Month, u8) {
570 let (year, leap, ordinal) = self.year_leap_ordinal();
571 let (month, day) = util::leap_ordinal_to_month_day(leap, ordinal);
572 (year, month, day)
573 }
574
575 #[inline]
582 pub const fn to_ordinal_date(self) -> (i32, u16) {
583 let (year, _, ordinal) = self.year_leap_ordinal();
584 (year, ordinal)
585 }
586
587 #[inline]
598 pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
599 self.date().to_iso_week_date()
600 }
601
602 #[inline]
610 pub const fn weekday(self) -> Weekday {
611 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 {
617 0 => Weekday::Monday,
618 1 => Weekday::Tuesday,
619 2 => Weekday::Wednesday,
620 3 => Weekday::Thursday,
621 4 => Weekday::Friday,
622 5 => Weekday::Saturday,
623 6 => Weekday::Sunday,
624 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
625 }
626 }
627
628 #[inline]
630 pub const fn to_julian_day(self) -> i32 {
631 const UNIX_EPOCH_JULIAN_DAY: i32 = Date::UNIX_EPOCH.to_julian_day();
632 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
633 }
634
635 #[inline]
642 pub const fn as_hms(self) -> (u8, u8, u8) {
643 self.time().as_hms()
644 }
645
646 #[inline]
653 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
654 self.time().as_hms_milli()
655 }
656
657 #[inline]
667 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
668 self.time().as_hms_micro()
669 }
670
671 #[inline]
681 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
682 self.time().as_hms_nano()
683 }
684
685 #[inline]
692 pub const fn hour(self) -> u8 {
693 self.time().hour()
694 }
695
696 #[inline]
703 pub const fn minute(self) -> u8 {
704 (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)))
705 .rem_euclid(Minute::per_t(Hour)) as u8
706 }
707
708 #[inline]
715 pub const fn second(self) -> u8 {
716 self.seconds.get().rem_euclid(Second::per_t(Minute)) as u8
717 }
718
719 #[inline]
726 pub const fn millisecond(self) -> u16 {
727 (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
728 }
729
730 #[inline]
737 pub const fn microsecond(self) -> u32 {
738 self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)
739 }
740
741 #[inline]
751 pub const fn nanosecond(self) -> u32 {
752 self.nanoseconds.get()
753 }
754
755 #[inline]
758 const fn add(self, duration: Duration) -> Result<Self, Overflow> {
759 let (second_adj, nanoseconds) = if duration.is_negative() {
760 let nanos = self.nanoseconds.get() as i32 + duration.subsec_nanoseconds();
761 if nanos < 0 {
762 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
763 } else {
764 (0, nanos as u32)
765 }
766 } else {
767 let nanos = self.nanoseconds.get() + duration.subsec_nanoseconds() as u32;
768 if nanos >= Nanosecond::per_t(Second) {
769 (1, nanos - Nanosecond::per_t::<u32>(Second))
770 } else {
771 (0, nanos)
772 }
773 };
774
775 let seconds = match self.seconds.get().checked_add(duration.whole_seconds()) {
776 Some(seconds) => seconds,
777 None if duration.is_negative() => return Err(Overflow::Negative),
778 None => return Err(Overflow::Positive),
779 };
780 let seconds = match seconds.checked_add(second_adj) {
781 Some(seconds) => seconds,
782 None if second_adj < 0 => return Err(Overflow::Negative),
783 None => return Err(Overflow::Positive),
784 };
785
786 if seconds < Seconds::MIN.get() {
788 return Err(Overflow::Negative);
789 } else if seconds > Seconds::MAX.get() {
790 return Err(Overflow::Positive);
791 }
792
793 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
795 }
796
797 #[inline]
800 const fn sub(self, duration: Duration) -> Result<Self, Overflow> {
801 let nanos = self.nanoseconds.get() as i32 - duration.subsec_nanoseconds();
802 let (second_adj, nanoseconds) = if duration.is_negative() {
803 if nanos >= Nanosecond::per_t::<i32>(Second) {
804 (1, (nanos - Nanosecond::per_t::<i32>(Second)) as u32)
805 } else if nanos < 0 {
806 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
807 } else {
808 (0, nanos as u32)
809 }
810 } else {
811 if nanos < 0 {
812 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
813 } else {
814 (0, nanos as u32)
815 }
816 };
817
818 let seconds = match self.seconds.get().checked_sub(duration.whole_seconds()) {
819 Some(seconds) => seconds,
820 None if duration.is_negative() => return Err(Overflow::Positive),
821 None => return Err(Overflow::Negative),
822 };
823 let seconds = match seconds.checked_add(second_adj) {
824 Some(seconds) => seconds,
825 None if second_adj < 0 => return Err(Overflow::Negative),
826 None => return Err(Overflow::Positive),
827 };
828
829 if seconds < Seconds::MIN.get() {
831 return Err(Overflow::Negative);
832 } else if seconds > Seconds::MAX.get() {
833 return Err(Overflow::Positive);
834 }
835
836 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
838 }
839
840 #[inline]
843 const fn add_std(self, duration: StdDuration) -> Result<Self, Overflow> {
844 let Some(mut seconds) = self.seconds.get().checked_add_unsigned(duration.as_secs()) else {
845 return Err(Overflow::Positive);
846 };
847 let mut nanoseconds = self.nanoseconds.get() + duration.subsec_nanos();
848
849 if nanoseconds >= Nanosecond::per_t(Second) {
850 nanoseconds -= Nanosecond::per_t::<u32>(Second);
851 let Some(new_seconds) = seconds.checked_add(1) else {
852 return Err(Overflow::Positive);
853 };
854 seconds = new_seconds;
855 }
856
857 if seconds < Seconds::MIN.get() {
859 return Err(Overflow::Negative);
860 } else if seconds > Seconds::MAX.get() {
861 return Err(Overflow::Positive);
862 }
863
864 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
866 }
867
868 #[inline]
871 const fn sub_std(self, duration: StdDuration) -> Result<Self, Overflow> {
872 let Some(mut seconds) = self.seconds.get().checked_sub_unsigned(duration.as_secs()) else {
873 return Err(Overflow::Negative);
874 };
875 let mut nanoseconds = self.nanoseconds.get() as i32 - duration.subsec_nanos() as i32;
876
877 if nanoseconds < 0 {
878 nanoseconds += Nanosecond::per_t::<i32>(Second);
879 let Some(new_seconds) = seconds.checked_sub(1) else {
880 return Err(Overflow::Negative);
881 };
882 seconds = new_seconds;
883 }
884
885 if seconds < Seconds::MIN.get() {
887 return Err(Overflow::Negative);
888 } else if seconds > Seconds::MAX.get() {
889 return Err(Overflow::Positive);
890 }
891
892 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds as u32) })
894 }
895
896 #[inline]
911 pub const fn checked_add(self, duration: Duration) -> Option<Self> {
912 match self.add(duration) {
913 Ok(timestamp) => Some(timestamp),
914 Err(Overflow::Positive | Overflow::Negative) => None,
915 }
916 }
917
918 #[inline]
933 pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
934 match self.sub(duration) {
935 Ok(timestamp) => Some(timestamp),
936 Err(Overflow::Positive | Overflow::Negative) => None,
937 }
938 }
939
940 #[inline]
956 pub const fn saturating_add(self, duration: Duration) -> Self {
957 match self.add(duration) {
958 Ok(timestamp) => timestamp,
959 Err(Overflow::Positive) => Self::MAX,
960 Err(Overflow::Negative) => Self::MIN,
961 }
962 }
963
964 #[inline]
980 pub const fn saturating_sub(self, duration: Duration) -> Self {
981 match self.sub(duration) {
982 Ok(timestamp) => timestamp,
983 Err(Overflow::Positive) => Self::MAX,
984 Err(Overflow::Negative) => Self::MIN,
985 }
986 }
987}
988
989impl Timestamp {
991 #[inline]
1001 #[must_use = "This method does not mutate the original `Timestamp`."]
1002 pub const fn replace_time(self, time: Time) -> Self {
1003 let seconds_since_midnight = time.hour() as i64 * Second::per_t::<i64>(Hour)
1004 + time.minute() as i64 * Second::per_t::<i64>(Minute)
1005 + time.second() as i64;
1006 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))
1007 * Second::per_t::<i64>(Day)
1008 + seconds_since_midnight;
1009 unsafe { Self::__new_unchecked(seconds, time.nanosecond()) }
1013 }
1014
1015 #[inline]
1025 #[must_use = "This method does not mutate the original `Timestamp`."]
1026 pub const fn replace_date(mut self, date: Date) -> Self {
1027 let seconds_after_midnight = self.seconds.get().rem_euclid(Second::per_t(Day));
1028 let seconds = (date.to_julian_day() as i64
1029 - UtcDateTime::UNIX_EPOCH.to_julian_day() as i64)
1030 * Second::per_t::<i64>(Day)
1031 + seconds_after_midnight;
1032 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1035 self
1036 }
1037
1038 #[inline]
1051 #[must_use = "This method does not mutate the original `Timestamp`."]
1052 pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1053 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));
1054 Ok(self.replace_date(date))
1055 }
1056
1057 #[inline]
1074 #[must_use = "This method does not mutate the original `Timestamp`."]
1075 pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1076 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));
1077 Ok(self.replace_date(date))
1078 }
1079
1080 #[inline]
1092 #[must_use = "This method does not mutate the original `Timestamp`."]
1093 pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1094 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));
1095 Ok(self.replace_date(date))
1096 }
1097
1098 #[inline]
1110 #[must_use = "This method does not mutate the original `Timestamp`."]
1111 pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1112 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));
1113 Ok(self.replace_date(date))
1114 }
1115
1116 #[inline]
1127 #[must_use = "This method does not mutate the original `Timestamp`."]
1128 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
1129 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);
1130 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))
1131 * Second::per_t::<i64>(Day)
1132 + hour as i64 * Second::per_t::<i64>(Hour)
1133 + self.minute() as i64 * Second::per_t::<i64>(Minute)
1134 + self.second() as i64;
1135 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1137 Ok(self)
1138 }
1139
1140 #[inline]
1151 #[must_use = "This method does not mutate the original `Timestamp`."]
1152 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
1153 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);
1154 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))
1155 * Second::per_t::<i64>(Hour)
1156 + minute as i64 * Second::per_t::<i64>(Minute)
1157 + self.second() as i64;
1158 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1160 Ok(self)
1161 }
1162
1163 #[inline]
1174 #[must_use = "This method does not mutate the original `Timestamp`."]
1175 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
1176 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);
1177 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))
1178 * Second::per_t::<i64>(Minute)
1179 + second as i64;
1180 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1182 Ok(self)
1183 }
1184
1185 #[inline]
1200 #[must_use = "This method does not mutate the original `Timestamp`."]
1201 pub const fn replace_millisecond(
1202 self,
1203 millisecond: u16,
1204 ) -> Result<Self, error::ComponentRange> {
1205 let nanos =
1206 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));
1207 Ok(self.replace_nanosecond_ranged(nanos))
1208 }
1209
1210 #[inline]
1225 #[must_use = "This method does not mutate the original `Timestamp`."]
1226 pub const fn replace_microsecond(
1227 self,
1228 microsecond: u32,
1229 ) -> Result<Self, error::ComponentRange> {
1230 let nanos =
1231 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));
1232 Ok(self.replace_nanosecond_ranged(nanos))
1233 }
1234
1235 #[inline]
1250 #[must_use = "This method does not mutate the original `Timestamp`."]
1251 pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1252 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);
1253 Ok(self.replace_nanosecond_ranged(nanos))
1254 }
1255
1256 #[inline]
1259 const fn replace_nanosecond_ranged(self, new_nanos: Nanoseconds) -> Self {
1260 let (seconds, nanoseconds) = self.as_parts_ranged();
1261
1262 if seconds.get() >= 0 || nanoseconds.get() == 0 {
1263 Self::new_ranged(seconds, new_nanos)
1264 } else if new_nanos.get() == 0 {
1265 Self::new_ranged(unsafe { seconds.unchecked_add(1) }, new_nanos)
1269 } else {
1270 Self::new_ranged(seconds, unsafe {
1273 Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - new_nanos.get())
1274 })
1275 }
1276 }
1277}
1278
1279#[cfg(feature = "formatting")]
1280impl Timestamp {
1281 #[inline]
1283 pub fn format_into(
1284 self,
1285 output: &mut (impl io::Write + ?Sized),
1286 format: &(impl Formattable + ?Sized),
1287 ) -> Result<usize, error::Format> {
1288 format.format_into(output, &self, &mut Default::default())
1289 }
1290
1291 #[inline]
1300 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1301 format.format(&self, &mut Default::default())
1302 }
1303}
1304
1305#[cfg(feature = "parsing")]
1306impl Timestamp {
1307 #[inline]
1321 pub fn parse(
1322 input: &str,
1323 description: &(impl Parsable + ?Sized),
1324 ) -> Result<Self, error::Parse> {
1325 description.parse_timestamp(input.as_bytes())
1326 }
1327}
1328
1329impl Timestamp {
1330 const DISPLAY_BUFFER_SIZE: usize = 25;
1333
1334 pub(crate) fn fmt_into_buffer(
1336 self,
1337 buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
1338 ) -> usize {
1339 let mut idx = 0;
1340
1341 let mut second = self.seconds.get();
1342 let mut nanosecond = self.nanoseconds;
1343
1344 if second < 0 {
1345 buf[idx] = MaybeUninit::new(b'-');
1346 idx += 1;
1347
1348 second = -second;
1349
1350 if nanosecond != Nanoseconds::new_static::<0>() {
1351 second -= 1;
1352 nanosecond = unsafe {
1356 Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - nanosecond.get())
1357 };
1358 }
1359 }
1360
1361 let seconds_str = u64_pad_none(second.cast_unsigned());
1362 let seconds_len = seconds_str.len();
1363 unsafe {
1365 seconds_str
1366 .as_ptr()
1367 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), seconds_len);
1368 }
1369 idx += seconds_len;
1370
1371 if nanosecond != Nanoseconds::new_static::<0>() {
1372 buf[idx] = MaybeUninit::new(b'.');
1373 idx += 1;
1374
1375 let subsecond = truncated_subsecond_from_nanos(nanosecond);
1376 unsafe {
1378 subsecond
1379 .as_ptr()
1380 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len());
1381 }
1382 idx += subsecond.len();
1383 }
1384
1385 idx
1386 }
1387}
1388
1389impl fmt::Display for Timestamp {
1390 #[inline]
1391 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1392 let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1393 let len = self.fmt_into_buffer(&mut buf);
1394 let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1396 f.pad(s)
1397 }
1398}
1399
1400impl fmt::Debug for Timestamp {
1401 #[inline]
1402 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1403 fmt::Display::fmt(self, f)
1404 }
1405}
1406
1407impl Add<Duration> for Timestamp {
1408 type Output = Self;
1409
1410 #[inline]
1414 #[track_caller]
1415 fn add(self, rhs: Duration) -> Self::Output {
1416 self.checked_add(rhs)
1417 .expect("resulting value is out of range")
1418 }
1419}
1420
1421impl Add<StdDuration> for Timestamp {
1422 type Output = Self;
1423
1424 #[inline]
1428 #[track_caller]
1429 fn add(self, rhs: StdDuration) -> Self::Output {
1430 self.add_std(rhs).expect("resulting value is out of range")
1431 }
1432}
1433
1434impl AddAssign<Duration> for Timestamp {
1435 #[inline]
1439 #[track_caller]
1440 fn add_assign(&mut self, rhs: Duration) {
1441 *self = *self + rhs;
1442 }
1443}
1444
1445impl AddAssign<StdDuration> for Timestamp {
1446 #[inline]
1450 #[track_caller]
1451 fn add_assign(&mut self, rhs: StdDuration) {
1452 *self = *self + rhs;
1453 }
1454}
1455
1456impl Sub<Duration> for Timestamp {
1457 type Output = Self;
1458
1459 #[inline]
1463 #[track_caller]
1464 fn sub(self, rhs: Duration) -> Self::Output {
1465 self.checked_sub(rhs)
1466 .expect("resulting value is out of range")
1467 }
1468}
1469
1470impl Sub<StdDuration> for Timestamp {
1471 type Output = Self;
1472
1473 #[inline]
1477 #[track_caller]
1478 fn sub(self, rhs: StdDuration) -> Self::Output {
1479 self.sub_std(rhs).expect("resulting value is out of range")
1480 }
1481}
1482
1483impl SubAssign<Duration> for Timestamp {
1484 #[inline]
1488 #[track_caller]
1489 fn sub_assign(&mut self, rhs: Duration) {
1490 *self = *self - rhs;
1491 }
1492}
1493
1494impl SubAssign<StdDuration> for Timestamp {
1495 #[inline]
1499 #[track_caller]
1500 fn sub_assign(&mut self, rhs: StdDuration) {
1501 *self = *self - rhs;
1502 }
1503}
1504
1505impl Sub for Timestamp {
1506 type Output = Duration;
1507
1508 #[inline]
1509 fn sub(self, rhs: Self) -> Self::Output {
1510 let seconds = self.seconds.get() - rhs.seconds.get();
1511 let nanoseconds = self.nanoseconds.get() as i32 - rhs.nanoseconds.get() as i32;
1512
1513 if nanoseconds < 0 {
1514 Duration::new(seconds - 1, nanoseconds + Nanosecond::per_t::<i32>(Second))
1515 } else {
1516 Duration::new(seconds, nanoseconds)
1517 }
1518 }
1519}