Coverage Report

Created: 2026-08-14 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/time-0.3.55/src/timestamp.rs
Line
Count
Source
1
//! The [`Timestamp`] struct and associated `impl`s.
2
3
#[cfg(feature = "formatting")]
4
use alloc::string::String;
5
use core::cmp::Ordering;
6
use core::fmt;
7
use core::hash::{Hash, Hasher};
8
use core::mem::MaybeUninit;
9
use core::ops::{Add, AddAssign, Sub, SubAssign};
10
use core::time::Duration as StdDuration;
11
#[cfg(feature = "formatting")]
12
use std::io;
13
#[cfg(feature = "std")]
14
use std::time::SystemTime;
15
16
use deranged::{ri64, ri128, ru8, ru32};
17
18
#[cfg(any(feature = "formatting", feature = "parsing"))]
19
use crate::PrivateMethod;
20
#[cfg(feature = "formatting")]
21
use crate::formatting::Formattable;
22
use crate::internal_macros::{bug, const_try, div_floor, ensure_ranged};
23
use crate::num_fmt::{str_from_raw_parts, truncated_subsecond_from_nanos, u64_pad_none};
24
#[cfg(feature = "parsing")]
25
use crate::parsing::{Parsable, Parsed};
26
use crate::unit::*;
27
use crate::util::Overflow;
28
use crate::{
29
    Date, Month, OffsetDateTime, SignedDuration, Time, UtcDateTime, UtcOffset, Weekday, error, util,
30
};
31
32
/// The range of valid seconds for a [`Timestamp`].
33
pub(crate) type Seconds =
34
    ri64<{ UtcDateTime::MIN.unix_timestamp() }, { UtcDateTime::MAX.unix_timestamp() }>;
35
type 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.
39
const _: () = {
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)]
48
enum 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))]
59
pub 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
75
impl Hash for Timestamp {
76
    #[inline]
77
0
    fn hash<H: Hasher>(&self, state: &mut H) {
78
0
        state.write_i128(self.as_i128());
79
0
    }
80
}
81
82
impl PartialEq for Timestamp {
83
    #[inline]
84
0
    fn eq(&self, other: &Self) -> bool {
85
0
        self.as_i128() == other.as_i128()
86
0
    }
87
}
88
89
impl PartialOrd for Timestamp {
90
    #[inline]
91
0
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
92
0
        Some(self.cmp(other))
93
0
    }
94
}
95
96
impl Ord for Timestamp {
97
    #[inline]
98
0
    fn cmp(&self, other: &Self) -> Ordering {
99
0
        self.as_i128().cmp(&other.as_i128())
100
0
    }
101
}
102
103
impl Timestamp {
104
    #[inline]
105
0
    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
0
        unsafe { core::mem::transmute(self) }
110
0
    }
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
0
    pub fn now() -> Self {
137
0
        SystemTime::now().into()
138
0
    }
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
0
    pub const unsafe fn __new_unchecked(seconds: i64, nanoseconds: u32) -> Self {
150
        // Safety: The caller must ensure both values are valid.
151
        unsafe {
152
0
            Self::new_ranged(
153
0
                Seconds::new_unchecked(seconds),
154
0
                Nanoseconds::new_unchecked(nanoseconds),
155
            )
156
        }
157
0
    }
158
159
    /// Create a `Timestamp` from the provided seconds and nanoseconds values that are known to be
160
    /// in range.
161
    #[inline]
162
0
    pub(crate) const fn new_ranged(seconds: Seconds, nanoseconds: Nanoseconds) -> Self {
163
0
        Self {
164
0
            seconds,
165
0
            nanoseconds,
166
0
            padding: Padding::Optimize,
167
0
        }
168
0
    }
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
0
    pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Self, error::ComponentRange> {
180
0
        Ok(Self::new_ranged(
181
0
            ensure_ranged!(Seconds: seconds),
182
0
            ensure_ranged!(Nanoseconds: nanoseconds),
183
        ))
184
0
    }
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
0
    pub const fn from_seconds(seconds: i64) -> Result<Self, error::ComponentRange> {
196
0
        Ok(Self::new_ranged(
197
0
            ensure_ranged!(Seconds: seconds),
198
0
            Nanoseconds::new_static::<0>(),
199
        ))
200
0
    }
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
0
    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
0
        ensure_ranged!(ri64<MIN, MAX>: milliseconds);
218
219
0
        let mut seconds = milliseconds / Millisecond::per_t::<i64>(Second);
220
0
        let nanoseconds = (milliseconds.rem_euclid(Millisecond::per_t(Second))
221
0
            * Nanosecond::per_t::<i64>(Millisecond)) as u32;
222
223
0
        if milliseconds < 0 && nanoseconds != 0 {
224
0
            seconds -= 1;
225
0
        }
226
227
        // Safety: The value provided was checked to be in range.
228
0
        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
229
0
    }
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
0
    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
0
        ensure_ranged!(ri128<MIN, MAX>: microseconds);
247
248
0
        let mut seconds = (microseconds / Microsecond::per_t::<i128>(Second)) as i64;
249
0
        let nanoseconds = (microseconds.rem_euclid(Microsecond::per_t(Second))
250
0
            * Nanosecond::per_t::<i128>(Microsecond)) as u32;
251
252
0
        if microseconds < 0 && nanoseconds != 0 {
253
0
            seconds -= 1;
254
0
        }
255
256
        // Safety: The value provided was checked to be in range.
257
0
        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
258
0
    }
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
0
    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
0
        ensure_ranged!(ri128<MIN, MAX>: nanoseconds);
276
277
0
        let input_is_negative = nanoseconds < 0;
278
0
        let mut seconds = (nanoseconds / Nanosecond::per_t::<i128>(Second)) as i64;
279
0
        let nanoseconds = nanoseconds.rem_euclid(Nanosecond::per_t(Second)) as u32;
280
281
0
        if input_is_negative && nanoseconds != 0 {
282
0
            seconds -= 1;
283
0
        }
284
285
        // Safety: The value provided was checked to be in range.
286
0
        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
287
0
    }
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
0
    pub const fn to_offset(self, offset: UtcOffset) -> OffsetDateTime {
303
0
        self.to_utc().to_offset(offset)
304
0
    }
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
0
    pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<OffsetDateTime> {
319
0
        self.to_utc().checked_to_offset(offset)
320
0
    }
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
0
    pub const fn to_utc(self) -> UtcDateTime {
330
0
        let Ok(utc_dt) = UtcDateTime::from_unix_timestamp(self.seconds.get()) else {
331
0
            bug!("timestamp was invalid beforehand");
332
        };
333
0
        let Ok(utc_dt) = utc_dt.replace_nanosecond(self.nanoseconds.get()) else {
334
0
            bug!("nanosecond was invalid beforehand");
335
        };
336
337
0
        utc_dt
338
0
    }
339
340
    /// Get the seconds and nanoseconds of the timestamp as ranged values.
341
    #[inline]
342
0
    pub(crate) const fn as_parts_ranged(self) -> (Seconds, Nanoseconds) {
343
0
        (self.seconds, self.nanoseconds)
344
0
    }
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
0
    pub const fn as_seconds(self) -> i64 {
356
0
        self.seconds.get()
357
0
    }
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
0
    pub const fn as_milliseconds(self) -> i64 {
372
0
        self.seconds.get() * Millisecond::per_t::<i64>(Second)
373
0
            + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as i64
374
0
    }
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
0
    pub const fn as_microseconds(self) -> i128 {
389
0
        self.seconds.get() as i128 * Microsecond::per_t::<i128>(Second)
390
0
            + (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)) as i128
391
0
    }
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
0
    pub const fn as_nanoseconds(self) -> i128 {
406
0
        self.seconds.get() as i128 * Nanosecond::per_t::<i128>(Second)
407
0
            + self.nanoseconds.get() as i128
408
0
    }
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
0
    pub const fn date(self) -> Date {
418
0
        self.to_utc().date()
419
0
    }
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
0
    pub const fn time(self) -> Time {
429
0
        let within_day = self.as_seconds().rem_euclid(Second::per_t::<i64>(Day)) as u32;
430
431
0
        let hour = within_day / Second::per_t::<u32>(Hour);
432
0
        let minute =
433
0
            (within_day - hour * Second::per_t::<u32>(Hour)) / Second::per_t::<u32>(Minute);
434
0
        let second =
435
0
            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
0
            Time::__from_hms_nanos_unchecked(
440
0
                hour as u8,
441
0
                minute as u8,
442
0
                second as u8,
443
0
                self.nanosecond(),
444
            )
445
        }
446
0
    }
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
0
    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
0
        let raw_day = div_floor!(self.as_seconds(), Second::per_t::<i64>(Day)) as i32;
464
465
0
        let day = raw_day.cast_unsigned().wrapping_add(D_SHIFT);
466
0
        let c_n = (day as u64 * CEN_MUL as u64) >> 15;
467
0
        let cen = (c_n >> 32) as u32;
468
0
        let cpt = c_n as u32;
469
0
        let ijy = cpt > CEN_CUT || cen.is_multiple_of(4);
470
0
        let jul = day - cen / 4 + cen;
471
0
        let y_n = (jul as u64 * JUL_MUL as u64) >> 8;
472
0
        let yrs = (y_n >> 32) as u32;
473
0
        let ypt = y_n as u32;
474
475
0
        let year = yrs.wrapping_sub(Y_SHIFT).cast_signed();
476
0
        let ordinal = ((ypt as u64 * 1_461) >> 34) as u32 + ijy as u32;
477
0
        let leap = yrs.is_multiple_of(4) & ijy;
478
479
0
        (year, leap, ordinal as u16)
480
0
    }
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
0
    pub const fn year(self) -> i32 {
490
0
        self.year_leap_ordinal().0
491
0
    }
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
0
    pub const fn month(self) -> Month {
502
0
        let (_, leap, ordinal) = self.year_leap_ordinal();
503
0
        util::leap_ordinal_to_month_day(leap, ordinal).0
504
0
    }
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
0
    pub const fn day(self) -> u8 {
516
0
        let (_, leap, ordinal) = self.year_leap_ordinal();
517
0
        util::leap_ordinal_to_month_day(leap, ordinal).1
518
0
    }
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
0
    pub const fn ordinal(self) -> u16 {
530
0
        self.year_leap_ordinal().2
531
0
    }
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
0
    pub const fn iso_week(self) -> u8 {
543
0
        self.date().iso_week()
544
0
    }
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
0
    pub const fn sunday_based_week(self) -> u8 {
556
0
        self.date().sunday_based_week()
557
0
    }
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
0
    pub const fn monday_based_week(self) -> u8 {
569
0
        self.date().monday_based_week()
570
0
    }
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
0
    pub const fn to_calendar_date(self) -> (i32, Month, u8) {
584
0
        let (year, leap, ordinal) = self.year_leap_ordinal();
585
0
        let (month, day) = util::leap_ordinal_to_month_day(leap, ordinal);
586
0
        (year, month, day)
587
0
    }
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
0
    pub const fn to_ordinal_date(self) -> (i32, u16) {
597
0
        let (year, _, ordinal) = self.year_leap_ordinal();
598
0
        (year, ordinal)
599
0
    }
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
0
    pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
613
0
        self.date().to_iso_week_date()
614
0
    }
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
0
    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
0
        match (div_floor!(self.seconds.get(), 86_400) + 365_961_669) % 7 {
631
0
            0 => Weekday::Monday,
632
0
            1 => Weekday::Tuesday,
633
0
            2 => Weekday::Wednesday,
634
0
            3 => Weekday::Thursday,
635
0
            4 => Weekday::Friday,
636
0
            5 => Weekday::Saturday,
637
0
            6 => Weekday::Sunday,
638
0
            _ => unreachable!(),
639
        }
640
0
    }
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
0
    pub const fn to_julian_day(self) -> i32 {
650
        const UNIX_EPOCH_JULIAN_DAY: i32 = Date::UNIX_EPOCH.to_julian_day();
651
0
        div_floor!(self.seconds.get(), 86_400) as i32 + UNIX_EPOCH_JULIAN_DAY
652
0
    }
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
0
    pub const fn as_hms(self) -> (u8, u8, u8) {
662
0
        self.time().as_hms()
663
0
    }
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
0
    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
673
0
        self.time().as_hms_milli()
674
0
    }
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
0
    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
687
0
        self.time().as_hms_micro()
688
0
    }
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
0
    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
701
0
        self.time().as_hms_nano()
702
0
    }
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
0
    pub const fn hour(self) -> u8 {
712
0
        self.time().hour()
713
0
    }
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
0
    pub const fn minute(self) -> u8 {
723
0
        (div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute)))
724
0
            .rem_euclid(Minute::per_t(Hour)) as u8
725
0
    }
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
0
    pub const fn second(self) -> u8 {
735
0
        self.seconds.get().rem_euclid(Second::per_t(Minute)) as u8
736
0
    }
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
0
    pub const fn millisecond(self) -> u16 {
746
0
        (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
747
0
    }
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
0
    pub const fn microsecond(self) -> u32 {
757
0
        self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)
758
0
    }
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
0
    pub const fn nanosecond(self) -> u32 {
771
0
        self.nanoseconds.get()
772
0
    }
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
0
    const fn add(self, duration: SignedDuration) -> Result<Self, Overflow> {
778
0
        let (second_adj, nanoseconds) = if duration.is_negative() {
779
0
            let nanos = self.nanoseconds.get() as i32 + duration.subsec_nanoseconds();
780
0
            if nanos < 0 {
781
0
                (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
782
            } else {
783
0
                (0, nanos as u32)
784
            }
785
        } else {
786
0
            let nanos = self.nanoseconds.get() + duration.subsec_nanoseconds() as u32;
787
0
            if nanos >= Nanosecond::per_t(Second) {
788
0
                (1, nanos - Nanosecond::per_t::<u32>(Second))
789
            } else {
790
0
                (0, nanos)
791
            }
792
        };
793
794
0
        let seconds = match self.seconds.get().checked_add(duration.whole_seconds()) {
795
0
            Some(seconds) => seconds,
796
0
            None if duration.is_negative() => return Err(Overflow::Negative),
797
0
            None => return Err(Overflow::Positive),
798
        };
799
0
        let seconds = match seconds.checked_add(second_adj) {
800
0
            Some(seconds) => seconds,
801
0
            None if second_adj < 0 => return Err(Overflow::Negative),
802
0
            None => return Err(Overflow::Positive),
803
        };
804
805
        // Check if the resulting seconds are within the valid range
806
0
        if seconds < Seconds::MIN.get() {
807
0
            return Err(Overflow::Negative);
808
0
        } else if seconds > Seconds::MAX.get() {
809
0
            return Err(Overflow::Positive);
810
0
        }
811
812
        // Safety: Both values are guaranteed to be in range.
813
0
        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
814
0
    }
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
0
    const fn sub(self, duration: SignedDuration) -> Result<Self, Overflow> {
820
0
        let nanos = self.nanoseconds.get() as i32 - duration.subsec_nanoseconds();
821
0
        let (second_adj, nanoseconds) = if duration.is_negative() {
822
0
            if nanos >= Nanosecond::per_t::<i32>(Second) {
823
0
                (1, (nanos - Nanosecond::per_t::<i32>(Second)) as u32)
824
0
            } else if nanos < 0 {
825
0
                (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
826
            } else {
827
0
                (0, nanos as u32)
828
            }
829
        } else {
830
0
            if nanos < 0 {
831
0
                (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
832
            } else {
833
0
                (0, nanos as u32)
834
            }
835
        };
836
837
0
        let seconds = match self.seconds.get().checked_sub(duration.whole_seconds()) {
838
0
            Some(seconds) => seconds,
839
0
            None if duration.is_negative() => return Err(Overflow::Positive),
840
0
            None => return Err(Overflow::Negative),
841
        };
842
0
        let seconds = match seconds.checked_add(second_adj) {
843
0
            Some(seconds) => seconds,
844
0
            None if second_adj < 0 => return Err(Overflow::Negative),
845
0
            None => return Err(Overflow::Positive),
846
        };
847
848
        // Check if the resulting seconds are within the valid range
849
0
        if seconds < Seconds::MIN.get() {
850
0
            return Err(Overflow::Negative);
851
0
        } else if seconds > Seconds::MAX.get() {
852
0
            return Err(Overflow::Positive);
853
0
        }
854
855
        // Safety: Both values are guaranteed to be in range.
856
0
        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
857
0
    }
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
0
    const fn add_std(self, duration: StdDuration) -> Result<Self, Overflow> {
863
0
        let Some(mut seconds) = self.seconds.get().checked_add_unsigned(duration.as_secs()) else {
864
0
            return Err(Overflow::Positive);
865
        };
866
0
        let mut nanoseconds = self.nanoseconds.get() + duration.subsec_nanos();
867
868
0
        if nanoseconds >= Nanosecond::per_t(Second) {
869
0
            nanoseconds -= Nanosecond::per_t::<u32>(Second);
870
0
            let Some(new_seconds) = seconds.checked_add(1) else {
871
0
                return Err(Overflow::Positive);
872
            };
873
0
            seconds = new_seconds;
874
0
        }
875
876
        // Check if the resulting seconds are within the valid range
877
0
        if seconds < Seconds::MIN.get() {
878
0
            return Err(Overflow::Negative);
879
0
        } else if seconds > Seconds::MAX.get() {
880
0
            return Err(Overflow::Positive);
881
0
        }
882
883
        // Safety: Both values are guaranteed to be in range.
884
0
        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
885
0
    }
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
0
    const fn sub_std(self, duration: StdDuration) -> Result<Self, Overflow> {
891
0
        let Some(mut seconds) = self.seconds.get().checked_sub_unsigned(duration.as_secs()) else {
892
0
            return Err(Overflow::Negative);
893
        };
894
0
        let mut nanoseconds = self.nanoseconds.get() as i32 - duration.subsec_nanos() as i32;
895
896
0
        if nanoseconds < 0 {
897
0
            nanoseconds += Nanosecond::per_t::<i32>(Second);
898
0
            let Some(new_seconds) = seconds.checked_sub(1) else {
899
0
                return Err(Overflow::Negative);
900
            };
901
0
            seconds = new_seconds;
902
0
        }
903
904
        // Check if the resulting seconds are within the valid range
905
0
        if seconds < Seconds::MIN.get() {
906
0
            return Err(Overflow::Negative);
907
0
        } else if seconds > Seconds::MAX.get() {
908
0
            return Err(Overflow::Positive);
909
0
        }
910
911
        // Safety: Both values are guaranteed to be in range.
912
0
        Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds as u32) })
913
0
    }
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
0
    pub const fn checked_add(self, duration: SignedDuration) -> Option<Self> {
931
0
        match self.add(duration) {
932
0
            Ok(timestamp) => Some(timestamp),
933
0
            Err(Overflow::Positive | Overflow::Negative) => None,
934
        }
935
0
    }
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
0
    pub const fn checked_sub(self, duration: SignedDuration) -> Option<Self> {
953
0
        match self.sub(duration) {
954
0
            Ok(timestamp) => Some(timestamp),
955
0
            Err(Overflow::Positive | Overflow::Negative) => None,
956
        }
957
0
    }
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
0
    pub const fn saturating_add(self, duration: SignedDuration) -> Self {
976
0
        match self.add(duration) {
977
0
            Ok(timestamp) => timestamp,
978
0
            Err(Overflow::Positive) => Self::MAX,
979
0
            Err(Overflow::Negative) => Self::MIN,
980
        }
981
0
    }
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
0
    pub const fn saturating_sub(self, duration: SignedDuration) -> Self {
1000
0
        match self.sub(duration) {
1001
0
            Ok(timestamp) => timestamp,
1002
0
            Err(Overflow::Positive) => Self::MAX,
1003
0
            Err(Overflow::Negative) => Self::MIN,
1004
        }
1005
0
    }
1006
}
1007
1008
/// Methods that replace part of the `Timestamp`.
1009
impl 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
0
    pub const fn replace_time(self, time: Time) -> Self {
1022
0
        let seconds_since_midnight = time.hour() as i64 * Second::per_t::<i64>(Hour)
1023
0
            + time.minute() as i64 * Second::per_t::<i64>(Minute)
1024
0
            + time.second() as i64;
1025
0
        let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Day))
1026
0
            * Second::per_t::<i64>(Day)
1027
0
            + 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
0
        unsafe { Self::__new_unchecked(seconds, time.nanosecond()) }
1032
0
    }
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
0
    pub const fn replace_date(mut self, date: Date) -> Self {
1046
0
        let seconds_after_midnight = self.seconds.get().rem_euclid(Second::per_t(Day));
1047
0
        let seconds = (date.to_julian_day() as i64
1048
0
            - UtcDateTime::UNIX_EPOCH.to_julian_day() as i64)
1049
0
            * Second::per_t::<i64>(Day)
1050
0
            + 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
0
        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1054
0
        self
1055
0
    }
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
0
    pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1072
0
        let date = const_try!(self.date().replace_year(year));
1073
0
        Ok(self.replace_date(date))
1074
0
    }
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
0
    pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1095
0
        let date = const_try!(self.date().replace_month(month));
1096
0
        Ok(self.replace_date(date))
1097
0
    }
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
0
    pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1113
0
        let date = const_try!(self.date().replace_day(day));
1114
0
        Ok(self.replace_date(date))
1115
0
    }
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
0
    pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1131
0
        let date = const_try!(self.date().replace_ordinal(ordinal));
1132
0
        Ok(self.replace_date(date))
1133
0
    }
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
0
    pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
1148
0
        ensure_ranged!(ru8<0, 23>: hour);
1149
0
        let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Day))
1150
0
            * Second::per_t::<i64>(Day)
1151
0
            + hour as i64 * Second::per_t::<i64>(Hour)
1152
0
            + self.minute() as i64 * Second::per_t::<i64>(Minute)
1153
0
            + self.second() as i64;
1154
        // Safety: Any value is valid so long as `hour` is in range.
1155
0
        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1156
0
        Ok(self)
1157
0
    }
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
0
    pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
1172
0
        ensure_ranged!(ru8<0, 59>: minute);
1173
0
        let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Hour))
1174
0
            * Second::per_t::<i64>(Hour)
1175
0
            + minute as i64 * Second::per_t::<i64>(Minute)
1176
0
            + self.second() as i64;
1177
        // Safety: Any value is valid so long as `minute` is in range.
1178
0
        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1179
0
        Ok(self)
1180
0
    }
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
0
    pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
1195
0
        ensure_ranged!(ru8<0, 59>: second);
1196
0
        let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute))
1197
0
            * Second::per_t::<i64>(Minute)
1198
0
            + second as i64;
1199
        // Safety: Any value is valid so long as `second` is in range.
1200
0
        self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1201
0
        Ok(self)
1202
0
    }
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
0
    pub const fn replace_millisecond(
1221
0
        self,
1222
0
        millisecond: u16,
1223
0
    ) -> Result<Self, error::ComponentRange> {
1224
0
        let nanos =
1225
0
            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
1226
0
        Ok(self.replace_nanosecond_ranged(nanos))
1227
0
    }
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
0
    pub const fn replace_microsecond(
1246
0
        self,
1247
0
        microsecond: u32,
1248
0
    ) -> Result<Self, error::ComponentRange> {
1249
0
        let nanos =
1250
0
            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
1251
0
        Ok(self.replace_nanosecond_ranged(nanos))
1252
0
    }
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
0
    pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1271
0
        let nanos = ensure_ranged!(Nanoseconds: nanosecond);
1272
0
        Ok(self.replace_nanosecond_ranged(nanos))
1273
0
    }
1274
1275
    /// Replace the nanoseconds within the second using a range-bounded integer to avoid range
1276
    /// checks.
1277
    #[inline]
1278
0
    const fn replace_nanosecond_ranged(self, new_nanos: Nanoseconds) -> Self {
1279
0
        let (seconds, nanoseconds) = self.as_parts_ranged();
1280
1281
0
        if seconds.get() >= 0 || nanoseconds.get() == 0 {
1282
0
            Self::new_ranged(seconds, new_nanos)
1283
0
        } 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
0
            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
0
            Self::new_ranged(seconds, unsafe {
1292
0
                Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - new_nanos.get())
1293
            })
1294
        }
1295
0
    }
1296
}
1297
1298
#[cfg(feature = "formatting")]
1299
impl 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")]
1325
impl 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
1372
impl 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
0
    pub(crate) fn fmt_into_buffer(
1379
0
        self,
1380
0
        buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
1381
0
    ) -> usize {
1382
0
        let mut idx = 0;
1383
1384
0
        let mut second = self.seconds.get();
1385
0
        let mut nanosecond = self.nanoseconds;
1386
1387
0
        if second < 0 {
1388
0
            buf[idx] = MaybeUninit::new(b'-');
1389
0
            idx += 1;
1390
1391
0
            second = -second;
1392
1393
0
            if nanosecond != Nanoseconds::new_static::<0>() {
1394
0
                second -= 1;
1395
0
                // Safety: `nanosecond` is in the range 1..=999_999_999, so subtracting it from
1396
0
                // 1_000_000_000 will always yield a value in the range 1..=999_999_999, which is a
1397
0
                // subset of the valid range for `Nanoseconds`.
1398
0
                nanosecond = unsafe {
1399
0
                    Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - nanosecond.get())
1400
0
                };
1401
0
            }
1402
0
        }
1403
1404
0
        let seconds_str = u64_pad_none(second.cast_unsigned());
1405
0
        let seconds_len = seconds_str.len();
1406
        // Safety: `buf` has sufficient capacity for the seconds digits.
1407
0
        unsafe {
1408
0
            seconds_str
1409
0
                .as_ptr()
1410
0
                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), seconds_len);
1411
0
        }
1412
0
        idx += seconds_len;
1413
1414
0
        if nanosecond != Nanoseconds::new_static::<0>() {
1415
0
            buf[idx] = MaybeUninit::new(b'.');
1416
0
            idx += 1;
1417
0
1418
0
            let subsecond = truncated_subsecond_from_nanos(nanosecond);
1419
0
            // Safety: `buf` has sufficient capacity for the subsecond digits.
1420
0
            unsafe {
1421
0
                subsecond
1422
0
                    .as_ptr()
1423
0
                    .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len());
1424
0
            }
1425
0
            idx += subsecond.len();
1426
0
        }
1427
1428
0
        idx
1429
0
    }
1430
}
1431
1432
impl fmt::Display for Timestamp {
1433
    #[inline]
1434
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1435
0
        let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1436
0
        let len = self.fmt_into_buffer(&mut buf);
1437
        // Safety: All bytes up to `len` have been initialized with ASCII characters.
1438
0
        let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1439
0
        f.pad(s)
1440
0
    }
1441
}
1442
1443
impl fmt::Debug for Timestamp {
1444
    #[inline]
1445
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1446
0
        fmt::Display::fmt(self, f)
1447
0
    }
1448
}
1449
1450
impl 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
0
    fn add(self, rhs: SignedDuration) -> Self::Output {
1459
0
        self.checked_add(rhs)
1460
0
            .expect("resulting value is out of range")
1461
0
    }
1462
}
1463
1464
impl 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
0
    fn add(self, rhs: StdDuration) -> Self::Output {
1473
0
        self.add_std(rhs).expect("resulting value is out of range")
1474
0
    }
1475
}
1476
1477
impl AddAssign<SignedDuration> for Timestamp {
1478
    /// # Panics
1479
    ///
1480
    /// This may panic if an overflow occurs.
1481
    #[inline]
1482
    #[track_caller]
1483
0
    fn add_assign(&mut self, rhs: SignedDuration) {
1484
0
        *self = *self + rhs;
1485
0
    }
1486
}
1487
1488
impl AddAssign<StdDuration> for Timestamp {
1489
    /// # Panics
1490
    ///
1491
    /// This may panic if an overflow occurs.
1492
    #[inline]
1493
    #[track_caller]
1494
0
    fn add_assign(&mut self, rhs: StdDuration) {
1495
0
        *self = *self + rhs;
1496
0
    }
1497
}
1498
1499
impl 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
0
    fn sub(self, rhs: SignedDuration) -> Self::Output {
1508
0
        self.checked_sub(rhs)
1509
0
            .expect("resulting value is out of range")
1510
0
    }
1511
}
1512
1513
impl 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
0
    fn sub(self, rhs: StdDuration) -> Self::Output {
1522
0
        self.sub_std(rhs).expect("resulting value is out of range")
1523
0
    }
1524
}
1525
1526
impl SubAssign<SignedDuration> for Timestamp {
1527
    /// # Panics
1528
    ///
1529
    /// This may panic if an overflow occurs.
1530
    #[inline]
1531
    #[track_caller]
1532
0
    fn sub_assign(&mut self, rhs: SignedDuration) {
1533
0
        *self = *self - rhs;
1534
0
    }
1535
}
1536
1537
impl SubAssign<StdDuration> for Timestamp {
1538
    /// # Panics
1539
    ///
1540
    /// This may panic if an overflow occurs.
1541
    #[inline]
1542
    #[track_caller]
1543
0
    fn sub_assign(&mut self, rhs: StdDuration) {
1544
0
        *self = *self - rhs;
1545
0
    }
1546
}
1547
1548
impl Sub for Timestamp {
1549
    type Output = SignedDuration;
1550
1551
    #[inline]
1552
0
    fn sub(self, rhs: Self) -> Self::Output {
1553
0
        let seconds = self.seconds.get() - rhs.seconds.get();
1554
0
        let nanoseconds = self.nanoseconds.get() as i32 - rhs.nanoseconds.get() as i32;
1555
1556
0
        if nanoseconds < 0 {
1557
0
            SignedDuration::new(seconds - 1, nanoseconds + Nanosecond::per_t::<i32>(Second))
1558
        } else {
1559
0
            SignedDuration::new(seconds, nanoseconds)
1560
        }
1561
0
    }
1562
}