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