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