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