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, Month, OffsetDateTime, SignedDuration, Time, UtcDateTime, UtcOffset, Weekday, error, util,
30};
31
32/// The range of valid seconds for a [`Timestamp`].
33pub(crate) type Seconds =
34    ri64<{ UtcDateTime::MIN.unix_timestamp() }, { UtcDateTime::MAX.unix_timestamp() }>;
35type Nanoseconds = ru32<0, 999_999_999>;
36
37// Validate that the minimum time is midnight and the maximum is one nanosecond before midnight.
38// This is necessary because the soundness of some functions relies on this fact.
39const _: () = {
40    assert!(Timestamp::MIN.time().as_u64() == Time::MIDNIGHT.as_u64());
41    assert!(Timestamp::MAX.time().as_u64() == Time::MAX.as_u64());
42};
43
44/// By explicitly inserting this enum where padding is expected, the compiler is able to better
45/// perform niche value optimization.
46#[repr(u32)]
47#[derive(Clone, Copy, PartialEq, Eq)]
48enum Padding {
49    #[allow(clippy::missing_docs_in_private_items)]
50    Optimize,
51}
52
53/// A Unix timestamp with nanosecond precision.
54///
55/// This type represents a point in time as a number of seconds and nanoseconds elapsed since the
56/// Unix epoch (1970-01-01 00:00:00 UTC). Negative values represent times before the Unix epoch.
57#[derive(Clone, Copy, Eq)]
58#[cfg_attr(not(docsrs), repr(C))]
59pub struct Timestamp {
60    #[cfg(target_endian = "big")]
61    seconds: Seconds,
62    #[cfg(target_endian = "big")]
63    nanoseconds: Nanoseconds,
64    #[cfg(target_endian = "big")]
65    padding: Padding,
66
67    #[cfg(target_endian = "little")]
68    padding: Padding,
69    #[cfg(target_endian = "little")]
70    nanoseconds: Nanoseconds,
71    #[cfg(target_endian = "little")]
72    seconds: Seconds,
73}
74
75impl Hash for Timestamp {
76    #[inline]
77    fn hash<H: Hasher>(&self, state: &mut H) {
78        state.write_i128(self.as_i128());
79    }
80}
81
82impl PartialEq for Timestamp {
83    #[inline]
84    fn eq(&self, other: &Self) -> bool {
85        self.as_i128() == other.as_i128()
86    }
87}
88
89impl PartialOrd for Timestamp {
90    #[inline]
91    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
92        Some(self.cmp(other))
93    }
94}
95
96impl Ord for Timestamp {
97    #[inline]
98    fn cmp(&self, other: &Self) -> Ordering {
99        self.as_i128().cmp(&other.as_i128())
100    }
101}
102
103impl Timestamp {
104    #[inline]
105    const fn as_i128(self) -> i128 {
106        // Safety: `self` is presumed valid because it exists, and any value of `i128` is valid.
107        // Size and alignment are enforced by the compiler. There is no implicit padding in
108        // either `Timestamp` or `i128`.
109        unsafe { core::mem::transmute(self) }
110    }
111
112    /// A `Timestamp` representing the Unix epoch (1970-01-01 00:00:00 UTC).
113    pub const UNIX_EPOCH: Self =
114        Self::new_ranged(Seconds::new_static::<0>(), Nanoseconds::new_static::<0>());
115
116    /// The minimum valid `Timestamp`.
117    ///
118    /// The moment in time represented by this value may vary depending on the feature flags
119    /// enabled.
120    pub const MIN: Self = Self::new_ranged(Seconds::MIN, Nanoseconds::MIN);
121
122    /// The maximum valid `Timestamp`.
123    ///
124    /// The moment in time represented by this value may vary depending on the feature flags
125    /// enabled.
126    pub const MAX: Self = Self::new_ranged(Seconds::MAX, Nanoseconds::MAX);
127
128    /// Create a new `Timestamp` representing the current moment in time.
129    ///
130    /// ```rust
131    /// # use time::Timestamp;
132    /// assert!(Timestamp::now().year() >= 2019);
133    /// ```
134    #[cfg(feature = "std")]
135    #[inline]
136    pub fn now() -> Self {
137        SystemTime::now().into()
138    }
139
140    /// Create a `Timestamp` from the provided seconds and nanoseconds values without checking if
141    /// they are valid.
142    ///
143    /// # Safety
144    ///
145    /// Both `seconds` and `nanoseconds` must be in range.
146    #[doc(hidden)]
147    #[inline]
148    #[track_caller]
149    pub const unsafe fn __new_unchecked(seconds: i64, nanoseconds: u32) -> Self {
150        // Safety: The caller must ensure both values are valid.
151        unsafe {
152            Self::new_ranged(
153                Seconds::new_unchecked(seconds),
154                Nanoseconds::new_unchecked(nanoseconds),
155            )
156        }
157    }
158
159    /// Create a `Timestamp` from the provided seconds and nanoseconds values that are known to be
160    /// in range.
161    #[inline]
162    pub(crate) const fn new_ranged(seconds: Seconds, nanoseconds: Nanoseconds) -> Self {
163        Self {
164            seconds,
165            nanoseconds,
166            padding: Padding::Optimize,
167        }
168    }
169
170    /// Create a `Timestamp` from the provided Unix timestamp in seconds and nanoseconds, returning
171    /// an error if the resulting value is out of range.
172    ///
173    /// ```rust
174    /// # use time::Timestamp;
175    /// assert!(Timestamp::new(0, 0).is_ok());
176    /// assert!(Timestamp::new(i64::MAX, 0).is_err());
177    /// ```
178    #[inline]
179    pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Self, error::ComponentRange> {
180        Ok(Self::new_ranged(
181            ensure_ranged!(Seconds: seconds),
182            ensure_ranged!(Nanoseconds: nanoseconds),
183        ))
184    }
185
186    /// Create a `Timestamp` from the provided Unix timestamp in seconds, returning an error if the
187    /// resulting value is out of range.
188    ///
189    /// ```rust
190    /// # use time::Timestamp;
191    /// assert!(Timestamp::from_seconds(0).is_ok());
192    /// assert!(Timestamp::from_seconds(i64::MAX).is_err());
193    /// ```
194    #[inline]
195    pub const fn from_seconds(seconds: i64) -> Result<Self, error::ComponentRange> {
196        Ok(Self::new_ranged(
197            ensure_ranged!(Seconds: seconds),
198            Nanoseconds::new_static::<0>(),
199        ))
200    }
201
202    /// Create a `Timestamp` from the provided Unix timestamp in milliseconds, returning an error if
203    /// the resulting value is out of range.
204    ///
205    /// ```rust
206    /// # use time::Timestamp;
207    /// assert!(Timestamp::from_milliseconds(0).is_ok());
208    /// assert!(Timestamp::from_milliseconds(i64::MAX).is_err());
209    /// ```
210    #[inline]
211    pub const fn from_milliseconds(milliseconds: i64) -> Result<Self, error::ComponentRange> {
212        const MAX: i64 = Seconds::MAX.get() * Millisecond::per_t::<i64>(Second)
213            + (Nanoseconds::MAX.get() as i64) / Nanosecond::per_t::<i64>(Millisecond);
214        const MIN: i64 = Seconds::MIN.get() * Millisecond::per_t::<i64>(Second)
215            + (Nanoseconds::MIN.get() as i64) / Nanosecond::per_t::<i64>(Millisecond);
216
217        ensure_ranged!(ri64<MIN, MAX>: milliseconds);
218
219        let mut seconds = milliseconds / Millisecond::per_t::<i64>(Second);
220        let nanoseconds = (milliseconds.rem_euclid(Millisecond::per_t(Second))
221            * Nanosecond::per_t::<i64>(Millisecond)) as u32;
222
223        if milliseconds < 0 && nanoseconds != 0 {
224            seconds -= 1;
225        }
226
227        // Safety: The value provided was checked to be in range.
228        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
229    }
230
231    /// Create a `Timestamp` from the provided Unix timestamp in microseconds, returning an error if
232    /// the resulting value is out of range.
233    ///
234    /// ```rust
235    /// # use time::Timestamp;
236    /// assert!(Timestamp::from_microseconds(0).is_ok());
237    /// assert!(Timestamp::from_microseconds(i128::MAX).is_err());
238    /// ```
239    #[inline]
240    pub const fn from_microseconds(microseconds: i128) -> Result<Self, error::ComponentRange> {
241        const MAX: i128 = Seconds::MAX.get() as i128 * Microsecond::per_t::<i128>(Second)
242            + (Nanoseconds::MAX.get() as i128) / Nanosecond::per_t::<i128>(Microsecond);
243        const MIN: i128 = Seconds::MIN.get() as i128 * Microsecond::per_t::<i128>(Second)
244            + (Nanoseconds::MIN.get() as i128) / Nanosecond::per_t::<i128>(Microsecond);
245
246        ensure_ranged!(ri128<MIN, MAX>: microseconds);
247
248        let mut seconds = (microseconds / Microsecond::per_t::<i128>(Second)) as i64;
249        let nanoseconds = (microseconds.rem_euclid(Microsecond::per_t(Second))
250            * Nanosecond::per_t::<i128>(Microsecond)) as u32;
251
252        if microseconds < 0 && nanoseconds != 0 {
253            seconds -= 1;
254        }
255
256        // Safety: The value provided was checked to be in range.
257        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
258    }
259
260    /// Create a `Timestamp` from the provided Unix timestamp in nanoseconds, returning an error if
261    /// the resulting value is out of range.
262    ///
263    /// ```rust
264    /// # use time::Timestamp;
265    /// assert!(Timestamp::from_nanoseconds(0).is_ok());
266    /// assert!(Timestamp::from_nanoseconds(i128::MAX).is_err());
267    /// ```
268    #[inline]
269    pub const fn from_nanoseconds(nanoseconds: i128) -> Result<Self, error::ComponentRange> {
270        const MAX: i128 = Seconds::MAX.get() as i128 * Nanosecond::per_t::<i128>(Second)
271            + Nanoseconds::MAX.get() as i128;
272        const MIN: i128 = Seconds::MIN.get() as i128 * Nanosecond::per_t::<i128>(Second)
273            + Nanoseconds::MIN.get() as i128;
274
275        ensure_ranged!(ri128<MIN, MAX>: nanoseconds);
276
277        let input_is_negative = nanoseconds < 0;
278        let mut seconds = (nanoseconds / Nanosecond::per_t::<i128>(Second)) as i64;
279        let nanoseconds = nanoseconds.rem_euclid(Nanosecond::per_t(Second)) as u32;
280
281        if input_is_negative && nanoseconds != 0 {
282            seconds -= 1;
283        }
284
285        // Safety: The value provided was checked to be in range.
286        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
287    }
288
289    /// Convert the `Timestamp` to an [`OffsetDateTime`] at the provided offset.
290    ///
291    /// ```rust
292    /// # use time_macros::{offset, timestamp};
293    /// assert_eq!(timestamp!(1_546_398_245).to_offset(offset!(+1)).hour(), 4);
294    /// ```
295    ///
296    /// # Panics
297    ///
298    /// This panics if the resulting date-time with the provided offset is outside the supported
299    /// range. Consider using [`checked_to_offset`](Self::checked_to_offset) for a non-panicking
300    /// alternative.
301    #[inline]
302    pub const fn to_offset(self, offset: UtcOffset) -> OffsetDateTime {
303        self.to_utc().to_offset(offset)
304    }
305
306    /// Convert the `Timestamp` to an [`OffsetDateTime`] with the provided offset, returning `None`
307    /// if the resulting value is out of range.
308    ///
309    /// ```rust
310    /// # use time_macros::{offset, timestamp};
311    /// assert!(
312    ///     timestamp!(1_546_398_245)
313    ///         .checked_to_offset(offset!(+1))
314    ///         .is_some()
315    /// );
316    /// ```
317    #[inline]
318    pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<OffsetDateTime> {
319        self.to_utc().checked_to_offset(offset)
320    }
321
322    /// Convert the `Timestamp` to a [`UtcDateTime`].
323    ///
324    /// ```rust
325    /// # use time_macros::{timestamp, utc_datetime};
326    /// assert_eq!(timestamp!(1_546_398_245).to_utc(), utc_datetime!(2019-01-02 3:04:05));
327    /// ```
328    #[inline]
329    pub const fn to_utc(self) -> UtcDateTime {
330        let Ok(utc_dt) = UtcDateTime::from_unix_timestamp(self.seconds.get()) else {
331            bug!("timestamp was invalid beforehand");
332        };
333        let Ok(utc_dt) = utc_dt.replace_nanosecond(self.nanoseconds.get()) else {
334            bug!("nanosecond was invalid beforehand");
335        };
336
337        utc_dt
338    }
339
340    /// Get the seconds and nanoseconds of the timestamp as ranged values.
341    #[inline]
342    pub(crate) const fn as_parts_ranged(self) -> (Seconds, Nanoseconds) {
343        (self.seconds, self.nanoseconds)
344    }
345
346    /// Get the number of seconds since the Unix epoch.
347    ///
348    /// Negative values represent moments before the Unix epoch.
349    ///
350    /// ```rust
351    /// # use time_macros::timestamp;
352    /// assert_eq!(timestamp!(1_546_398_245).as_seconds(), 1_546_398_245);
353    /// ```
354    #[inline]
355    pub const fn as_seconds(self) -> i64 {
356        self.seconds.get()
357    }
358
359    /// Get the number of milliseconds since the Unix epoch.
360    ///
361    /// Negative values represent moments before the Unix epoch.
362    ///
363    /// ```rust
364    /// # use time_macros::timestamp;
365    /// assert_eq!(
366    ///     timestamp!(1_546_398_245.006).as_milliseconds(),
367    ///     1_546_398_245_006
368    /// );
369    /// ```
370    #[inline]
371    pub const fn as_milliseconds(self) -> i64 {
372        self.seconds.get() * Millisecond::per_t::<i64>(Second)
373            + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as i64
374    }
375
376    /// Get the number of microseconds since the Unix epoch.
377    ///
378    /// Negative values represent moments before the Unix epoch.
379    ///
380    /// ```rust
381    /// # use time_macros::timestamp;
382    /// assert_eq!(
383    ///     timestamp!(1_546_398_245.006_007).as_microseconds(),
384    ///     1_546_398_245_006_007
385    /// );
386    /// ```
387    #[inline]
388    pub const fn as_microseconds(self) -> i128 {
389        self.seconds.get() as i128 * Microsecond::per_t::<i128>(Second)
390            + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)) as i128
391    }
392
393    /// Get the number of nanoseconds since the Unix epoch.
394    ///
395    /// Negative values represent moments before the Unix epoch.
396    ///
397    /// ```rust
398    /// # use time_macros::timestamp;
399    /// assert_eq!(
400    ///     timestamp!(1_546_398_245.006_007_008).as_nanoseconds(),
401    ///     1_546_398_245_006_007_008
402    /// );
403    /// ```
404    #[inline]
405    pub const fn as_nanoseconds(self) -> i128 {
406        self.seconds.get() as i128 * Nanosecond::per_t::<i128>(Second)
407            + self.nanoseconds.get() as i128
408    }
409
410    /// Get the [`Date`] of the timestamp in UTC.
411    ///
412    /// ```rust
413    /// # use time_macros::{date, timestamp};
414    /// assert_eq!(timestamp!(1_546_398_245).date(), date!(2019-01-02));
415    /// ```
416    #[inline]
417    pub const fn date(self) -> Date {
418        self.to_utc().date()
419    }
420
421    /// Get the [`Time`] of the timestamp in UTC.
422    ///
423    /// ```rust
424    /// # use time_macros::{time, timestamp};
425    /// assert_eq!(timestamp!(1_546_398_245).time(), time!(3:04:05));
426    /// ```
427    #[inline]
428    pub const fn time(self) -> Time {
429        let within_day = self.as_seconds().rem_euclid(Second::per_t::<i64>(Day)) as u32;
430
431        let hour = within_day / Second::per_t::<u32>(Hour);
432        let minute =
433            (within_day - hour * Second::per_t::<u32>(Hour)) / Second::per_t::<u32>(Minute);
434        let second =
435            within_day - hour * Second::per_t::<u32>(Hour) - minute * Second::per_t::<u32>(Minute);
436
437        // Safety: All values are guaranteed to be in range.
438        unsafe {
439            Time::__from_hms_nanos_unchecked(
440                hour as u8,
441                minute as u8,
442                second as u8,
443                self.nanosecond(),
444            )
445        }
446    }
447
448    /// Compute the year, leap year status, and ordinal day of the timestamp in UTC.
449    ///
450    /// This algorithm is essentially identical to `Date::from_julian_day_unchecked`. Instead of
451    /// returning `Date`, it returns the components as a tuple. By not bitpacking the values, it
452    /// allows the compiler to see through the function boundary and better optimize methods.
453    #[inline]
454    const fn year_leap_ordinal(self) -> (i32, bool, u16) {
455        const ERAS: u32 = 5_949;
456        const D_SHIFT: u32 = 146097 * ERAS + 719_528;
457        const Y_SHIFT: u32 = 400 * ERAS;
458
459        const CEN_MUL: u32 = ((4u64 << 47) / 146_097) as u32;
460        const JUL_MUL: u32 = ((4u64 << 40) / 1_461 + 1) as u32;
461        const CEN_CUT: u32 = ((365u64 << 32) / 36_525) as u32;
462
463        let raw_day = div_floor!(self.as_seconds(), Second::per_t::<i64>(Day)) as i32;
464
465        let day = raw_day.cast_unsigned().wrapping_add(D_SHIFT);
466        let c_n = (day as u64 * CEN_MUL as u64) >> 15;
467        let cen = (c_n >> 32) as u32;
468        let cpt = c_n as u32;
469        let ijy = cpt > CEN_CUT || cen.is_multiple_of(4);
470        let jul = day - cen / 4 + cen;
471        let y_n = (jul as u64 * JUL_MUL as u64) >> 8;
472        let yrs = (y_n >> 32) as u32;
473        let ypt = y_n as u32;
474
475        let year = yrs.wrapping_sub(Y_SHIFT).cast_signed();
476        let ordinal = ((ypt as u64 * 1_461) >> 34) as u32 + ijy as u32;
477        let leap = yrs.is_multiple_of(4) & ijy;
478
479        (year, leap, ordinal as u16)
480    }
481
482    /// Get the year of the timestamp in UTC.
483    ///
484    /// ```rust
485    /// # use time_macros::timestamp;
486    /// assert_eq!(timestamp!(1_546_398_245).year(), 2019);
487    /// ```
488    #[inline]
489    pub const fn year(self) -> i32 {
490        self.year_leap_ordinal().0
491    }
492
493    /// Get the month of the timestamp in UTC.
494    ///
495    /// ```rust
496    /// # use time::Month;
497    /// # use time_macros::timestamp;
498    /// assert_eq!(timestamp!(1_546_398_245).month(), Month::January);
499    /// ```
500    #[inline]
501    pub const fn month(self) -> Month {
502        let (_, leap, ordinal) = self.year_leap_ordinal();
503        util::leap_ordinal_to_month_day(leap, ordinal).0
504    }
505
506    /// Get the day of the month of the timestamp in UTC.
507    ///
508    /// The returned value will always be in the range `1..=31`.
509    ///
510    /// ```rust
511    /// # use time_macros::timestamp;
512    /// assert_eq!(timestamp!(1_546_398_245).day(), 2);
513    /// ```
514    #[inline]
515    pub const fn day(self) -> u8 {
516        let (_, leap, ordinal) = self.year_leap_ordinal();
517        util::leap_ordinal_to_month_day(leap, ordinal).1
518    }
519
520    /// Get the day of the year of the timestamp in UTC.
521    ///
522    /// The returned value will always be in the range `1..=366`.
523    ///
524    /// ```rust
525    /// # use time_macros::timestamp;
526    /// assert_eq!(timestamp!(1_546_398_245).ordinal(), 2);
527    /// ```
528    #[inline]
529    pub const fn ordinal(self) -> u16 {
530        self.year_leap_ordinal().2
531    }
532
533    /// Get the ISO week number of the timestamp in UTC.
534    ///
535    /// The returned value will always be in the range `1..=53`.
536    ///
537    /// ```rust
538    /// # use time_macros::timestamp;
539    /// assert_eq!(timestamp!(1_546_398_245).iso_week(), 1);
540    /// ```
541    #[inline]
542    pub const fn iso_week(self) -> u8 {
543        self.date().iso_week()
544    }
545
546    /// Get the Sunday-based week number of the timestamp in UTC.
547    ///
548    /// The returned value will always be in the range `0..=53`.
549    ///
550    /// ```rust
551    /// # use time_macros::timestamp;
552    /// assert_eq!(timestamp!(1_546_398_245).sunday_based_week(), 0);
553    /// ```
554    #[inline]
555    pub const fn sunday_based_week(self) -> u8 {
556        self.date().sunday_based_week()
557    }
558
559    /// Get the Monday-based week number of the timestamp in UTC.
560    ///
561    /// The returned value will always be in the range `0..=53`.
562    ///
563    /// ```rust
564    /// # use time_macros::timestamp;
565    /// assert_eq!(timestamp!(1_546_398_245).monday_based_week(), 0);
566    /// ```
567    #[inline]
568    pub const fn monday_based_week(self) -> u8 {
569        self.date().monday_based_week()
570    }
571
572    /// Get the calendar date (year, month, day) of the timestamp in UTC.
573    ///
574    /// ```rust
575    /// # use time::Month;
576    /// # use time_macros::timestamp;
577    /// assert_eq!(
578    ///     timestamp!(1_546_398_245).to_calendar_date(),
579    ///     (2019, Month::January, 2)
580    /// );
581    /// ```
582    #[inline]
583    pub const fn to_calendar_date(self) -> (i32, Month, u8) {
584        let (year, leap, ordinal) = self.year_leap_ordinal();
585        let (month, day) = util::leap_ordinal_to_month_day(leap, ordinal);
586        (year, month, day)
587    }
588
589    /// Get the ordinal date (year, ordinal day) of the timestamp in UTC.
590    ///
591    /// ```rust
592    /// # use time_macros::timestamp;
593    /// assert_eq!(timestamp!(1_546_398_245).to_ordinal_date(), (2019, 2));
594    /// ```
595    #[inline]
596    pub const fn to_ordinal_date(self) -> (i32, u16) {
597        let (year, _, ordinal) = self.year_leap_ordinal();
598        (year, ordinal)
599    }
600
601    /// Get the ISO week date (year, week number, weekday) of the timestamp in UTC.
602    ///
603    /// ```rust
604    /// # use time::Weekday;
605    /// # use time_macros::timestamp;
606    /// assert_eq!(
607    ///     timestamp!(1_546_398_245).to_iso_week_date(),
608    ///     (2019, 1, Weekday::Wednesday)
609    /// );
610    /// ```
611    #[inline]
612    pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
613        self.date().to_iso_week_date()
614    }
615
616    /// Get the weekday of the timestamp in UTC.
617    ///
618    /// ```rust
619    /// # use time::Weekday;
620    /// # use time_macros::timestamp;
621    /// assert_eq!(timestamp!(1_546_398_245).weekday(), Weekday::Wednesday);
622    /// ```
623    #[inline]
624    pub const fn weekday(self) -> Weekday {
625        // 365,961,669 is obtained by starting with the smallest timestamp (with large-dates
626        // enabled), dividing by 86,400 to get the number of days, then rounding down to get a
627        // multiple of 7. This value is negated as we want to end with a positive number. Finally, 3
628        // is added to shift the zero value to Monday, matching the internal representation of
629        // `Weekday`.
630        match (div_floor!(self.seconds.get(), 86_400) + 365_961_669) % 7 {
631            0 => Weekday::Monday,
632            1 => Weekday::Tuesday,
633            2 => Weekday::Wednesday,
634            3 => Weekday::Thursday,
635            4 => Weekday::Friday,
636            5 => Weekday::Saturday,
637            6 => Weekday::Sunday,
638            _ => unreachable!(),
639        }
640    }
641
642    /// Get the Julian day of the timestamp.
643    ///
644    /// ```rust
645    /// # use time_macros::timestamp;
646    /// assert_eq!(timestamp!(1_546_398_245).to_julian_day(), 2_458_486);
647    /// ```
648    #[inline]
649    pub const fn to_julian_day(self) -> i32 {
650        const UNIX_EPOCH_JULIAN_DAY: i32 = Date::UNIX_EPOCH.to_julian_day();
651        div_floor!(self.seconds.get(), 86_400) as i32 + UNIX_EPOCH_JULIAN_DAY
652    }
653
654    /// Get the hours, minutes, and seconds of the timestamp in UTC.
655    ///
656    /// ```rust
657    /// # use time_macros::timestamp;
658    /// assert_eq!(timestamp!(1_546_398_245).as_hms(), (3, 4, 5));
659    /// ```
660    #[inline]
661    pub const fn as_hms(self) -> (u8, u8, u8) {
662        self.time().as_hms()
663    }
664
665    /// Get the hours, minutes, seconds, and milliseconds of the timestamp in UTC.
666    ///
667    /// ```rust
668    /// # use time_macros::timestamp;
669    /// assert_eq!(timestamp!(1_546_398_245.006).as_hms_milli(), (3, 4, 5, 6));
670    /// ```
671    #[inline]
672    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
673        self.time().as_hms_milli()
674    }
675
676    /// Get the hours, minutes, seconds, and microseconds of the timestamp in UTC.
677    ///
678    /// ```rust
679    /// # use time_macros::timestamp;
680    /// assert_eq!(
681    ///     timestamp!(1_546_398_245.006_007).as_hms_micro(),
682    ///     (3, 4, 5, 6_007)
683    /// );
684    /// ```
685    #[inline]
686    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
687        self.time().as_hms_micro()
688    }
689
690    /// Get the hours, minutes, seconds, and nanoseconds of the timestamp in UTC.
691    ///
692    /// ```rust
693    /// # use time_macros::timestamp;
694    /// assert_eq!(
695    ///     timestamp!(1_546_398_245.006_007_008).as_hms_nano(),
696    ///     (3, 4, 5, 6_007_008)
697    /// );
698    /// ```
699    #[inline]
700    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
701        self.time().as_hms_nano()
702    }
703
704    /// Get the hour of the timestamp in UTC.
705    ///
706    /// ```rust
707    /// # use time_macros::timestamp;
708    /// assert_eq!(timestamp!(1_546_398_245).hour(), 3);
709    /// ```
710    #[inline]
711    pub const fn hour(self) -> u8 {
712        self.time().hour()
713    }
714
715    /// Get the minute of the timestamp in UTC.
716    ///
717    /// ```rust
718    /// # use time_macros::timestamp;
719    /// assert_eq!(timestamp!(1_546_398_245).minute(), 4);
720    /// ```
721    #[inline]
722    pub const fn minute(self) -> u8 {
723        (div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute)))
724            .rem_euclid(Minute::per_t(Hour)) as u8
725    }
726
727    /// Get the second of the timestamp in UTC.
728    ///
729    /// ```rust
730    /// # use time_macros::timestamp;
731    /// assert_eq!(timestamp!(1_546_398_245).second(), 5);
732    /// ```
733    #[inline]
734    pub const fn second(self) -> u8 {
735        self.seconds.get().rem_euclid(Second::per_t(Minute)) as u8
736    }
737
738    /// Get the millisecond of the timestamp in UTC.
739    ///
740    /// ```rust
741    /// # use time_macros::timestamp;
742    /// assert_eq!(timestamp!(1_546_398_245.006).millisecond(), 6);
743    /// ```
744    #[inline]
745    pub const fn millisecond(self) -> u16 {
746        (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
747    }
748
749    /// Get the microsecond of the timestamp in UTC.
750    ///
751    /// ```rust
752    /// # use time_macros::timestamp;
753    /// assert_eq!(timestamp!(1_546_398_245.006_007).microsecond(), 6_007);
754    /// ```
755    #[inline]
756    pub const fn microsecond(self) -> u32 {
757        self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)
758    }
759
760    /// Get the nanosecond of the timestamp in UTC.
761    ///
762    /// ```rust
763    /// # use time_macros::timestamp;
764    /// assert_eq!(
765    ///     timestamp!(1_546_398_245.006_007_008).nanosecond(),
766    ///     6_007_008
767    /// );
768    /// ```
769    #[inline]
770    pub const fn nanosecond(self) -> u32 {
771        self.nanoseconds.get()
772    }
773
774    /// Add a [`SignedDuration`] to the timestamp. Returns `Overflow::Positive` or
775    /// `Overflow::Negative` if the result is out of range.
776    #[inline]
777    const fn add(self, duration: SignedDuration) -> Result<Self, Overflow> {
778        let (second_adj, nanoseconds) = if duration.is_negative() {
779            let nanos = self.nanoseconds.get() as i32 + duration.subsec_nanoseconds();
780            if nanos < 0 {
781                (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
782            } else {
783                (0, nanos as u32)
784            }
785        } else {
786            let nanos = self.nanoseconds.get() + duration.subsec_nanoseconds() as u32;
787            if nanos >= Nanosecond::per_t(Second) {
788                (1, nanos - Nanosecond::per_t::<u32>(Second))
789            } else {
790                (0, nanos)
791            }
792        };
793
794        let seconds = match self.seconds.get().checked_add(duration.whole_seconds()) {
795            Some(seconds) => seconds,
796            None if duration.is_negative() => return Err(Overflow::Negative),
797            None => return Err(Overflow::Positive),
798        };
799        let seconds = match seconds.checked_add(second_adj) {
800            Some(seconds) => seconds,
801            None if second_adj < 0 => return Err(Overflow::Negative),
802            None => return Err(Overflow::Positive),
803        };
804
805        // Check if the resulting seconds are within the valid range
806        if seconds < Seconds::MIN.get() {
807            return Err(Overflow::Negative);
808        } else if seconds > Seconds::MAX.get() {
809            return Err(Overflow::Positive);
810        }
811
812        // Safety: Both values are guaranteed to be in range.
813        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
814    }
815
816    /// Subtract a [`SignedDuration`] from the timestamp. Returns `Overflow::Positive` or
817    /// `Overflow::Negative` if the result is out of range.
818    #[inline]
819    const fn sub(self, duration: SignedDuration) -> Result<Self, Overflow> {
820        let nanos = self.nanoseconds.get() as i32 - duration.subsec_nanoseconds();
821        let (second_adj, nanoseconds) = if duration.is_negative() {
822            if nanos >= Nanosecond::per_t::<i32>(Second) {
823                (1, (nanos - Nanosecond::per_t::<i32>(Second)) as u32)
824            } else if nanos < 0 {
825                (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
826            } else {
827                (0, nanos as u32)
828            }
829        } else {
830            if nanos < 0 {
831                (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
832            } else {
833                (0, nanos as u32)
834            }
835        };
836
837        let seconds = match self.seconds.get().checked_sub(duration.whole_seconds()) {
838            Some(seconds) => seconds,
839            None if duration.is_negative() => return Err(Overflow::Positive),
840            None => return Err(Overflow::Negative),
841        };
842        let seconds = match seconds.checked_add(second_adj) {
843            Some(seconds) => seconds,
844            None if second_adj < 0 => return Err(Overflow::Negative),
845            None => return Err(Overflow::Positive),
846        };
847
848        // Check if the resulting seconds are within the valid range
849        if seconds < Seconds::MIN.get() {
850            return Err(Overflow::Negative);
851        } else if seconds > Seconds::MAX.get() {
852            return Err(Overflow::Positive);
853        }
854
855        // Safety: Both values are guaranteed to be in range.
856        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
857    }
858
859    /// Add a [`std::time::Duration`] to the timestamp. Returns `Overflow::Positive` or
860    /// `Overflow::Negative` if the result is out of range.
861    #[inline]
862    const fn add_std(self, duration: StdDuration) -> Result<Self, Overflow> {
863        let Some(mut seconds) = self.seconds.get().checked_add_unsigned(duration.as_secs()) else {
864            return Err(Overflow::Positive);
865        };
866        let mut nanoseconds = self.nanoseconds.get() + duration.subsec_nanos();
867
868        if nanoseconds >= Nanosecond::per_t(Second) {
869            nanoseconds -= Nanosecond::per_t::<u32>(Second);
870            let Some(new_seconds) = seconds.checked_add(1) else {
871                return Err(Overflow::Positive);
872            };
873            seconds = new_seconds;
874        }
875
876        // Check if the resulting seconds are within the valid range
877        if seconds < Seconds::MIN.get() {
878            return Err(Overflow::Negative);
879        } else if seconds > Seconds::MAX.get() {
880            return Err(Overflow::Positive);
881        }
882
883        // Safety: Both values are guaranteed to be in range.
884        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
885    }
886
887    /// Subtract a [`std::time::Duration`] from the timestamp. Returns `Overflow::Positive` or
888    /// `Overflow::Negative` if the result is out of range.
889    #[inline]
890    const fn sub_std(self, duration: StdDuration) -> Result<Self, Overflow> {
891        let Some(mut seconds) = self.seconds.get().checked_sub_unsigned(duration.as_secs()) else {
892            return Err(Overflow::Negative);
893        };
894        let mut nanoseconds = self.nanoseconds.get() as i32 - duration.subsec_nanos() as i32;
895
896        if nanoseconds < 0 {
897            nanoseconds += Nanosecond::per_t::<i32>(Second);
898            let Some(new_seconds) = seconds.checked_sub(1) else {
899                return Err(Overflow::Negative);
900            };
901            seconds = new_seconds;
902        }
903
904        // Check if the resulting seconds are within the valid range
905        if seconds < Seconds::MIN.get() {
906            return Err(Overflow::Negative);
907        } else if seconds > Seconds::MAX.get() {
908            return Err(Overflow::Positive);
909        }
910
911        // Safety: Both values are guaranteed to be in range.
912        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds as u32) })
913    }
914
915    /// Checked addition of a [`SignedDuration`], returning `None` if the result is out of range.
916    ///
917    /// ```rust
918    /// # use time_macros::timestamp;
919    /// # use time::ext::NumericalDuration as _;
920    /// assert_eq!(
921    ///     timestamp!(1_546_398_245).checked_add(1.days()),
922    ///     Some(timestamp!(1_546_484_645))
923    /// );
924    /// assert_eq!(
925    ///     timestamp!(1_546_398_245).checked_add((-1).days()),
926    ///     Some(timestamp!(1_546_311_845))
927    /// );
928    /// ```
929    #[inline]
930    pub const fn checked_add(self, duration: SignedDuration) -> Option<Self> {
931        match self.add(duration) {
932            Ok(timestamp) => Some(timestamp),
933            Err(Overflow::Positive | Overflow::Negative) => None,
934        }
935    }
936
937    /// Checked subtraction of a [`SignedDuration`], returning `None` if the result is out of range.
938    ///
939    /// ```rust
940    /// # use time_macros::timestamp;
941    /// # use time::ext::NumericalDuration as _;
942    /// assert_eq!(
943    ///     timestamp!(1_546_398_245).checked_sub(1.days()),
944    ///     Some(timestamp!(1_546_311_845))
945    /// );
946    /// assert_eq!(
947    ///     timestamp!(1_546_398_245).checked_sub((-1).days()),
948    ///     Some(timestamp!(1_546_484_645))
949    /// );
950    /// ```
951    #[inline]
952    pub const fn checked_sub(self, duration: SignedDuration) -> Option<Self> {
953        match self.sub(duration) {
954            Ok(timestamp) => Some(timestamp),
955            Err(Overflow::Positive | Overflow::Negative) => None,
956        }
957    }
958
959    /// Saturating addition of a [`SignedDuration`].
960    ///
961    /// Returns [`Timestamp::MAX`] or [`Timestamp::MIN`] if the result is out of range.
962    ///
963    /// ```rust
964    /// # use time::Timestamp;
965    /// # use time_macros::timestamp;
966    /// # use time::ext::NumericalDuration as _;
967    /// assert_eq!(
968    ///     timestamp!(1_546_398_245).saturating_add(1.days()),
969    ///     timestamp!(1_546_484_645)
970    /// );
971    /// assert_eq!(Timestamp::MAX.saturating_add(1.days()), Timestamp::MAX);
972    /// assert_eq!(Timestamp::MIN.saturating_add((-1).days()), Timestamp::MIN);
973    /// ```
974    #[inline]
975    pub const fn saturating_add(self, duration: SignedDuration) -> Self {
976        match self.add(duration) {
977            Ok(timestamp) => timestamp,
978            Err(Overflow::Positive) => Self::MAX,
979            Err(Overflow::Negative) => Self::MIN,
980        }
981    }
982
983    /// Saturating subtraction of a [`SignedDuration`].
984    ///
985    /// Returns [`Timestamp::MAX`] or [`Timestamp::MIN`] if the result is out of range.
986    ///
987    /// ```rust
988    /// # use time::Timestamp;
989    /// # use time_macros::timestamp;
990    /// # use time::ext::NumericalDuration as _;
991    /// assert_eq!(
992    ///     timestamp!(1_546_398_245).saturating_sub(1.days()),
993    ///     timestamp!(1_546_311_845)
994    /// );
995    /// assert_eq!(Timestamp::MIN.saturating_sub(1.days()), Timestamp::MIN);
996    /// assert_eq!(Timestamp::MAX.saturating_sub((-1).days()), Timestamp::MAX);
997    /// ```
998    #[inline]
999    pub const fn saturating_sub(self, duration: SignedDuration) -> Self {
1000        match self.sub(duration) {
1001            Ok(timestamp) => timestamp,
1002            Err(Overflow::Positive) => Self::MAX,
1003            Err(Overflow::Negative) => Self::MIN,
1004        }
1005    }
1006}
1007
1008/// Methods that replace part of the `Timestamp`.
1009impl Timestamp {
1010    /// Replace the time, preserving the date.
1011    ///
1012    /// ```rust
1013    /// # use time_macros::{time, timestamp};
1014    /// assert_eq!(
1015    ///     timestamp!(1_546_398_245).replace_time(time!(12:34:56)),
1016    ///     timestamp!(1_546_432_496)
1017    /// );
1018    /// ```
1019    #[inline]
1020    #[must_use = "This method does not mutate the original `Timestamp`."]
1021    pub const fn replace_time(self, time: Time) -> Self {
1022        let seconds_since_midnight = time.hour() as i64 * Second::per_t::<i64>(Hour)
1023            + time.minute() as i64 * Second::per_t::<i64>(Minute)
1024            + time.second() as i64;
1025        let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Day))
1026            * Second::per_t::<i64>(Day)
1027            + seconds_since_midnight;
1028        // Safety: Seconds is constructed from an existing valid value, and nanoseconds are always
1029        // in range given the origin. Any time of day is valid for any date in range, as enforced by
1030        // const assertions.
1031        unsafe { Self::__new_unchecked(seconds, time.nanosecond()) }
1032    }
1033
1034    /// Replace the date, preserving the time.
1035    ///
1036    /// ```rust
1037    /// # use time_macros::{date, timestamp};
1038    /// assert_eq!(
1039    ///     timestamp!(1_546_398_245).replace_date(date!(2020-01-02)),
1040    ///     timestamp!(1_577_934_245)
1041    /// );
1042    /// ```
1043    #[inline]
1044    #[must_use = "This method does not mutate the original `Timestamp`."]
1045    pub const fn replace_date(mut self, date: Date) -> Self {
1046        let seconds_after_midnight = self.seconds.get().rem_euclid(Second::per_t(Day));
1047        let seconds = (date.to_julian_day() as i64
1048            - UtcDateTime::UNIX_EPOCH.to_julian_day() as i64)
1049            * Second::per_t::<i64>(Day)
1050            + seconds_after_midnight;
1051        // Safety: The range of valid dates is identical to the range of valid timestamps, so any
1052        // date is necessarily valid.
1053        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1054        self
1055    }
1056
1057    /// Replace the year, preserving the month and day. If the date is February 29 and the resulting
1058    /// year is not a leap year, an error is returned.
1059    ///
1060    /// ```rust
1061    /// # use time_macros::timestamp;
1062    /// assert_eq!(
1063    ///     timestamp!(1_546_398_245).replace_year(2020),
1064    ///     Ok(timestamp!(1_577_934_245))
1065    /// );
1066    /// assert!(timestamp!(1_546_398_245).replace_year(-1_000_000).is_err()); // -1_000_000 isn't a valid year
1067    /// assert!(timestamp!(1_546_398_245).replace_year(1_000_000).is_err()); // 1_000_000 isn't a valid year
1068    /// ```
1069    #[inline]
1070    #[must_use = "This method does not mutate the original `Timestamp`."]
1071    pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1072        let date = const_try!(self.date().replace_year(year));
1073        Ok(self.replace_date(date))
1074    }
1075
1076    /// Replace the month of the year, preserving the year and day. If the day is invalid for the
1077    /// resulting month, an error is returned.
1078    ///
1079    /// ```rust
1080    /// # use time_macros::timestamp;
1081    /// # use time::Month;
1082    /// assert_eq!(
1083    ///     timestamp!(1_546_398_245).replace_month(Month::February),
1084    ///     Ok(timestamp!(1_549_076_645))
1085    /// );
1086    /// assert!(
1087    ///     timestamp!(1_548_817_445)
1088    ///         .replace_month(Month::February)
1089    ///         .is_err()
1090    /// ); // the day of the month is 30, which is invalid for February
1091    /// ```
1092    #[inline]
1093    #[must_use = "This method does not mutate the original `Timestamp`."]
1094    pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1095        let date = const_try!(self.date().replace_month(month));
1096        Ok(self.replace_date(date))
1097    }
1098
1099    /// Replace the day of the month.
1100    ///
1101    /// ```rust
1102    /// # use time_macros::timestamp;
1103    /// assert_eq!(
1104    ///     timestamp!(1_546_398_245).replace_day(1),
1105    ///     Ok(timestamp!(1_546_311_845))
1106    /// );
1107    /// assert!(timestamp!(1_546_398_245).replace_day(0).is_err()); // 00 isn't a valid day
1108    /// assert!(timestamp!(1_546_398_245).replace_day(32).is_err()); // 32 isn't a valid day
1109    /// ```
1110    #[inline]
1111    #[must_use = "This method does not mutate the original `Timestamp`."]
1112    pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1113        let date = const_try!(self.date().replace_day(day));
1114        Ok(self.replace_date(date))
1115    }
1116
1117    /// Replace the day of the year.
1118    ///
1119    /// ```rust
1120    /// # use time_macros::timestamp;
1121    /// assert_eq!(
1122    ///     timestamp!(1_546_398_245).replace_ordinal(1),
1123    ///     Ok(timestamp!(1_546_311_845))
1124    /// );
1125    /// assert!(timestamp!(1_546_398_245).replace_ordinal(0).is_err()); // 0 isn't a valid day of the year
1126    /// assert!(timestamp!(1_546_398_245).replace_ordinal(366).is_err()); // the timestamp is in 2019, which isn't a leap year
1127    /// ```
1128    #[inline]
1129    #[must_use = "This method does not mutate the original `Timestamp`."]
1130    pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1131        let date = const_try!(self.date().replace_ordinal(ordinal));
1132        Ok(self.replace_date(date))
1133    }
1134
1135    /// Replace the clock hour.
1136    ///
1137    /// ```rust
1138    /// # use time_macros::timestamp;
1139    /// assert_eq!(
1140    ///     timestamp!(1_546_398_245).replace_hour(0),
1141    ///     Ok(timestamp!(1_546_387_445))
1142    /// );
1143    /// assert!(timestamp!(1_546_398_245).replace_hour(24).is_err()); // 24 isn't a valid hour
1144    /// ```
1145    #[inline]
1146    #[must_use = "This method does not mutate the original `Timestamp`."]
1147    pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
1148        ensure_ranged!(ru8<0, 23>: hour);
1149        let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Day))
1150            * Second::per_t::<i64>(Day)
1151            + hour as i64 * Second::per_t::<i64>(Hour)
1152            + self.minute() as i64 * Second::per_t::<i64>(Minute)
1153            + self.second() as i64;
1154        // Safety: Any value is valid so long as `hour` is in range.
1155        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1156        Ok(self)
1157    }
1158
1159    /// Replace the minutes within the hour.
1160    ///
1161    /// ```rust
1162    /// # use time_macros::timestamp;
1163    /// assert_eq!(
1164    ///     timestamp!(1_546_398_245).replace_minute(0),
1165    ///     Ok(timestamp!(1_546_398_005))
1166    /// );
1167    /// assert!(timestamp!(1_546_398_245).replace_minute(60).is_err()); // 60 isn't a valid minute
1168    /// ```
1169    #[inline]
1170    #[must_use = "This method does not mutate the original `Timestamp`."]
1171    pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
1172        ensure_ranged!(ru8<0, 59>: minute);
1173        let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Hour))
1174            * Second::per_t::<i64>(Hour)
1175            + minute as i64 * Second::per_t::<i64>(Minute)
1176            + self.second() as i64;
1177        // Safety: Any value is valid so long as `minute` is in range.
1178        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1179        Ok(self)
1180    }
1181
1182    /// Replace the seconds within the minute.
1183    ///
1184    /// ```rust
1185    /// # use time_macros::timestamp;
1186    /// assert_eq!(
1187    ///     timestamp!(1_546_398_245).replace_second(0),
1188    ///     Ok(timestamp!(1_546_398_240))
1189    /// );
1190    /// assert!(timestamp!(1_546_398_245).replace_second(60).is_err()); // 60 isn't a valid second
1191    /// ```
1192    #[inline]
1193    #[must_use = "This method does not mutate the original `Timestamp`."]
1194    pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
1195        ensure_ranged!(ru8<0, 59>: second);
1196        let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute))
1197            * Second::per_t::<i64>(Minute)
1198            + second as i64;
1199        // Safety: Any value is valid so long as `second` is in range.
1200        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1201        Ok(self)
1202    }
1203
1204    /// Replace the milliseconds within the second.
1205    ///
1206    /// ```rust
1207    /// # use time_macros::timestamp;
1208    /// assert_eq!(
1209    ///     timestamp!(1_546_398_245.006).replace_millisecond(7),
1210    ///     Ok(timestamp!(1_546_398_245.007))
1211    /// );
1212    /// assert!(
1213    ///     timestamp!(1_546_398_245.006)
1214    ///         .replace_millisecond(1_000)
1215    ///         .is_err()
1216    /// ); // 1_000 isn't a valid millisecond
1217    /// ```
1218    #[inline]
1219    #[must_use = "This method does not mutate the original `Timestamp`."]
1220    pub const fn replace_millisecond(
1221        self,
1222        millisecond: u16,
1223    ) -> Result<Self, error::ComponentRange> {
1224        let nanos =
1225            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
1226        Ok(self.replace_nanosecond_ranged(nanos))
1227    }
1228
1229    /// Replace the microseconds within the second.
1230    ///
1231    /// ```rust
1232    /// # use time_macros::timestamp;
1233    /// assert_eq!(
1234    ///     timestamp!(1_546_398_245.006_007).replace_microsecond(123_456),
1235    ///     Ok(timestamp!(1_546_398_245.123_456))
1236    /// );
1237    /// assert!(
1238    ///     timestamp!(1_546_398_245.006_007)
1239    ///         .replace_microsecond(1_000_000)
1240    ///         .is_err()
1241    /// ); // 1_000_000 isn't a valid microsecond
1242    /// ```
1243    #[inline]
1244    #[must_use = "This method does not mutate the original `Timestamp`."]
1245    pub const fn replace_microsecond(
1246        self,
1247        microsecond: u32,
1248    ) -> Result<Self, error::ComponentRange> {
1249        let nanos =
1250            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
1251        Ok(self.replace_nanosecond_ranged(nanos))
1252    }
1253
1254    /// Replace the nanoseconds within the second.
1255    ///
1256    /// ```rust
1257    /// # use time_macros::timestamp;
1258    /// assert_eq!(
1259    ///     timestamp!(1_546_398_245.006_007_008).replace_nanosecond(123_456_789),
1260    ///     Ok(timestamp!(1_546_398_245.123_456_789))
1261    /// );
1262    /// assert!(
1263    ///     timestamp!(1_546_398_245.006_007_008)
1264    ///         .replace_nanosecond(1_000_000_000)
1265    ///         .is_err()
1266    /// ); // 1_000_000_000 isn't a valid nanosecond
1267    /// ```
1268    #[inline]
1269    #[must_use = "This method does not mutate the original `Timestamp`."]
1270    pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1271        let nanos = ensure_ranged!(Nanoseconds: nanosecond);
1272        Ok(self.replace_nanosecond_ranged(nanos))
1273    }
1274
1275    /// Replace the nanoseconds within the second using a range-bounded integer to avoid range
1276    /// checks.
1277    #[inline]
1278    const fn replace_nanosecond_ranged(self, new_nanos: Nanoseconds) -> Self {
1279        let (seconds, nanoseconds) = self.as_parts_ranged();
1280
1281        if seconds.get() >= 0 || nanoseconds.get() == 0 {
1282            Self::new_ranged(seconds, new_nanos)
1283        } else if new_nanos.get() == 0 {
1284            // Safety: The previous conditional guarantees that `seconds` is negative (if it were
1285            // non-negative, we wouldn't be in this branch). Given that the maximum value is
1286            // positive, we can always add one without exceeding the maximum.
1287            Self::new_ranged(unsafe { seconds.unchecked_add(1) }, new_nanos)
1288        } else {
1289            // Safety: Given the range of `new_nanos`, subtracting it from the maximum always
1290            // results in a value in range. Zero is excluded by a previous conditional.
1291            Self::new_ranged(seconds, unsafe {
1292                Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - new_nanos.get())
1293            })
1294        }
1295    }
1296}
1297
1298#[cfg(feature = "formatting")]
1299impl Timestamp {
1300    /// Format the `Timestamp` using the provided [format description](crate::format_description).
1301    #[inline]
1302    pub fn format_into(
1303        self,
1304        output: &mut (impl io::Write + ?Sized),
1305        format: &(impl Formattable + ?Sized),
1306    ) -> Result<usize, error::Format> {
1307        format.format_into(output, &self, &mut Default::default(), PrivateMethod)
1308    }
1309
1310    /// Format the `Timestamp` using the provided [format description](crate::format_description).
1311    ///
1312    /// ```rust
1313    /// # use time_macros::{format_description, timestamp};
1314    /// let format = format_description!("[unix_timestamp]");
1315    /// assert_eq!(timestamp!(1_546_398_245).format(&format)?, "1546398245");
1316    /// # Ok::<_, time::Error>(())
1317    /// ```
1318    #[inline]
1319    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1320        format.format(&self, &mut Default::default(), PrivateMethod)
1321    }
1322}
1323
1324#[cfg(feature = "parsing")]
1325impl Timestamp {
1326    /// Parse a `Timestamp` from the input using the provided [format
1327    /// description](crate::format_description).
1328    ///
1329    /// ```rust
1330    /// # use time::Timestamp;
1331    /// # use time_macros::{format_description, timestamp};
1332    /// let format = format_description!("[unix_timestamp]");
1333    /// assert_eq!(
1334    ///     Timestamp::parse("1546398245", &format)?,
1335    ///     timestamp!(1_546_398_245),
1336    /// );
1337    /// # Ok::<_, time::Error>(())
1338    /// ```
1339    #[inline]
1340    pub fn parse(
1341        input: &str,
1342        description: &(impl Parsable + ?Sized),
1343    ) -> Result<Self, error::Parse> {
1344        description.parse_timestamp(input.as_bytes(), None, PrivateMethod)
1345    }
1346
1347    /// Parse a `Timestamp` from the input using the provided [format
1348    /// description](crate::format_description) and default values.
1349    ///
1350    /// ```rust
1351    /// # use time::Timestamp;
1352    /// # use time::parsing::Parsed;
1353    /// # use time_macros::{format_description, timestamp};
1354    /// let format = format_description!("[year]-[month]-[day]");
1355    /// let defaults = Parsed::new().with_hour_24(0).expect("0 is a valid hour");
1356    /// assert_eq!(
1357    ///     Timestamp::parse_with_defaults(b"2020-01-02", &format, defaults)?,
1358    ///     timestamp!(1_577_923_200)
1359    /// );
1360    /// # Ok::<_, time::Error>(())
1361    /// ```
1362    #[inline]
1363    pub fn parse_with_defaults(
1364        input: &[u8],
1365        description: &(impl Parsable + ?Sized),
1366        defaults: Parsed,
1367    ) -> Result<Self, error::Parse> {
1368        description.parse_timestamp(input, Some(defaults), PrivateMethod)
1369    }
1370}
1371
1372impl Timestamp {
1373    /// The maximum number of bytes that the `fmt_into_buffer` method will write, which is also used
1374    /// by the `Display` implementation.
1375    const DISPLAY_BUFFER_SIZE: usize = 25;
1376
1377    /// Format the `Timestamp` into the provided buffer, returning the number of bytes written.
1378    pub(crate) fn fmt_into_buffer(
1379        self,
1380        buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
1381    ) -> usize {
1382        let mut idx = 0;
1383
1384        let mut second = self.seconds.get();
1385        let mut nanosecond = self.nanoseconds;
1386
1387        if second < 0 {
1388            buf[idx] = MaybeUninit::new(b'-');
1389            idx += 1;
1390
1391            second = -second;
1392
1393            if nanosecond != Nanoseconds::new_static::<0>() {
1394                second -= 1;
1395                // Safety: `nanosecond` is in the range 1..=999_999_999, so subtracting it from
1396                // 1_000_000_000 will always yield a value in the range 1..=999_999_999, which is a
1397                // subset of the valid range for `Nanoseconds`.
1398                nanosecond = unsafe {
1399                    Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - nanosecond.get())
1400                };
1401            }
1402        }
1403
1404        let seconds_str = u64_pad_none(second.cast_unsigned());
1405        let seconds_len = seconds_str.len();
1406        // Safety: `buf` has sufficient capacity for the seconds digits.
1407        unsafe {
1408            seconds_str
1409                .as_ptr()
1410                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), seconds_len);
1411        }
1412        idx += seconds_len;
1413
1414        if nanosecond != Nanoseconds::new_static::<0>() {
1415            buf[idx] = MaybeUninit::new(b'.');
1416            idx += 1;
1417
1418            let subsecond = truncated_subsecond_from_nanos(nanosecond);
1419            // Safety: `buf` has sufficient capacity for the subsecond digits.
1420            unsafe {
1421                subsecond
1422                    .as_ptr()
1423                    .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len());
1424            }
1425            idx += subsecond.len();
1426        }
1427
1428        idx
1429    }
1430}
1431
1432impl fmt::Display for Timestamp {
1433    #[inline]
1434    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1435        let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1436        let len = self.fmt_into_buffer(&mut buf);
1437        // Safety: All bytes up to `len` have been initialized with ASCII characters.
1438        let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1439        f.pad(s)
1440    }
1441}
1442
1443impl fmt::Debug for Timestamp {
1444    #[inline]
1445    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1446        fmt::Display::fmt(self, f)
1447    }
1448}
1449
1450impl Add<SignedDuration> for Timestamp {
1451    type Output = Self;
1452
1453    /// # Panics
1454    ///
1455    /// This may panic if an overflow occurs.
1456    #[inline]
1457    #[track_caller]
1458    fn add(self, rhs: SignedDuration) -> Self::Output {
1459        self.checked_add(rhs)
1460            .expect("resulting value is out of range")
1461    }
1462}
1463
1464impl Add<StdDuration> for Timestamp {
1465    type Output = Self;
1466
1467    /// # Panics
1468    ///
1469    /// This may panic if an overflow occurs.
1470    #[inline]
1471    #[track_caller]
1472    fn add(self, rhs: StdDuration) -> Self::Output {
1473        self.add_std(rhs).expect("resulting value is out of range")
1474    }
1475}
1476
1477impl AddAssign<SignedDuration> for Timestamp {
1478    /// # Panics
1479    ///
1480    /// This may panic if an overflow occurs.
1481    #[inline]
1482    #[track_caller]
1483    fn add_assign(&mut self, rhs: SignedDuration) {
1484        *self = *self + rhs;
1485    }
1486}
1487
1488impl AddAssign<StdDuration> for Timestamp {
1489    /// # Panics
1490    ///
1491    /// This may panic if an overflow occurs.
1492    #[inline]
1493    #[track_caller]
1494    fn add_assign(&mut self, rhs: StdDuration) {
1495        *self = *self + rhs;
1496    }
1497}
1498
1499impl Sub<SignedDuration> for Timestamp {
1500    type Output = Self;
1501
1502    /// # Panics
1503    ///
1504    /// This may panic if an overflow occurs.
1505    #[inline]
1506    #[track_caller]
1507    fn sub(self, rhs: SignedDuration) -> Self::Output {
1508        self.checked_sub(rhs)
1509            .expect("resulting value is out of range")
1510    }
1511}
1512
1513impl Sub<StdDuration> for Timestamp {
1514    type Output = Self;
1515
1516    /// # Panics
1517    ///
1518    /// This may panic if an overflow occurs.
1519    #[inline]
1520    #[track_caller]
1521    fn sub(self, rhs: StdDuration) -> Self::Output {
1522        self.sub_std(rhs).expect("resulting value is out of range")
1523    }
1524}
1525
1526impl SubAssign<SignedDuration> for Timestamp {
1527    /// # Panics
1528    ///
1529    /// This may panic if an overflow occurs.
1530    #[inline]
1531    #[track_caller]
1532    fn sub_assign(&mut self, rhs: SignedDuration) {
1533        *self = *self - rhs;
1534    }
1535}
1536
1537impl SubAssign<StdDuration> for Timestamp {
1538    /// # Panics
1539    ///
1540    /// This may panic if an overflow occurs.
1541    #[inline]
1542    #[track_caller]
1543    fn sub_assign(&mut self, rhs: StdDuration) {
1544        *self = *self - rhs;
1545    }
1546}
1547
1548impl Sub for Timestamp {
1549    type Output = SignedDuration;
1550
1551    #[inline]
1552    fn sub(self, rhs: Self) -> Self::Output {
1553        let seconds = self.seconds.get() - rhs.seconds.get();
1554        let nanoseconds = self.nanoseconds.get() as i32 - rhs.nanoseconds.get() as i32;
1555
1556        if nanoseconds < 0 {
1557            SignedDuration::new(seconds - 1, nanoseconds + Nanosecond::per_t::<i32>(Second))
1558        } else {
1559            SignedDuration::new(seconds, nanoseconds)
1560        }
1561    }
1562}