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(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
33// Validate that the minimum time is midnight and the maximum is one nanosecond before midnight.
34// This is necessary because the soundness of some functions relies on this fact.
35const _: () = {
36    assert!(Timestamp::MIN.time().as_u64() == Time::MIDNIGHT.as_u64());
37    assert!(Timestamp::MAX.time().as_u64() == Time::MAX.as_u64());
38};
39
40/// By explicitly inserting this enum where padding is expected, the compiler is able to better
41/// perform niche value optimization.
42#[repr(u32)]
43#[derive(Clone, Copy, PartialEq, Eq)]
44enum Padding {
45    #[allow(clippy::missing_docs_in_private_items)]
46    Optimize,
47}
48
49/// A Unix timestamp with nanosecond precision.
50///
51/// This type represents a point in time as a number of seconds and nanoseconds elapsed since the
52/// Unix epoch (1970-01-01 00:00:00 UTC). Negative values represent times before the Unix epoch.
53#[derive(Clone, Copy, 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        // Safety: `self` is presumed valid because it exists, and any value of `i128` is valid.
103        // Size and alignment are enforced by the compiler. There is no implicit padding in
104        // either `Timestamp` or `i128`.
105        unsafe { core::mem::transmute(self) }
106    }
107
108    /// A `Timestamp` representing the Unix epoch (1970-01-01 00:00:00 UTC).
109    pub const UNIX_EPOCH: Self =
110        Self::new_ranged(Seconds::new_static::<0>(), Nanoseconds::new_static::<0>());
111
112    /// The minimum valid `Timestamp`.
113    ///
114    /// The moment in time represented by this value may vary depending on the feature flags
115    /// enabled.
116    pub const MIN: Self = Self::new_ranged(Seconds::MIN, Nanoseconds::MIN);
117
118    /// The maximum valid `Timestamp`.
119    ///
120    /// The moment in time represented by this value may vary depending on the feature flags
121    /// enabled.
122    pub const MAX: Self = Self::new_ranged(Seconds::MAX, Nanoseconds::MAX);
123
124    /// Create a new `Timestamp` representing the current moment in time.
125    ///
126    /// ```rust
127    /// # use time::Timestamp;
128    /// assert!(Timestamp::now().year() >= 2019);
129    /// ```
130    #[cfg(feature = "std")]
131    #[inline]
132    pub fn now() -> Self {
133        SystemTime::now().into()
134    }
135
136    /// Create a `Timestamp` from the provided seconds and nanoseconds values without checking if
137    /// they are valid.
138    ///
139    /// # Safety
140    ///
141    /// Both `seconds` and `nanoseconds` must be in range.
142    #[doc(hidden)]
143    #[inline]
144    #[track_caller]
145    pub const unsafe fn __new_unchecked(seconds: i64, nanoseconds: u32) -> Self {
146        // Safety: The caller must ensure both values are valid.
147        unsafe {
148            Self::new_ranged(
149                Seconds::new_unchecked(seconds),
150                Nanoseconds::new_unchecked(nanoseconds),
151            )
152        }
153    }
154
155    /// Create a `Timestamp` from the provided seconds and nanoseconds values that are known to be
156    /// in range.
157    #[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    /// Create a `Timestamp` from the provided Unix timestamp in seconds and nanoseconds, returning
167    /// an error if the resulting value is out of range.
168    ///
169    /// ```rust
170    /// # use time::Timestamp;
171    /// assert!(Timestamp::new(0, 0).is_ok());
172    /// assert!(Timestamp::new(i64::MAX, 0).is_err());
173    /// ```
174    #[inline]
175    pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Self, error::ComponentRange> {
176        Ok(Self::new_ranged(
177            ensure_ranged!(Seconds: seconds),
178            ensure_ranged!(Nanoseconds: nanoseconds),
179        ))
180    }
181
182    /// Create a `Timestamp` from the provided Unix timestamp in seconds, returning an error if the
183    /// resulting value is out of range.
184    ///
185    /// ```rust
186    /// # use time::Timestamp;
187    /// assert!(Timestamp::from_seconds(0).is_ok());
188    /// assert!(Timestamp::from_seconds(i64::MAX).is_err());
189    /// ```
190    #[inline]
191    pub const fn from_seconds(seconds: i64) -> Result<Self, error::ComponentRange> {
192        Ok(Self::new_ranged(
193            ensure_ranged!(Seconds: seconds),
194            Nanoseconds::new_static::<0>(),
195        ))
196    }
197
198    /// Create a `Timestamp` from the provided Unix timestamp in milliseconds, returning an error if
199    /// the resulting value is out of range.
200    ///
201    /// ```rust
202    /// # use time::Timestamp;
203    /// assert!(Timestamp::from_milliseconds(0).is_ok());
204    /// assert!(Timestamp::from_milliseconds(i64::MAX).is_err());
205    /// ```
206    #[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        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        // Safety: The value provided was checked to be in range.
224        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
225    }
226
227    /// Create a `Timestamp` from the provided Unix timestamp in microseconds, returning an error if
228    /// the resulting value is out of range.
229    ///
230    /// ```rust
231    /// # use time::Timestamp;
232    /// assert!(Timestamp::from_microseconds(0).is_ok());
233    /// assert!(Timestamp::from_microseconds(i128::MAX).is_err());
234    /// ```
235    #[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        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        // Safety: The value provided was checked to be in range.
253        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
254    }
255
256    /// Create a `Timestamp` from the provided Unix timestamp in nanoseconds, returning an error if
257    /// the resulting value is out of range.
258    ///
259    /// ```rust
260    /// # use time::Timestamp;
261    /// assert!(Timestamp::from_nanoseconds(0).is_ok());
262    /// assert!(Timestamp::from_nanoseconds(i128::MAX).is_err());
263    /// ```
264    #[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        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        // Safety: The value provided was checked to be in range.
282        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
283    }
284
285    /// Convert the `Timestamp` to an [`OffsetDateTime`] at the provided offset.
286    ///
287    /// ```rust
288    /// # use time_macros::{offset, timestamp};
289    /// assert_eq!(timestamp!(1_546_398_245).to_offset(offset!(+1)).hour(), 4);
290    /// ```
291    ///
292    /// # Panics
293    ///
294    /// This panics if the resulting date-time with the provided offset is outside the supported
295    /// range. Consider using [`checked_to_offset`](Self::checked_to_offset) for a non-panicking
296    /// alternative.
297    #[inline]
298    pub const fn to_offset(self, offset: UtcOffset) -> OffsetDateTime {
299        self.to_utc().to_offset(offset)
300    }
301
302    /// Convert the `Timestamp` to an [`OffsetDateTime`] with the provided offset, returning `None`
303    /// if the resulting value is out of range.
304    ///
305    /// ```rust
306    /// # use time_macros::{offset, timestamp};
307    /// assert!(
308    ///     timestamp!(1_546_398_245)
309    ///         .checked_to_offset(offset!(+1))
310    ///         .is_some()
311    /// );
312    /// ```
313    #[inline]
314    pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<OffsetDateTime> {
315        self.to_utc().checked_to_offset(offset)
316    }
317
318    /// Convert the `Timestamp` to a [`UtcDateTime`].
319    ///
320    /// ```rust
321    /// # use time_macros::{timestamp, utc_datetime};
322    /// assert_eq!(timestamp!(1_546_398_245).to_utc(), utc_datetime!(2019-01-02 3:04:05));
323    /// ```
324    #[inline]
325    pub const fn to_utc(self) -> UtcDateTime {
326        let Ok(utc_dt) = UtcDateTime::from_unix_timestamp(self.seconds.get()) else {
327            bug!("timestamp was invalid beforehand");
328        };
329        let Ok(utc_dt) = utc_dt.replace_nanosecond(self.nanoseconds.get()) else {
330            bug!("nanosecond was invalid beforehand");
331        };
332
333        utc_dt
334    }
335
336    /// Get the seconds and nanoseconds of the timestamp as ranged values.
337    #[inline]
338    pub(crate) const fn as_parts_ranged(self) -> (Seconds, Nanoseconds) {
339        (self.seconds, self.nanoseconds)
340    }
341
342    /// Get the number of seconds since the Unix epoch.
343    ///
344    /// Negative values represent moments before the Unix epoch.
345    ///
346    /// ```rust
347    /// # use time_macros::timestamp;
348    /// assert_eq!(timestamp!(1_546_398_245).as_seconds(), 1_546_398_245);
349    /// ```
350    #[inline]
351    pub const fn as_seconds(self) -> i64 {
352        self.seconds.get()
353    }
354
355    /// Get the number of milliseconds since the Unix epoch.
356    ///
357    /// Negative values represent moments before the Unix epoch.
358    ///
359    /// ```rust
360    /// # use time_macros::timestamp;
361    /// assert_eq!(
362    ///     timestamp!(1_546_398_245.006).as_milliseconds(),
363    ///     1_546_398_245_006
364    /// );
365    /// ```
366    #[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    /// Get the number of microseconds since the Unix epoch.
373    ///
374    /// Negative values represent moments before the Unix epoch.
375    ///
376    /// ```rust
377    /// # use time_macros::timestamp;
378    /// assert_eq!(
379    ///     timestamp!(1_546_398_245.006_007).as_microseconds(),
380    ///     1_546_398_245_006_007
381    /// );
382    /// ```
383    #[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    /// Get the number of nanoseconds since the Unix epoch.
390    ///
391    /// Negative values represent moments before the Unix epoch.
392    ///
393    /// ```rust
394    /// # use time_macros::timestamp;
395    /// assert_eq!(
396    ///     timestamp!(1_546_398_245.006_007_008).as_nanoseconds(),
397    ///     1_546_398_245_006_007_008
398    /// );
399    /// ```
400    #[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    /// Get the [`Date`] of the timestamp in UTC.
407    ///
408    /// ```rust
409    /// # use time_macros::{date, timestamp};
410    /// assert_eq!(timestamp!(1_546_398_245).date(), date!(2019-01-02));
411    /// ```
412    #[inline]
413    pub const fn date(self) -> Date {
414        self.to_utc().date()
415    }
416
417    /// Get the [`Time`] of the timestamp in UTC.
418    ///
419    /// ```rust
420    /// # use time_macros::{time, timestamp};
421    /// assert_eq!(timestamp!(1_546_398_245).time(), time!(3:04:05));
422    /// ```
423    #[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        // Safety: All values are guaranteed to be in range.
434        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    /// Compute the year, leap year status, and ordinal day of the timestamp in UTC.
445    ///
446    /// This algorithm is essentially identical to `Date::from_julian_day_unchecked`. Instead of
447    /// returning `Date`, it returns the components as a tuple. By not bitpacking the values, it
448    /// allows the compiler to see through the function boundary and better optimize methods.
449    #[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 = 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    /// Get the year of the timestamp in UTC.
479    ///
480    /// ```rust
481    /// # use time_macros::timestamp;
482    /// assert_eq!(timestamp!(1_546_398_245).year(), 2019);
483    /// ```
484    #[inline]
485    pub const fn year(self) -> i32 {
486        self.year_leap_ordinal().0
487    }
488
489    /// Get the month of the timestamp in UTC.
490    ///
491    /// ```rust
492    /// # use time::Month;
493    /// # use time_macros::timestamp;
494    /// assert_eq!(timestamp!(1_546_398_245).month(), Month::January);
495    /// ```
496    #[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    /// Get the day of the month of the timestamp in UTC.
503    ///
504    /// The returned value will always be in the range `1..=31`.
505    ///
506    /// ```rust
507    /// # use time_macros::timestamp;
508    /// assert_eq!(timestamp!(1_546_398_245).day(), 2);
509    /// ```
510    #[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    /// Get the day of the year of the timestamp in UTC.
517    ///
518    /// The returned value will always be in the range `1..=366`.
519    ///
520    /// ```rust
521    /// # use time_macros::timestamp;
522    /// assert_eq!(timestamp!(1_546_398_245).ordinal(), 2);
523    /// ```
524    #[inline]
525    pub const fn ordinal(self) -> u16 {
526        self.year_leap_ordinal().2
527    }
528
529    /// Get the ISO week number of the timestamp in UTC.
530    ///
531    /// The returned value will always be in the range `1..=53`.
532    ///
533    /// ```rust
534    /// # use time_macros::timestamp;
535    /// assert_eq!(timestamp!(1_546_398_245).iso_week(), 1);
536    /// ```
537    #[inline]
538    pub const fn iso_week(self) -> u8 {
539        self.date().iso_week()
540    }
541
542    /// Get the Sunday-based week number of the timestamp in UTC.
543    ///
544    /// The returned value will always be in the range `0..=53`.
545    #[inline]
546    pub const fn sunday_based_week(self) -> u8 {
547        self.date().sunday_based_week()
548    }
549
550    /// Get the Monday-based week number of the timestamp in UTC.
551    ///
552    /// The returned value will always be in the range `0..=53`.
553    #[inline]
554    pub const fn monday_based_week(self) -> u8 {
555        self.date().monday_based_week()
556    }
557
558    /// Get the calendar date (year, month, day) of the timestamp in UTC.
559    ///
560    /// ```rust
561    /// # use time::Month;
562    /// # use time_macros::timestamp;
563    /// assert_eq!(
564    ///     timestamp!(1_546_398_245).to_calendar_date(),
565    ///     (2019, Month::January, 2)
566    /// );
567    /// ```
568    #[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    /// Get the ordinal date (year, ordinal day) of the timestamp in UTC.
576    ///
577    /// ```rust
578    /// # use time_macros::timestamp;
579    /// assert_eq!(timestamp!(1_546_398_245).to_ordinal_date(), (2019, 2));
580    /// ```
581    #[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    /// Get the ISO week date (year, week number, weekday) of the timestamp in UTC.
588    ///
589    /// ```rust
590    /// # use time::Weekday;
591    /// # use time_macros::timestamp;
592    /// assert_eq!(
593    ///     timestamp!(1_546_398_245).to_iso_week_date(),
594    ///     (2019, 1, Weekday::Wednesday)
595    /// );
596    /// ```
597    #[inline]
598    pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
599        self.date().to_iso_week_date()
600    }
601
602    /// Get the weekday of the timestamp in UTC.
603    ///
604    /// ```rust
605    /// # use time::Weekday;
606    /// # use time_macros::timestamp;
607    /// assert_eq!(timestamp!(1_546_398_245).weekday(), Weekday::Wednesday);
608    /// ```
609    #[inline]
610    pub const fn weekday(self) -> Weekday {
611        // 365,961,669 is obtained by starting with the smallest timestamp (with large-dates
612        // enabled), dividing by 86,400 to get the number of days, then rounding down to get a
613        // multiple of 7. This value is negated as we want to end with a positive number. Finally, 3
614        // is added to shift the zero value to Monday, matching the internal representation of
615        // `Weekday`.
616        match (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            _ => unreachable!(),
625        }
626    }
627
628    /// Get the Julian day of the timestamp.
629    #[inline]
630    pub const fn to_julian_day(self) -> i32 {
631        const UNIX_EPOCH_JULIAN_DAY: i32 = Date::UNIX_EPOCH.to_julian_day();
632        div_floor!(self.seconds.get(), 86_400) as i32 + UNIX_EPOCH_JULIAN_DAY
633    }
634
635    /// Get the hours, minutes, and seconds of the timestamp in UTC.
636    ///
637    /// ```rust
638    /// # use time_macros::timestamp;
639    /// assert_eq!(timestamp!(1_546_398_245).as_hms(), (3, 4, 5));
640    /// ```
641    #[inline]
642    pub const fn as_hms(self) -> (u8, u8, u8) {
643        self.time().as_hms()
644    }
645
646    /// Get the hours, minutes, seconds, and milliseconds of the timestamp in UTC.
647    ///
648    /// ```rust
649    /// # use time_macros::timestamp;
650    /// assert_eq!(timestamp!(1_546_398_245.006).as_hms_milli(), (3, 4, 5, 6));
651    /// ```
652    #[inline]
653    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
654        self.time().as_hms_milli()
655    }
656
657    /// Get the hours, minutes, seconds, and microseconds of the timestamp in UTC.
658    ///
659    /// ```rust
660    /// # use time_macros::timestamp;
661    /// assert_eq!(
662    ///     timestamp!(1_546_398_245.006_007).as_hms_micro(),
663    ///     (3, 4, 5, 6_007)
664    /// );
665    /// ```
666    #[inline]
667    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
668        self.time().as_hms_micro()
669    }
670
671    /// Get the hours, minutes, seconds, and nanoseconds of the timestamp in UTC.
672    ///
673    /// ```rust
674    /// # use time_macros::timestamp;
675    /// assert_eq!(
676    ///     timestamp!(1_546_398_245.006_007_008).as_hms_nano(),
677    ///     (3, 4, 5, 6_007_008)
678    /// );
679    /// ```
680    #[inline]
681    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
682        self.time().as_hms_nano()
683    }
684
685    /// Get the hour of the timestamp in UTC.
686    ///
687    /// ```rust
688    /// # use time_macros::timestamp;
689    /// assert_eq!(timestamp!(1_546_398_245).hour(), 3);
690    /// ```
691    #[inline]
692    pub const fn hour(self) -> u8 {
693        self.time().hour()
694    }
695
696    /// Get the minute of the timestamp in UTC.
697    ///
698    /// ```rust
699    /// # use time_macros::timestamp;
700    /// assert_eq!(timestamp!(1_546_398_245).minute(), 4);
701    /// ```
702    #[inline]
703    pub const fn minute(self) -> u8 {
704        (div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute)))
705            .rem_euclid(Minute::per_t(Hour)) as u8
706    }
707
708    /// Get the second of the timestamp in UTC.
709    ///
710    /// ```rust
711    /// # use time_macros::timestamp;
712    /// assert_eq!(timestamp!(1_546_398_245).second(), 5);
713    /// ```
714    #[inline]
715    pub const fn second(self) -> u8 {
716        self.seconds.get().rem_euclid(Second::per_t(Minute)) as u8
717    }
718
719    /// Get the millisecond of the timestamp in UTC.
720    ///
721    /// ```rust
722    /// # use time_macros::timestamp;
723    /// assert_eq!(timestamp!(1_546_398_245.006).millisecond(), 6);
724    /// ```
725    #[inline]
726    pub const fn millisecond(self) -> u16 {
727        (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
728    }
729
730    /// Get the microsecond of the timestamp in UTC.
731    ///
732    /// ```rust
733    /// # use time_macros::timestamp;
734    /// assert_eq!(timestamp!(1_546_398_245.006_007).microsecond(), 6_007);
735    /// ```
736    #[inline]
737    pub const fn microsecond(self) -> u32 {
738        self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)
739    }
740
741    /// Get the nanosecond of the timestamp in UTC.
742    ///
743    /// ```rust
744    /// # use time_macros::timestamp;
745    /// assert_eq!(
746    ///     timestamp!(1_546_398_245.006_007_008).nanosecond(),
747    ///     6_007_008
748    /// );
749    /// ```
750    #[inline]
751    pub const fn nanosecond(self) -> u32 {
752        self.nanoseconds.get()
753    }
754
755    /// Add a [`Duration`] to the timestamp. Returns `Overflow::Positive` or `Overflow::Negative` if
756    /// the result is out of range.
757    #[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        // Check if the resulting seconds are within the valid range
787        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        // Safety: Both values are guaranteed to be in range.
794        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
795    }
796
797    /// Subtract a [`Duration`] from the timestamp. Returns `Overflow::Positive` or
798    /// `Overflow::Negative` if the result is out of range.
799    #[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        // Check if the resulting seconds are within the valid range
830        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        // Safety: Both values are guaranteed to be in range.
837        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
838    }
839
840    /// Add a [`std::time::Duration`] to the timestamp. Returns `Overflow::Positive` or
841    /// `Overflow::Negative` if the result is out of range.
842    #[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        // Check if the resulting seconds are within the valid range
858        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        // Safety: Both values are guaranteed to be in range.
865        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
866    }
867
868    /// Subtract a [`std::time::Duration`] from the timestamp. Returns `Overflow::Positive` or
869    /// `Overflow::Negative` if the result is out of range.
870    #[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        // Check if the resulting seconds are within the valid range
886        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        // Safety: Both values are guaranteed to be in range.
893        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds as u32) })
894    }
895
896    /// Checked addition of a [`Duration`], returning `None` if the result is out of range.
897    ///
898    /// ```rust
899    /// # use time_macros::timestamp;
900    /// # use time::ext::NumericalDuration as _;
901    /// assert_eq!(
902    ///     timestamp!(1_546_398_245).checked_add(1.days()),
903    ///     Some(timestamp!(1_546_484_645))
904    /// );
905    /// assert_eq!(
906    ///     timestamp!(1_546_398_245).checked_add((-1).days()),
907    ///     Some(timestamp!(1_546_311_845))
908    /// );
909    /// ```
910    #[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    /// Checked subtraction of a [`Duration`], returning `None` if the result is out of range.
919    ///
920    /// ```rust
921    /// # use time_macros::timestamp;
922    /// # use time::ext::NumericalDuration as _;
923    /// assert_eq!(
924    ///     timestamp!(1_546_398_245).checked_sub(1.days()),
925    ///     Some(timestamp!(1_546_311_845))
926    /// );
927    /// assert_eq!(
928    ///     timestamp!(1_546_398_245).checked_sub((-1).days()),
929    ///     Some(timestamp!(1_546_484_645))
930    /// );
931    /// ```
932    #[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    /// Saturating addition of a [`Duration`].
941    ///
942    /// Returns [`Timestamp::MAX`] or [`Timestamp::MIN`] if the result is out of range.
943    ///
944    /// ```rust
945    /// # use time::Timestamp;
946    /// # use time_macros::timestamp;
947    /// # use time::ext::NumericalDuration as _;
948    /// assert_eq!(
949    ///     timestamp!(1_546_398_245).saturating_add(1.days()),
950    ///     timestamp!(1_546_484_645)
951    /// );
952    /// assert_eq!(Timestamp::MAX.saturating_add(1.days()), Timestamp::MAX);
953    /// assert_eq!(Timestamp::MIN.saturating_add((-1).days()), Timestamp::MIN);
954    /// ```
955    #[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    /// Saturating subtraction of a [`Duration`].
965    ///
966    /// Returns [`Timestamp::MAX`] or [`Timestamp::MIN`] if the result is out of range.
967    ///
968    /// ```rust
969    /// # use time::Timestamp;
970    /// # use time_macros::timestamp;
971    /// # use time::ext::NumericalDuration as _;
972    /// assert_eq!(
973    ///     timestamp!(1_546_398_245).saturating_sub(1.days()),
974    ///     timestamp!(1_546_311_845)
975    /// );
976    /// assert_eq!(Timestamp::MIN.saturating_sub(1.days()), Timestamp::MIN);
977    /// assert_eq!(Timestamp::MAX.saturating_sub((-1).days()), Timestamp::MAX);
978    /// ```
979    #[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
989/// Methods that replace part of the `Timestamp`.
990impl Timestamp {
991    /// Replace the time, preserving the date.
992    ///
993    /// ```rust
994    /// # use time_macros::{time, timestamp};
995    /// assert_eq!(
996    ///     timestamp!(1_546_398_245).replace_time(time!(12:34:56)),
997    ///     timestamp!(1_546_432_496)
998    /// );
999    /// ```
1000    #[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 = div_floor!(self.seconds.get(), Second::per_t::<i64>(Day))
1007            * Second::per_t::<i64>(Day)
1008            + seconds_since_midnight;
1009        // Safety: Seconds is constructed from an existing valid value, and nanoseconds are always
1010        // in range given the origin. Any time of day is valid for any date in range, as enforced by
1011        // const assertions.
1012        unsafe { Self::__new_unchecked(seconds, time.nanosecond()) }
1013    }
1014
1015    /// Replace the date, preserving the time.
1016    ///
1017    /// ```rust
1018    /// # use time_macros::{date, timestamp};
1019    /// assert_eq!(
1020    ///     timestamp!(1_546_398_245).replace_date(date!(2020-01-02)),
1021    ///     timestamp!(1_577_934_245)
1022    /// );
1023    /// ```
1024    #[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        // Safety: The range of valid dates is identical to the range of valid timestamps, so any
1033        // date is necessarily valid.
1034        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1035        self
1036    }
1037
1038    /// Replace the year, preserving the month and day. If the date is February 29 and the resulting
1039    /// year is not a leap year, an error is returned.
1040    ///
1041    /// ```rust
1042    /// # use time_macros::timestamp;
1043    /// assert_eq!(
1044    ///     timestamp!(1_546_398_245).replace_year(2020),
1045    ///     Ok(timestamp!(1_577_934_245))
1046    /// );
1047    /// assert!(timestamp!(1_546_398_245).replace_year(-1_000_000).is_err()); // -1_000_000 isn't a valid year
1048    /// assert!(timestamp!(1_546_398_245).replace_year(1_000_000).is_err()); // 1_000_000 isn't a valid year
1049    /// ```
1050    #[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 = const_try!(self.date().replace_year(year));
1054        Ok(self.replace_date(date))
1055    }
1056
1057    /// Replace the month of the year, preserving the year and day. If the day is invalid for the
1058    /// resulting month, an error is returned.
1059    ///
1060    /// ```rust
1061    /// # use time_macros::timestamp;
1062    /// # use time::Month;
1063    /// assert_eq!(
1064    ///     timestamp!(1_546_398_245).replace_month(Month::February),
1065    ///     Ok(timestamp!(1_549_076_645))
1066    /// );
1067    /// assert!(
1068    ///     timestamp!(1_548_817_445)
1069    ///         .replace_month(Month::February)
1070    ///         .is_err()
1071    /// ); // the day of the month is 30, which is invalid for February
1072    /// ```
1073    #[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 = const_try!(self.date().replace_month(month));
1077        Ok(self.replace_date(date))
1078    }
1079
1080    /// Replace the day of the month.
1081    ///
1082    /// ```rust
1083    /// # use time_macros::timestamp;
1084    /// assert_eq!(
1085    ///     timestamp!(1_546_398_245).replace_day(1),
1086    ///     Ok(timestamp!(1_546_311_845))
1087    /// );
1088    /// assert!(timestamp!(1_546_398_245).replace_day(0).is_err()); // 00 isn't a valid day
1089    /// assert!(timestamp!(1_546_398_245).replace_day(32).is_err()); // 32 isn't a valid day
1090    /// ```
1091    #[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 = const_try!(self.date().replace_day(day));
1095        Ok(self.replace_date(date))
1096    }
1097
1098    /// Replace the day of the year.
1099    ///
1100    /// ```rust
1101    /// # use time_macros::timestamp;
1102    /// assert_eq!(
1103    ///     timestamp!(1_546_398_245).replace_ordinal(1),
1104    ///     Ok(timestamp!(1_546_311_845))
1105    /// );
1106    /// assert!(timestamp!(1_546_398_245).replace_ordinal(0).is_err()); // 0 isn't a valid day of the year
1107    /// assert!(timestamp!(1_546_398_245).replace_ordinal(366).is_err()); // the timestamp is in 2019, which isn't a leap year
1108    /// ```
1109    #[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 = const_try!(self.date().replace_ordinal(ordinal));
1113        Ok(self.replace_date(date))
1114    }
1115
1116    /// Replace the clock hour.
1117    ///
1118    /// ```rust
1119    /// # use time_macros::timestamp;
1120    /// assert_eq!(
1121    ///     timestamp!(1_546_398_245).replace_hour(0),
1122    ///     Ok(timestamp!(1_546_387_445))
1123    /// );
1124    /// assert!(timestamp!(1_546_398_245).replace_hour(24).is_err()); // 24 isn't a valid hour
1125    /// ```
1126    #[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        ensure_ranged!(ru8<0, 23>: hour);
1130        let seconds = 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        // Safety: Any value is valid so long as `hour` is in range.
1136        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1137        Ok(self)
1138    }
1139
1140    /// Replace the minutes within the hour.
1141    ///
1142    /// ```rust
1143    /// # use time_macros::timestamp;
1144    /// assert_eq!(
1145    ///     timestamp!(1_546_398_245).replace_minute(0),
1146    ///     Ok(timestamp!(1_546_398_005))
1147    /// );
1148    /// assert!(timestamp!(1_546_398_245).replace_minute(60).is_err()); // 60 isn't a valid minute
1149    /// ```
1150    #[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        ensure_ranged!(ru8<0, 59>: minute);
1154        let seconds = 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        // Safety: Any value is valid so long as `minute` is in range.
1159        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1160        Ok(self)
1161    }
1162
1163    /// Replace the seconds within the minute.
1164    ///
1165    /// ```rust
1166    /// # use time_macros::timestamp;
1167    /// assert_eq!(
1168    ///     timestamp!(1_546_398_245).replace_second(0),
1169    ///     Ok(timestamp!(1_546_398_240))
1170    /// );
1171    /// assert!(timestamp!(1_546_398_245).replace_second(60).is_err()); // 60 isn't a valid second
1172    /// ```
1173    #[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        ensure_ranged!(ru8<0, 59>: second);
1177        let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute))
1178            * Second::per_t::<i64>(Minute)
1179            + second as i64;
1180        // Safety: Any value is valid so long as `second` is in range.
1181        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1182        Ok(self)
1183    }
1184
1185    /// Replace the milliseconds within the second.
1186    ///
1187    /// ```rust
1188    /// # use time_macros::timestamp;
1189    /// assert_eq!(
1190    ///     timestamp!(1_546_398_245.006).replace_millisecond(7),
1191    ///     Ok(timestamp!(1_546_398_245.007))
1192    /// );
1193    /// assert!(
1194    ///     timestamp!(1_546_398_245.006)
1195    ///         .replace_millisecond(1_000)
1196    ///         .is_err()
1197    /// ); // 1_000 isn't a valid millisecond
1198    /// ```
1199    #[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            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
1207        Ok(self.replace_nanosecond_ranged(nanos))
1208    }
1209
1210    /// Replace the microseconds within the second.
1211    ///
1212    /// ```rust
1213    /// # use time_macros::timestamp;
1214    /// assert_eq!(
1215    ///     timestamp!(1_546_398_245.006_007).replace_microsecond(123_456),
1216    ///     Ok(timestamp!(1_546_398_245.123_456))
1217    /// );
1218    /// assert!(
1219    ///     timestamp!(1_546_398_245.006_007)
1220    ///         .replace_microsecond(1_000_000)
1221    ///         .is_err()
1222    /// ); // 1_000_000 isn't a valid microsecond
1223    /// ```
1224    #[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            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
1232        Ok(self.replace_nanosecond_ranged(nanos))
1233    }
1234
1235    /// Replace the nanoseconds within the second.
1236    ///
1237    /// ```rust
1238    /// # use time_macros::timestamp;
1239    /// assert_eq!(
1240    ///     timestamp!(1_546_398_245.006_007_008).replace_nanosecond(123_456_789),
1241    ///     Ok(timestamp!(1_546_398_245.123_456_789))
1242    /// );
1243    /// assert!(
1244    ///     timestamp!(1_546_398_245.006_007_008)
1245    ///         .replace_nanosecond(1_000_000_000)
1246    ///         .is_err()
1247    /// ); // 1_000_000_000 isn't a valid nanosecond
1248    /// ```
1249    #[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 = ensure_ranged!(Nanoseconds: nanosecond);
1253        Ok(self.replace_nanosecond_ranged(nanos))
1254    }
1255
1256    /// Replace the nanoseconds within the second using a range-bounded integer to avoid range
1257    /// checks.
1258    #[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            // Safety: The previous conditional guarantees that `seconds` is negative (if it were
1266            // non-negative, we wouldn't be in this branch). Given that the maximum value is
1267            // positive, we can always add one without exceeding the maximum.
1268            Self::new_ranged(unsafe { seconds.unchecked_add(1) }, new_nanos)
1269        } else {
1270            // Safety: Given the range of `new_nanos`, subtracting it from the maximum always
1271            // results in a value in range. Zero is excluded by a previous conditional.
1272            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    /// Format the `Timestamp` using the provided [format description](crate::format_description).
1282    #[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    /// Format the `Timestamp` using the provided [format description](crate::format_description).
1292    ///
1293    /// ```rust
1294    /// # use time_macros::{format_description, timestamp};
1295    /// let format = format_description!("[unix_timestamp]");
1296    /// assert_eq!(timestamp!(1_546_398_245).format(&format)?, "1546398245");
1297    /// # Ok::<_, time::Error>(())
1298    /// ```
1299    #[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    /// Parse a `Timestamp` from the input using the provided [format
1308    /// description](crate::format_description).
1309    ///
1310    /// ```rust
1311    /// # use time::Timestamp;
1312    /// # use time_macros::{format_description, timestamp};
1313    /// let format = format_description!("[unix_timestamp]");
1314    /// assert_eq!(
1315    ///     Timestamp::parse("1546398245", &format)?,
1316    ///     timestamp!(1_546_398_245),
1317    /// );
1318    /// # Ok::<_, time::Error>(())
1319    /// ```
1320    #[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    /// The maximum number of bytes that the `fmt_into_buffer` method will write, which is also used
1331    /// by the `Display` implementation.
1332    const DISPLAY_BUFFER_SIZE: usize = 25;
1333
1334    /// Format the `Timestamp` into the provided buffer, returning the number of bytes written.
1335    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                // Safety: `nanosecond` is in the range 1..=999_999_999, so subtracting it from
1353                // 1_000_000_000 will always yield a value in the range 1..=999_999_999, which is a
1354                // subset of the valid range for `Nanoseconds`.
1355                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        // Safety: `buf` has sufficient capacity for the seconds digits.
1364        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            // Safety: `buf` has sufficient capacity for the subsecond digits.
1377            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        // Safety: All bytes up to `len` have been initialized with ASCII characters.
1395        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    /// # Panics
1411    ///
1412    /// This may panic if an overflow occurs.
1413    #[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    /// # Panics
1425    ///
1426    /// This may panic if an overflow occurs.
1427    #[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    /// # Panics
1436    ///
1437    /// This may panic if an overflow occurs.
1438    #[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    /// # Panics
1447    ///
1448    /// This may panic if an overflow occurs.
1449    #[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    /// # Panics
1460    ///
1461    /// This may panic if an overflow occurs.
1462    #[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    /// # Panics
1474    ///
1475    /// This may panic if an overflow occurs.
1476    #[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    /// # Panics
1485    ///
1486    /// This may panic if an overflow occurs.
1487    #[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    /// # Panics
1496    ///
1497    /// This may panic if an overflow occurs.
1498    #[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}