Skip to main content

time/
timestamp.rs

1//! The [`Timestamp`] struct and associated `impl`s.
2
3#[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
35// Validate that the minimum time is midnight and the maximum is one nanosecond before midnight.
36// This is necessary because the soundness of some functions relies on this fact.
37const _: () = {
38    assert!(Timestamp::MIN.time().as_u64() == Time::MIDNIGHT.as_u64());
39    assert!(Timestamp::MAX.time().as_u64() == Time::MAX.as_u64());
40};
41
42/// By explicitly inserting this enum where padding is expected, the compiler is able to better
43/// perform niche value optimization.
44#[repr(u32)]
45#[derive(Clone, Copy, PartialEq, Eq)]
46enum Padding {
47    #[allow(clippy::missing_docs_in_private_items)]
48    Optimize,
49}
50
51/// A Unix timestamp with nanosecond precision.
52///
53/// This type represents a point in time as a number of seconds and nanoseconds elapsed since the
54/// Unix epoch (1970-01-01 00:00:00 UTC). Negative values represent times before the Unix epoch.
55#[derive(Clone, Copy, 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        // Safety: `self` is presumed valid because it exists, and any value of `i128` is valid.
105        // Size and alignment are enforced by the compiler. There is no implicit padding in
106        // either `Timestamp` or `i128`.
107        unsafe { core::mem::transmute(self) }
108    }
109
110    /// A `Timestamp` representing the Unix epoch (1970-01-01 00:00:00 UTC).
111    pub const UNIX_EPOCH: Self =
112        Self::new_ranged(Seconds::new_static::<0>(), Nanoseconds::new_static::<0>());
113
114    /// The minimum valid `Timestamp`.
115    ///
116    /// The moment in time represented by this value may vary depending on the feature flags
117    /// enabled.
118    pub const MIN: Self = Self::new_ranged(Seconds::MIN, Nanoseconds::MIN);
119
120    /// The maximum valid `Timestamp`.
121    ///
122    /// The moment in time represented by this value may vary depending on the feature flags
123    /// enabled.
124    pub const MAX: Self = Self::new_ranged(Seconds::MAX, Nanoseconds::MAX);
125
126    /// Create a new `Timestamp` representing the current moment in time.
127    ///
128    /// ```rust
129    /// # use time::Timestamp;
130    /// assert!(Timestamp::now().year() >= 2019);
131    /// ```
132    #[cfg(feature = "std")]
133    #[inline]
134    pub fn now() -> Self {
135        SystemTime::now().into()
136    }
137
138    /// Create a `Timestamp` from the provided seconds and nanoseconds values without checking if
139    /// they are valid.
140    ///
141    /// # Safety
142    ///
143    /// Both `seconds` and `nanoseconds` must be in range.
144    #[doc(hidden)]
145    #[inline]
146    #[track_caller]
147    pub const unsafe fn __new_unchecked(seconds: i64, nanoseconds: u32) -> Self {
148        // Safety: The caller must ensure both values are valid.
149        unsafe {
150            Self::new_ranged(
151                Seconds::new_unchecked(seconds),
152                Nanoseconds::new_unchecked(nanoseconds),
153            )
154        }
155    }
156
157    /// Create a `Timestamp` from the provided seconds and nanoseconds values that are known to be
158    /// in range.
159    #[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    /// Create a `Timestamp` from the provided Unix timestamp in seconds and nanoseconds, returning
169    /// an error if the resulting value is out of range.
170    ///
171    /// ```rust
172    /// # use time::Timestamp;
173    /// assert!(Timestamp::new(0, 0).is_ok());
174    /// assert!(Timestamp::new(i64::MAX, 0).is_err());
175    /// ```
176    #[inline]
177    pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Self, error::ComponentRange> {
178        Ok(Self::new_ranged(
179            ensure_ranged!(Seconds: seconds),
180            ensure_ranged!(Nanoseconds: nanoseconds),
181        ))
182    }
183
184    /// Create a `Timestamp` from the provided Unix timestamp in seconds, returning an error if the
185    /// resulting value is out of range.
186    ///
187    /// ```rust
188    /// # use time::Timestamp;
189    /// assert!(Timestamp::from_seconds(0).is_ok());
190    /// assert!(Timestamp::from_seconds(i64::MAX).is_err());
191    /// ```
192    #[inline]
193    pub const fn from_seconds(seconds: i64) -> Result<Self, error::ComponentRange> {
194        Ok(Self::new_ranged(
195            ensure_ranged!(Seconds: seconds),
196            Nanoseconds::new_static::<0>(),
197        ))
198    }
199
200    /// Create a `Timestamp` from the provided Unix timestamp in milliseconds, returning an error if
201    /// the resulting value is out of range.
202    ///
203    /// ```rust
204    /// # use time::Timestamp;
205    /// assert!(Timestamp::from_milliseconds(0).is_ok());
206    /// assert!(Timestamp::from_milliseconds(i64::MAX).is_err());
207    /// ```
208    #[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        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        // Safety: The value provided was checked to be in range.
226        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
227    }
228
229    /// Create a `Timestamp` from the provided Unix timestamp in microseconds, returning an error if
230    /// the resulting value is out of range.
231    ///
232    /// ```rust
233    /// # use time::Timestamp;
234    /// assert!(Timestamp::from_microseconds(0).is_ok());
235    /// assert!(Timestamp::from_microseconds(i128::MAX).is_err());
236    /// ```
237    #[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        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        // Safety: The value provided was checked to be in range.
255        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
256    }
257
258    /// Create a `Timestamp` from the provided Unix timestamp in nanoseconds, returning an error if
259    /// the resulting value is out of range.
260    ///
261    /// ```rust
262    /// # use time::Timestamp;
263    /// assert!(Timestamp::from_nanoseconds(0).is_ok());
264    /// assert!(Timestamp::from_nanoseconds(i128::MAX).is_err());
265    /// ```
266    #[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        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        // Safety: The value provided was checked to be in range.
284        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
285    }
286
287    /// Convert the `Timestamp` to an [`OffsetDateTime`] at the provided offset.
288    ///
289    /// ```rust
290    /// # use time_macros::{offset, timestamp};
291    /// assert_eq!(timestamp!(1_546_398_245).to_offset(offset!(+1)).hour(), 4);
292    /// ```
293    ///
294    /// # Panics
295    ///
296    /// This panics if the resulting date-time with the provided offset is outside the supported
297    /// range. Consider using [`checked_to_offset`](Self::checked_to_offset) for a non-panicking
298    /// alternative.
299    #[inline]
300    pub const fn to_offset(self, offset: UtcOffset) -> OffsetDateTime {
301        self.to_utc().to_offset(offset)
302    }
303
304    /// Convert the `Timestamp` to an [`OffsetDateTime`] with the provided offset, returning `None`
305    /// if the resulting value is out of range.
306    ///
307    /// ```rust
308    /// # use time_macros::{offset, timestamp};
309    /// assert!(
310    ///     timestamp!(1_546_398_245)
311    ///         .checked_to_offset(offset!(+1))
312    ///         .is_some()
313    /// );
314    /// ```
315    #[inline]
316    pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<OffsetDateTime> {
317        self.to_utc().checked_to_offset(offset)
318    }
319
320    /// Convert the `Timestamp` to a [`UtcDateTime`].
321    ///
322    /// ```rust
323    /// # use time_macros::{timestamp, utc_datetime};
324    /// assert_eq!(timestamp!(1_546_398_245).to_utc(), utc_datetime!(2019-01-02 3:04:05));
325    /// ```
326    #[inline]
327    pub const fn to_utc(self) -> UtcDateTime {
328        let Ok(utc_dt) = UtcDateTime::from_unix_timestamp(self.seconds.get()) else {
329            bug!("timestamp was invalid beforehand");
330        };
331        let Ok(utc_dt) = utc_dt.replace_nanosecond(self.nanoseconds.get()) else {
332            bug!("nanosecond was invalid beforehand");
333        };
334
335        utc_dt
336    }
337
338    /// Get the seconds and nanoseconds of the timestamp as ranged values.
339    #[inline]
340    pub(crate) const fn as_parts_ranged(self) -> (Seconds, Nanoseconds) {
341        (self.seconds, self.nanoseconds)
342    }
343
344    /// Get the number of seconds since the Unix epoch.
345    ///
346    /// Negative values represent moments before the Unix epoch.
347    ///
348    /// ```rust
349    /// # use time_macros::timestamp;
350    /// assert_eq!(timestamp!(1_546_398_245).as_seconds(), 1_546_398_245);
351    /// ```
352    #[inline]
353    pub const fn as_seconds(self) -> i64 {
354        self.seconds.get()
355    }
356
357    /// Get the number of milliseconds since the Unix epoch.
358    ///
359    /// Negative values represent moments before the Unix epoch.
360    ///
361    /// ```rust
362    /// # use time_macros::timestamp;
363    /// assert_eq!(
364    ///     timestamp!(1_546_398_245.006).as_milliseconds(),
365    ///     1_546_398_245_006
366    /// );
367    /// ```
368    #[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    /// Get the number of microseconds since the Unix epoch.
375    ///
376    /// Negative values represent moments before the Unix epoch.
377    ///
378    /// ```rust
379    /// # use time_macros::timestamp;
380    /// assert_eq!(
381    ///     timestamp!(1_546_398_245.006_007).as_microseconds(),
382    ///     1_546_398_245_006_007
383    /// );
384    /// ```
385    #[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    /// Get the number of nanoseconds since the Unix epoch.
392    ///
393    /// Negative values represent moments before the Unix epoch.
394    ///
395    /// ```rust
396    /// # use time_macros::timestamp;
397    /// assert_eq!(
398    ///     timestamp!(1_546_398_245.006_007_008).as_nanoseconds(),
399    ///     1_546_398_245_006_007_008
400    /// );
401    /// ```
402    #[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    /// Get the [`Date`] of the timestamp in UTC.
409    ///
410    /// ```rust
411    /// # use time_macros::{date, timestamp};
412    /// assert_eq!(timestamp!(1_546_398_245).date(), date!(2019-01-02));
413    /// ```
414    #[inline]
415    pub const fn date(self) -> Date {
416        self.to_utc().date()
417    }
418
419    /// Get the [`Time`] of the timestamp in UTC.
420    ///
421    /// ```rust
422    /// # use time_macros::{time, timestamp};
423    /// assert_eq!(timestamp!(1_546_398_245).time(), time!(3:04:05));
424    /// ```
425    #[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        // Safety: All values are guaranteed to be in range.
436        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    /// Compute the year, leap year status, and ordinal day of the timestamp in UTC.
447    ///
448    /// This algorithm is essentially identical to `Date::from_julian_day_unchecked`. Instead of
449    /// returning `Date`, it returns the components as a tuple. By not bitpacking the values, it
450    /// allows the compiler to see through the function boundary and better optimize methods.
451    #[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 = 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    /// Get the year of the timestamp in UTC.
481    ///
482    /// ```rust
483    /// # use time_macros::timestamp;
484    /// assert_eq!(timestamp!(1_546_398_245).year(), 2019);
485    /// ```
486    #[inline]
487    pub const fn year(self) -> i32 {
488        self.year_leap_ordinal().0
489    }
490
491    /// Get the month of the timestamp in UTC.
492    ///
493    /// ```rust
494    /// # use time::Month;
495    /// # use time_macros::timestamp;
496    /// assert_eq!(timestamp!(1_546_398_245).month(), Month::January);
497    /// ```
498    #[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    /// Get the day of the month of the timestamp in UTC.
505    ///
506    /// The returned value will always be in the range `1..=31`.
507    ///
508    /// ```rust
509    /// # use time_macros::timestamp;
510    /// assert_eq!(timestamp!(1_546_398_245).day(), 2);
511    /// ```
512    #[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    /// Get the day of the year of the timestamp in UTC.
519    ///
520    /// The returned value will always be in the range `1..=366`.
521    ///
522    /// ```rust
523    /// # use time_macros::timestamp;
524    /// assert_eq!(timestamp!(1_546_398_245).ordinal(), 2);
525    /// ```
526    #[inline]
527    pub const fn ordinal(self) -> u16 {
528        self.year_leap_ordinal().2
529    }
530
531    /// Get the ISO week number of the timestamp in UTC.
532    ///
533    /// The returned value will always be in the range `1..=53`.
534    ///
535    /// ```rust
536    /// # use time_macros::timestamp;
537    /// assert_eq!(timestamp!(1_546_398_245).iso_week(), 1);
538    /// ```
539    #[inline]
540    pub const fn iso_week(self) -> u8 {
541        self.date().iso_week()
542    }
543
544    /// Get the Sunday-based week number of the timestamp in UTC.
545    ///
546    /// The returned value will always be in the range `0..=53`.
547    ///
548    /// ```rust
549    /// # use time_macros::timestamp;
550    /// assert_eq!(timestamp!(1_546_398_245).sunday_based_week(), 0);
551    /// ```
552    #[inline]
553    pub const fn sunday_based_week(self) -> u8 {
554        self.date().sunday_based_week()
555    }
556
557    /// Get the Monday-based week number of the timestamp in UTC.
558    ///
559    /// The returned value will always be in the range `0..=53`.
560    ///
561    /// ```rust
562    /// # use time_macros::timestamp;
563    /// assert_eq!(timestamp!(1_546_398_245).monday_based_week(), 0);
564    /// ```
565    #[inline]
566    pub const fn monday_based_week(self) -> u8 {
567        self.date().monday_based_week()
568    }
569
570    /// Get the calendar date (year, month, day) of the timestamp in UTC.
571    ///
572    /// ```rust
573    /// # use time::Month;
574    /// # use time_macros::timestamp;
575    /// assert_eq!(
576    ///     timestamp!(1_546_398_245).to_calendar_date(),
577    ///     (2019, Month::January, 2)
578    /// );
579    /// ```
580    #[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    /// Get the ordinal date (year, ordinal day) of the timestamp in UTC.
588    ///
589    /// ```rust
590    /// # use time_macros::timestamp;
591    /// assert_eq!(timestamp!(1_546_398_245).to_ordinal_date(), (2019, 2));
592    /// ```
593    #[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    /// Get the ISO week date (year, week number, weekday) of the timestamp in UTC.
600    ///
601    /// ```rust
602    /// # use time::Weekday;
603    /// # use time_macros::timestamp;
604    /// assert_eq!(
605    ///     timestamp!(1_546_398_245).to_iso_week_date(),
606    ///     (2019, 1, Weekday::Wednesday)
607    /// );
608    /// ```
609    #[inline]
610    pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
611        self.date().to_iso_week_date()
612    }
613
614    /// Get the weekday of the timestamp in UTC.
615    ///
616    /// ```rust
617    /// # use time::Weekday;
618    /// # use time_macros::timestamp;
619    /// assert_eq!(timestamp!(1_546_398_245).weekday(), Weekday::Wednesday);
620    /// ```
621    #[inline]
622    pub const fn weekday(self) -> Weekday {
623        // 365,961,669 is obtained by starting with the smallest timestamp (with large-dates
624        // enabled), dividing by 86,400 to get the number of days, then rounding down to get a
625        // multiple of 7. This value is negated as we want to end with a positive number. Finally, 3
626        // is added to shift the zero value to Monday, matching the internal representation of
627        // `Weekday`.
628        match (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            _ => unreachable!(),
637        }
638    }
639
640    /// Get the Julian day of the timestamp.
641    ///
642    /// ```rust
643    /// # use time_macros::timestamp;
644    /// assert_eq!(timestamp!(1_546_398_245).to_julian_day(), 2_458_486);
645    /// ```
646    #[inline]
647    pub const fn to_julian_day(self) -> i32 {
648        const UNIX_EPOCH_JULIAN_DAY: i32 = Date::UNIX_EPOCH.to_julian_day();
649        div_floor!(self.seconds.get(), 86_400) as i32 + UNIX_EPOCH_JULIAN_DAY
650    }
651
652    /// Get the hours, minutes, and seconds of the timestamp in UTC.
653    ///
654    /// ```rust
655    /// # use time_macros::timestamp;
656    /// assert_eq!(timestamp!(1_546_398_245).as_hms(), (3, 4, 5));
657    /// ```
658    #[inline]
659    pub const fn as_hms(self) -> (u8, u8, u8) {
660        self.time().as_hms()
661    }
662
663    /// Get the hours, minutes, seconds, and milliseconds of the timestamp in UTC.
664    ///
665    /// ```rust
666    /// # use time_macros::timestamp;
667    /// assert_eq!(timestamp!(1_546_398_245.006).as_hms_milli(), (3, 4, 5, 6));
668    /// ```
669    #[inline]
670    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
671        self.time().as_hms_milli()
672    }
673
674    /// Get the hours, minutes, seconds, and microseconds of the timestamp in UTC.
675    ///
676    /// ```rust
677    /// # use time_macros::timestamp;
678    /// assert_eq!(
679    ///     timestamp!(1_546_398_245.006_007).as_hms_micro(),
680    ///     (3, 4, 5, 6_007)
681    /// );
682    /// ```
683    #[inline]
684    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
685        self.time().as_hms_micro()
686    }
687
688    /// Get the hours, minutes, seconds, and nanoseconds of the timestamp in UTC.
689    ///
690    /// ```rust
691    /// # use time_macros::timestamp;
692    /// assert_eq!(
693    ///     timestamp!(1_546_398_245.006_007_008).as_hms_nano(),
694    ///     (3, 4, 5, 6_007_008)
695    /// );
696    /// ```
697    #[inline]
698    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
699        self.time().as_hms_nano()
700    }
701
702    /// Get the hour of the timestamp in UTC.
703    ///
704    /// ```rust
705    /// # use time_macros::timestamp;
706    /// assert_eq!(timestamp!(1_546_398_245).hour(), 3);
707    /// ```
708    #[inline]
709    pub const fn hour(self) -> u8 {
710        self.time().hour()
711    }
712
713    /// Get the minute of the timestamp in UTC.
714    ///
715    /// ```rust
716    /// # use time_macros::timestamp;
717    /// assert_eq!(timestamp!(1_546_398_245).minute(), 4);
718    /// ```
719    #[inline]
720    pub const fn minute(self) -> u8 {
721        (div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute)))
722            .rem_euclid(Minute::per_t(Hour)) as u8
723    }
724
725    /// Get the second of the timestamp in UTC.
726    ///
727    /// ```rust
728    /// # use time_macros::timestamp;
729    /// assert_eq!(timestamp!(1_546_398_245).second(), 5);
730    /// ```
731    #[inline]
732    pub const fn second(self) -> u8 {
733        self.seconds.get().rem_euclid(Second::per_t(Minute)) as u8
734    }
735
736    /// Get the millisecond of the timestamp in UTC.
737    ///
738    /// ```rust
739    /// # use time_macros::timestamp;
740    /// assert_eq!(timestamp!(1_546_398_245.006).millisecond(), 6);
741    /// ```
742    #[inline]
743    pub const fn millisecond(self) -> u16 {
744        (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
745    }
746
747    /// Get the microsecond of the timestamp in UTC.
748    ///
749    /// ```rust
750    /// # use time_macros::timestamp;
751    /// assert_eq!(timestamp!(1_546_398_245.006_007).microsecond(), 6_007);
752    /// ```
753    #[inline]
754    pub const fn microsecond(self) -> u32 {
755        self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)
756    }
757
758    /// Get the nanosecond of the timestamp in UTC.
759    ///
760    /// ```rust
761    /// # use time_macros::timestamp;
762    /// assert_eq!(
763    ///     timestamp!(1_546_398_245.006_007_008).nanosecond(),
764    ///     6_007_008
765    /// );
766    /// ```
767    #[inline]
768    pub const fn nanosecond(self) -> u32 {
769        self.nanoseconds.get()
770    }
771
772    /// Add a [`Duration`] to the timestamp. Returns `Overflow::Positive` or `Overflow::Negative` if
773    /// the result is out of range.
774    #[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        // Check if the resulting seconds are within the valid range
804        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        // Safety: Both values are guaranteed to be in range.
811        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
812    }
813
814    /// Subtract a [`Duration`] from the timestamp. Returns `Overflow::Positive` or
815    /// `Overflow::Negative` if the result is out of range.
816    #[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        // Check if the resulting seconds are within the valid range
847        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        // Safety: Both values are guaranteed to be in range.
854        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
855    }
856
857    /// Add a [`std::time::Duration`] to the timestamp. Returns `Overflow::Positive` or
858    /// `Overflow::Negative` if the result is out of range.
859    #[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        // Check if the resulting seconds are within the valid range
875        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        // Safety: Both values are guaranteed to be in range.
882        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
883    }
884
885    /// Subtract a [`std::time::Duration`] from the timestamp. Returns `Overflow::Positive` or
886    /// `Overflow::Negative` if the result is out of range.
887    #[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        // Check if the resulting seconds are within the valid range
903        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        // Safety: Both values are guaranteed to be in range.
910        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds as u32) })
911    }
912
913    /// Checked addition of a [`Duration`], returning `None` if the result is out of range.
914    ///
915    /// ```rust
916    /// # use time_macros::timestamp;
917    /// # use time::ext::NumericalDuration as _;
918    /// assert_eq!(
919    ///     timestamp!(1_546_398_245).checked_add(1.days()),
920    ///     Some(timestamp!(1_546_484_645))
921    /// );
922    /// assert_eq!(
923    ///     timestamp!(1_546_398_245).checked_add((-1).days()),
924    ///     Some(timestamp!(1_546_311_845))
925    /// );
926    /// ```
927    #[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    /// Checked subtraction of a [`Duration`], returning `None` if the result is out of range.
936    ///
937    /// ```rust
938    /// # use time_macros::timestamp;
939    /// # use time::ext::NumericalDuration as _;
940    /// assert_eq!(
941    ///     timestamp!(1_546_398_245).checked_sub(1.days()),
942    ///     Some(timestamp!(1_546_311_845))
943    /// );
944    /// assert_eq!(
945    ///     timestamp!(1_546_398_245).checked_sub((-1).days()),
946    ///     Some(timestamp!(1_546_484_645))
947    /// );
948    /// ```
949    #[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    /// Saturating addition of a [`Duration`].
958    ///
959    /// Returns [`Timestamp::MAX`] or [`Timestamp::MIN`] if the result is out of range.
960    ///
961    /// ```rust
962    /// # use time::Timestamp;
963    /// # use time_macros::timestamp;
964    /// # use time::ext::NumericalDuration as _;
965    /// assert_eq!(
966    ///     timestamp!(1_546_398_245).saturating_add(1.days()),
967    ///     timestamp!(1_546_484_645)
968    /// );
969    /// assert_eq!(Timestamp::MAX.saturating_add(1.days()), Timestamp::MAX);
970    /// assert_eq!(Timestamp::MIN.saturating_add((-1).days()), Timestamp::MIN);
971    /// ```
972    #[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    /// Saturating subtraction of a [`Duration`].
982    ///
983    /// Returns [`Timestamp::MAX`] or [`Timestamp::MIN`] if the result is out of range.
984    ///
985    /// ```rust
986    /// # use time::Timestamp;
987    /// # use time_macros::timestamp;
988    /// # use time::ext::NumericalDuration as _;
989    /// assert_eq!(
990    ///     timestamp!(1_546_398_245).saturating_sub(1.days()),
991    ///     timestamp!(1_546_311_845)
992    /// );
993    /// assert_eq!(Timestamp::MIN.saturating_sub(1.days()), Timestamp::MIN);
994    /// assert_eq!(Timestamp::MAX.saturating_sub((-1).days()), Timestamp::MAX);
995    /// ```
996    #[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
1006/// Methods that replace part of the `Timestamp`.
1007impl Timestamp {
1008    /// Replace the time, preserving the date.
1009    ///
1010    /// ```rust
1011    /// # use time_macros::{time, timestamp};
1012    /// assert_eq!(
1013    ///     timestamp!(1_546_398_245).replace_time(time!(12:34:56)),
1014    ///     timestamp!(1_546_432_496)
1015    /// );
1016    /// ```
1017    #[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 = div_floor!(self.seconds.get(), Second::per_t::<i64>(Day))
1024            * Second::per_t::<i64>(Day)
1025            + seconds_since_midnight;
1026        // Safety: Seconds is constructed from an existing valid value, and nanoseconds are always
1027        // in range given the origin. Any time of day is valid for any date in range, as enforced by
1028        // const assertions.
1029        unsafe { Self::__new_unchecked(seconds, time.nanosecond()) }
1030    }
1031
1032    /// Replace the date, preserving the time.
1033    ///
1034    /// ```rust
1035    /// # use time_macros::{date, timestamp};
1036    /// assert_eq!(
1037    ///     timestamp!(1_546_398_245).replace_date(date!(2020-01-02)),
1038    ///     timestamp!(1_577_934_245)
1039    /// );
1040    /// ```
1041    #[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        // Safety: The range of valid dates is identical to the range of valid timestamps, so any
1050        // date is necessarily valid.
1051        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1052        self
1053    }
1054
1055    /// Replace the year, preserving the month and day. If the date is February 29 and the resulting
1056    /// year is not a leap year, an error is returned.
1057    ///
1058    /// ```rust
1059    /// # use time_macros::timestamp;
1060    /// assert_eq!(
1061    ///     timestamp!(1_546_398_245).replace_year(2020),
1062    ///     Ok(timestamp!(1_577_934_245))
1063    /// );
1064    /// assert!(timestamp!(1_546_398_245).replace_year(-1_000_000).is_err()); // -1_000_000 isn't a valid year
1065    /// assert!(timestamp!(1_546_398_245).replace_year(1_000_000).is_err()); // 1_000_000 isn't a valid year
1066    /// ```
1067    #[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 = const_try!(self.date().replace_year(year));
1071        Ok(self.replace_date(date))
1072    }
1073
1074    /// Replace the month of the year, preserving the year and day. If the day is invalid for the
1075    /// resulting month, an error is returned.
1076    ///
1077    /// ```rust
1078    /// # use time_macros::timestamp;
1079    /// # use time::Month;
1080    /// assert_eq!(
1081    ///     timestamp!(1_546_398_245).replace_month(Month::February),
1082    ///     Ok(timestamp!(1_549_076_645))
1083    /// );
1084    /// assert!(
1085    ///     timestamp!(1_548_817_445)
1086    ///         .replace_month(Month::February)
1087    ///         .is_err()
1088    /// ); // the day of the month is 30, which is invalid for February
1089    /// ```
1090    #[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 = const_try!(self.date().replace_month(month));
1094        Ok(self.replace_date(date))
1095    }
1096
1097    /// Replace the day of the month.
1098    ///
1099    /// ```rust
1100    /// # use time_macros::timestamp;
1101    /// assert_eq!(
1102    ///     timestamp!(1_546_398_245).replace_day(1),
1103    ///     Ok(timestamp!(1_546_311_845))
1104    /// );
1105    /// assert!(timestamp!(1_546_398_245).replace_day(0).is_err()); // 00 isn't a valid day
1106    /// assert!(timestamp!(1_546_398_245).replace_day(32).is_err()); // 32 isn't a valid day
1107    /// ```
1108    #[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 = const_try!(self.date().replace_day(day));
1112        Ok(self.replace_date(date))
1113    }
1114
1115    /// Replace the day of the year.
1116    ///
1117    /// ```rust
1118    /// # use time_macros::timestamp;
1119    /// assert_eq!(
1120    ///     timestamp!(1_546_398_245).replace_ordinal(1),
1121    ///     Ok(timestamp!(1_546_311_845))
1122    /// );
1123    /// assert!(timestamp!(1_546_398_245).replace_ordinal(0).is_err()); // 0 isn't a valid day of the year
1124    /// assert!(timestamp!(1_546_398_245).replace_ordinal(366).is_err()); // the timestamp is in 2019, which isn't a leap year
1125    /// ```
1126    #[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 = const_try!(self.date().replace_ordinal(ordinal));
1130        Ok(self.replace_date(date))
1131    }
1132
1133    /// Replace the clock hour.
1134    ///
1135    /// ```rust
1136    /// # use time_macros::timestamp;
1137    /// assert_eq!(
1138    ///     timestamp!(1_546_398_245).replace_hour(0),
1139    ///     Ok(timestamp!(1_546_387_445))
1140    /// );
1141    /// assert!(timestamp!(1_546_398_245).replace_hour(24).is_err()); // 24 isn't a valid hour
1142    /// ```
1143    #[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        ensure_ranged!(ru8<0, 23>: hour);
1147        let seconds = 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        // Safety: Any value is valid so long as `hour` is in range.
1153        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1154        Ok(self)
1155    }
1156
1157    /// Replace the minutes within the hour.
1158    ///
1159    /// ```rust
1160    /// # use time_macros::timestamp;
1161    /// assert_eq!(
1162    ///     timestamp!(1_546_398_245).replace_minute(0),
1163    ///     Ok(timestamp!(1_546_398_005))
1164    /// );
1165    /// assert!(timestamp!(1_546_398_245).replace_minute(60).is_err()); // 60 isn't a valid minute
1166    /// ```
1167    #[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        ensure_ranged!(ru8<0, 59>: minute);
1171        let seconds = 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        // Safety: Any value is valid so long as `minute` is in range.
1176        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1177        Ok(self)
1178    }
1179
1180    /// Replace the seconds within the minute.
1181    ///
1182    /// ```rust
1183    /// # use time_macros::timestamp;
1184    /// assert_eq!(
1185    ///     timestamp!(1_546_398_245).replace_second(0),
1186    ///     Ok(timestamp!(1_546_398_240))
1187    /// );
1188    /// assert!(timestamp!(1_546_398_245).replace_second(60).is_err()); // 60 isn't a valid second
1189    /// ```
1190    #[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        ensure_ranged!(ru8<0, 59>: second);
1194        let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute))
1195            * Second::per_t::<i64>(Minute)
1196            + second as i64;
1197        // Safety: Any value is valid so long as `second` is in range.
1198        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1199        Ok(self)
1200    }
1201
1202    /// Replace the milliseconds within the second.
1203    ///
1204    /// ```rust
1205    /// # use time_macros::timestamp;
1206    /// assert_eq!(
1207    ///     timestamp!(1_546_398_245.006).replace_millisecond(7),
1208    ///     Ok(timestamp!(1_546_398_245.007))
1209    /// );
1210    /// assert!(
1211    ///     timestamp!(1_546_398_245.006)
1212    ///         .replace_millisecond(1_000)
1213    ///         .is_err()
1214    /// ); // 1_000 isn't a valid millisecond
1215    /// ```
1216    #[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            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
1224        Ok(self.replace_nanosecond_ranged(nanos))
1225    }
1226
1227    /// Replace the microseconds within the second.
1228    ///
1229    /// ```rust
1230    /// # use time_macros::timestamp;
1231    /// assert_eq!(
1232    ///     timestamp!(1_546_398_245.006_007).replace_microsecond(123_456),
1233    ///     Ok(timestamp!(1_546_398_245.123_456))
1234    /// );
1235    /// assert!(
1236    ///     timestamp!(1_546_398_245.006_007)
1237    ///         .replace_microsecond(1_000_000)
1238    ///         .is_err()
1239    /// ); // 1_000_000 isn't a valid microsecond
1240    /// ```
1241    #[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            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
1249        Ok(self.replace_nanosecond_ranged(nanos))
1250    }
1251
1252    /// Replace the nanoseconds within the second.
1253    ///
1254    /// ```rust
1255    /// # use time_macros::timestamp;
1256    /// assert_eq!(
1257    ///     timestamp!(1_546_398_245.006_007_008).replace_nanosecond(123_456_789),
1258    ///     Ok(timestamp!(1_546_398_245.123_456_789))
1259    /// );
1260    /// assert!(
1261    ///     timestamp!(1_546_398_245.006_007_008)
1262    ///         .replace_nanosecond(1_000_000_000)
1263    ///         .is_err()
1264    /// ); // 1_000_000_000 isn't a valid nanosecond
1265    /// ```
1266    #[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 = ensure_ranged!(Nanoseconds: nanosecond);
1270        Ok(self.replace_nanosecond_ranged(nanos))
1271    }
1272
1273    /// Replace the nanoseconds within the second using a range-bounded integer to avoid range
1274    /// checks.
1275    #[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            // Safety: The previous conditional guarantees that `seconds` is negative (if it were
1283            // non-negative, we wouldn't be in this branch). Given that the maximum value is
1284            // positive, we can always add one without exceeding the maximum.
1285            Self::new_ranged(unsafe { seconds.unchecked_add(1) }, new_nanos)
1286        } else {
1287            // Safety: Given the range of `new_nanos`, subtracting it from the maximum always
1288            // results in a value in range. Zero is excluded by a previous conditional.
1289            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    /// Format the `Timestamp` using the provided [format description](crate::format_description).
1299    #[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    /// Format the `Timestamp` using the provided [format description](crate::format_description).
1309    ///
1310    /// ```rust
1311    /// # use time_macros::{format_description, timestamp};
1312    /// let format = format_description!("[unix_timestamp]");
1313    /// assert_eq!(timestamp!(1_546_398_245).format(&format)?, "1546398245");
1314    /// # Ok::<_, time::Error>(())
1315    /// ```
1316    #[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    /// Parse a `Timestamp` from the input using the provided [format
1325    /// description](crate::format_description).
1326    ///
1327    /// ```rust
1328    /// # use time::Timestamp;
1329    /// # use time_macros::{format_description, timestamp};
1330    /// let format = format_description!("[unix_timestamp]");
1331    /// assert_eq!(
1332    ///     Timestamp::parse("1546398245", &format)?,
1333    ///     timestamp!(1_546_398_245),
1334    /// );
1335    /// # Ok::<_, time::Error>(())
1336    /// ```
1337    #[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    /// Parse a `Timestamp` from the input using the provided [format
1346    /// description](crate::format_description) and default values.
1347    ///
1348    /// ```rust
1349    /// # use time::Timestamp;
1350    /// # use time::parsing::Parsed;
1351    /// # use time_macros::{format_description, timestamp};
1352    /// let format = format_description!("[year]-[month]-[day]");
1353    /// let defaults = Parsed::new().with_hour_24(0).expect("0 is a valid hour");
1354    /// assert_eq!(
1355    ///     Timestamp::parse_with_defaults(b"2020-01-02", &format, defaults)?,
1356    ///     timestamp!(1_577_923_200)
1357    /// );
1358    /// # Ok::<_, time::Error>(())
1359    /// ```
1360    #[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    /// The maximum number of bytes that the `fmt_into_buffer` method will write, which is also used
1372    /// by the `Display` implementation.
1373    const DISPLAY_BUFFER_SIZE: usize = 25;
1374
1375    /// Format the `Timestamp` into the provided buffer, returning the number of bytes written.
1376    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                // Safety: `nanosecond` is in the range 1..=999_999_999, so subtracting it from
1394                // 1_000_000_000 will always yield a value in the range 1..=999_999_999, which is a
1395                // subset of the valid range for `Nanoseconds`.
1396                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        // Safety: `buf` has sufficient capacity for the seconds digits.
1405        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            // Safety: `buf` has sufficient capacity for the subsecond digits.
1418            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        // Safety: All bytes up to `len` have been initialized with ASCII characters.
1436        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    /// # Panics
1452    ///
1453    /// This may panic if an overflow occurs.
1454    #[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    /// # Panics
1466    ///
1467    /// This may panic if an overflow occurs.
1468    #[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    /// # Panics
1477    ///
1478    /// This may panic if an overflow occurs.
1479    #[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    /// # Panics
1488    ///
1489    /// This may panic if an overflow occurs.
1490    #[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    /// # Panics
1501    ///
1502    /// This may panic if an overflow occurs.
1503    #[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    /// # Panics
1515    ///
1516    /// This may panic if an overflow occurs.
1517    #[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    /// # Panics
1526    ///
1527    /// This may panic if an overflow occurs.
1528    #[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    /// # Panics
1537    ///
1538    /// This may panic if an overflow occurs.
1539    #[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}