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