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 /// The returned value will always be in the range `0..24`.
709 ///
710 /// ```rust
711 /// # use time_macros::timestamp;
712 /// assert_eq!(timestamp!(1_546_398_245).hour(), 3);
713 /// ```
714 #[inline]
715 pub const fn hour(self) -> u8 {
716 self.time().hour()
717 }
718
719 /// Get the minute of the timestamp in UTC.
720 ///
721 /// The returned value will always be in the range `0..60`.
722 ///
723 /// ```rust
724 /// # use time_macros::timestamp;
725 /// assert_eq!(timestamp!(1_546_398_245).minute(), 4);
726 /// ```
727 #[inline]
728 pub const fn minute(self) -> u8 {
729 (div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute)))
730 .rem_euclid(Minute::per_t(Hour)) as u8
731 }
732
733 /// Get the second of the timestamp in UTC.
734 ///
735 /// The returned value will always be in the range `0..60`.
736 ///
737 /// ```rust
738 /// # use time_macros::timestamp;
739 /// assert_eq!(timestamp!(1_546_398_245).second(), 5);
740 /// ```
741 #[inline]
742 pub const fn second(self) -> u8 {
743 self.seconds.get().rem_euclid(Second::per_t(Minute)) as u8
744 }
745
746 /// Get the millisecond of the timestamp in UTC.
747 ///
748 /// The returned value will always be in the range `0..1_000`.
749 ///
750 /// ```rust
751 /// # use time_macros::timestamp;
752 /// assert_eq!(timestamp!(1_546_398_245.006).millisecond(), 6);
753 /// ```
754 #[inline]
755 pub const fn millisecond(self) -> u16 {
756 (self.nanoseconds.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
757 }
758
759 /// Get the microsecond of the timestamp in UTC.
760 ///
761 /// The returned value will always be in the range `0..1_000_000`.
762 ///
763 /// ```rust
764 /// # use time_macros::timestamp;
765 /// assert_eq!(timestamp!(1_546_398_245.006_007).microsecond(), 6_007);
766 /// ```
767 #[inline]
768 pub const fn microsecond(self) -> u32 {
769 self.nanoseconds.get() / Nanosecond::per_t::<u32>(Microsecond)
770 }
771
772 /// Get the nanosecond of the timestamp in UTC.
773 ///
774 /// The returned value will always be in the range `0..1_000_000_000`.
775 ///
776 /// ```rust
777 /// # use time_macros::timestamp;
778 /// assert_eq!(
779 /// timestamp!(1_546_398_245.006_007_008).nanosecond(),
780 /// 6_007_008
781 /// );
782 /// ```
783 #[inline]
784 pub const fn nanosecond(self) -> u32 {
785 self.nanoseconds.get()
786 }
787
788 /// Add a [`SignedDuration`] to the timestamp. Returns `Overflow::Positive` or
789 /// `Overflow::Negative` if the result is out of range.
790 #[inline]
791 const fn add(self, duration: SignedDuration) -> Result<Self, Overflow> {
792 let (second_adj, nanoseconds) = if duration.is_negative() {
793 let nanos = self.nanoseconds.get() as i32 + duration.subsec_nanoseconds();
794 if nanos < 0 {
795 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
796 } else {
797 (0, nanos as u32)
798 }
799 } else {
800 let nanos = self.nanoseconds.get() + duration.subsec_nanoseconds() as u32;
801 if nanos >= Nanosecond::per_t(Second) {
802 (1, nanos - Nanosecond::per_t::<u32>(Second))
803 } else {
804 (0, nanos)
805 }
806 };
807
808 let seconds = match self.seconds.get().checked_add(duration.whole_seconds()) {
809 Some(seconds) => seconds,
810 None if duration.is_negative() => return Err(Overflow::Negative),
811 None => return Err(Overflow::Positive),
812 };
813 let seconds = match seconds.checked_add(second_adj) {
814 Some(seconds) => seconds,
815 None if second_adj < 0 => return Err(Overflow::Negative),
816 None => return Err(Overflow::Positive),
817 };
818
819 // Check if the resulting seconds are within the valid range
820 if seconds < Seconds::MIN.get() {
821 return Err(Overflow::Negative);
822 } else if seconds > Seconds::MAX.get() {
823 return Err(Overflow::Positive);
824 }
825
826 // Safety: Both values are guaranteed to be in range.
827 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
828 }
829
830 /// Subtract a [`SignedDuration`] from the timestamp. Returns `Overflow::Positive` or
831 /// `Overflow::Negative` if the result is out of range.
832 #[inline]
833 const fn sub(self, duration: SignedDuration) -> Result<Self, Overflow> {
834 let nanos = self.nanoseconds.get() as i32 - duration.subsec_nanoseconds();
835 let (second_adj, nanoseconds) = if duration.is_negative() {
836 if nanos >= Nanosecond::per_t::<i32>(Second) {
837 (1, (nanos - Nanosecond::per_t::<i32>(Second)) as u32)
838 } else if nanos < 0 {
839 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
840 } else {
841 (0, nanos as u32)
842 }
843 } else {
844 if nanos < 0 {
845 (-1, (nanos + Nanosecond::per_t::<i32>(Second)) as u32)
846 } else {
847 (0, nanos as u32)
848 }
849 };
850
851 let seconds = match self.seconds.get().checked_sub(duration.whole_seconds()) {
852 Some(seconds) => seconds,
853 None if duration.is_negative() => return Err(Overflow::Positive),
854 None => return Err(Overflow::Negative),
855 };
856 let seconds = match seconds.checked_add(second_adj) {
857 Some(seconds) => seconds,
858 None if second_adj < 0 => return Err(Overflow::Negative),
859 None => return Err(Overflow::Positive),
860 };
861
862 // Check if the resulting seconds are within the valid range
863 if seconds < Seconds::MIN.get() {
864 return Err(Overflow::Negative);
865 } else if seconds > Seconds::MAX.get() {
866 return Err(Overflow::Positive);
867 }
868
869 // Safety: Both values are guaranteed to be in range.
870 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
871 }
872
873 /// Add a [`std::time::Duration`] to the timestamp. Returns `Overflow::Positive` or
874 /// `Overflow::Negative` if the result is out of range.
875 #[inline]
876 const fn add_std(self, duration: StdDuration) -> Result<Self, Overflow> {
877 let Some(mut seconds) = self.seconds.get().checked_add_unsigned(duration.as_secs()) else {
878 return Err(Overflow::Positive);
879 };
880 let mut nanoseconds = self.nanoseconds.get() + duration.subsec_nanos();
881
882 if nanoseconds >= Nanosecond::per_t(Second) {
883 nanoseconds -= Nanosecond::per_t::<u32>(Second);
884 let Some(new_seconds) = seconds.checked_add(1) else {
885 return Err(Overflow::Positive);
886 };
887 seconds = new_seconds;
888 }
889
890 // Check if the resulting seconds are within the valid range
891 if seconds < Seconds::MIN.get() {
892 return Err(Overflow::Negative);
893 } else if seconds > Seconds::MAX.get() {
894 return Err(Overflow::Positive);
895 }
896
897 // Safety: Both values are guaranteed to be in range.
898 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds) })
899 }
900
901 /// Subtract a [`std::time::Duration`] from the timestamp. Returns `Overflow::Positive` or
902 /// `Overflow::Negative` if the result is out of range.
903 #[inline]
904 const fn sub_std(self, duration: StdDuration) -> Result<Self, Overflow> {
905 let Some(mut seconds) = self.seconds.get().checked_sub_unsigned(duration.as_secs()) else {
906 return Err(Overflow::Negative);
907 };
908 let mut nanoseconds = self.nanoseconds.get() as i32 - duration.subsec_nanos() as i32;
909
910 if nanoseconds < 0 {
911 nanoseconds += Nanosecond::per_t::<i32>(Second);
912 let Some(new_seconds) = seconds.checked_sub(1) else {
913 return Err(Overflow::Negative);
914 };
915 seconds = new_seconds;
916 }
917
918 // Check if the resulting seconds are within the valid range
919 if seconds < Seconds::MIN.get() {
920 return Err(Overflow::Negative);
921 } else if seconds > Seconds::MAX.get() {
922 return Err(Overflow::Positive);
923 }
924
925 // Safety: Both values are guaranteed to be in range.
926 Ok(unsafe { Self::__new_unchecked(seconds, nanoseconds as u32) })
927 }
928
929 /// Checked addition of a [`SignedDuration`], returning `None` if the result is out of range.
930 ///
931 /// ```rust
932 /// # use time_macros::timestamp;
933 /// # use time::ext::NumericalDuration as _;
934 /// assert_eq!(
935 /// timestamp!(1_546_398_245).checked_add(1.days()),
936 /// Some(timestamp!(1_546_484_645))
937 /// );
938 /// assert_eq!(
939 /// timestamp!(1_546_398_245).checked_add((-1).days()),
940 /// Some(timestamp!(1_546_311_845))
941 /// );
942 /// ```
943 #[inline]
944 pub const fn checked_add(self, duration: SignedDuration) -> Option<Self> {
945 match self.add(duration) {
946 Ok(timestamp) => Some(timestamp),
947 Err(Overflow::Positive | Overflow::Negative) => None,
948 }
949 }
950
951 /// Checked subtraction of a [`SignedDuration`], returning `None` if the result is out of range.
952 ///
953 /// ```rust
954 /// # use time_macros::timestamp;
955 /// # use time::ext::NumericalDuration as _;
956 /// assert_eq!(
957 /// timestamp!(1_546_398_245).checked_sub(1.days()),
958 /// Some(timestamp!(1_546_311_845))
959 /// );
960 /// assert_eq!(
961 /// timestamp!(1_546_398_245).checked_sub((-1).days()),
962 /// Some(timestamp!(1_546_484_645))
963 /// );
964 /// ```
965 #[inline]
966 pub const fn checked_sub(self, duration: SignedDuration) -> Option<Self> {
967 match self.sub(duration) {
968 Ok(timestamp) => Some(timestamp),
969 Err(Overflow::Positive | Overflow::Negative) => None,
970 }
971 }
972
973 /// Saturating addition of a [`SignedDuration`].
974 ///
975 /// Returns [`Timestamp::MAX`] or [`Timestamp::MIN`] if the result is out of range.
976 ///
977 /// ```rust
978 /// # use time::Timestamp;
979 /// # use time_macros::timestamp;
980 /// # use time::ext::NumericalDuration as _;
981 /// assert_eq!(
982 /// timestamp!(1_546_398_245).saturating_add(1.days()),
983 /// timestamp!(1_546_484_645)
984 /// );
985 /// assert_eq!(Timestamp::MAX.saturating_add(1.days()), Timestamp::MAX);
986 /// assert_eq!(Timestamp::MIN.saturating_add((-1).days()), Timestamp::MIN);
987 /// ```
988 #[inline]
989 pub const fn saturating_add(self, duration: SignedDuration) -> Self {
990 match self.add(duration) {
991 Ok(timestamp) => timestamp,
992 Err(Overflow::Positive) => Self::MAX,
993 Err(Overflow::Negative) => Self::MIN,
994 }
995 }
996
997 /// Saturating subtraction of a [`SignedDuration`].
998 ///
999 /// Returns [`Timestamp::MAX`] or [`Timestamp::MIN`] if the result is out of range.
1000 ///
1001 /// ```rust
1002 /// # use time::Timestamp;
1003 /// # use time_macros::timestamp;
1004 /// # use time::ext::NumericalDuration as _;
1005 /// assert_eq!(
1006 /// timestamp!(1_546_398_245).saturating_sub(1.days()),
1007 /// timestamp!(1_546_311_845)
1008 /// );
1009 /// assert_eq!(Timestamp::MIN.saturating_sub(1.days()), Timestamp::MIN);
1010 /// assert_eq!(Timestamp::MAX.saturating_sub((-1).days()), Timestamp::MAX);
1011 /// ```
1012 #[inline]
1013 pub const fn saturating_sub(self, duration: SignedDuration) -> Self {
1014 match self.sub(duration) {
1015 Ok(timestamp) => timestamp,
1016 Err(Overflow::Positive) => Self::MAX,
1017 Err(Overflow::Negative) => Self::MIN,
1018 }
1019 }
1020}
1021
1022/// Methods that replace part of the `Timestamp`.
1023impl Timestamp {
1024 /// Replace the time, preserving the date.
1025 ///
1026 /// ```rust
1027 /// # use time_macros::{time, timestamp};
1028 /// assert_eq!(
1029 /// timestamp!(1_546_398_245).replace_time(time!(12:34:56)),
1030 /// timestamp!(1_546_432_496)
1031 /// );
1032 /// ```
1033 #[inline]
1034 #[must_use = "This method does not mutate the original `Timestamp`."]
1035 pub const fn replace_time(self, time: Time) -> Self {
1036 let seconds_since_midnight = time.hour() as i64 * Second::per_t::<i64>(Hour)
1037 + time.minute() as i64 * Second::per_t::<i64>(Minute)
1038 + time.second() as i64;
1039 let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Day))
1040 * Second::per_t::<i64>(Day)
1041 + seconds_since_midnight;
1042 // Safety: Seconds is constructed from an existing valid value, and nanoseconds are always
1043 // in range given the origin. Any time of day is valid for any date in range, as enforced by
1044 // const assertions.
1045 unsafe { Self::__new_unchecked(seconds, time.nanosecond()) }
1046 }
1047
1048 /// Replace the date, preserving the time.
1049 ///
1050 /// ```rust
1051 /// # use time_macros::{date, timestamp};
1052 /// assert_eq!(
1053 /// timestamp!(1_546_398_245).replace_date(date!(2020-01-02)),
1054 /// timestamp!(1_577_934_245)
1055 /// );
1056 /// ```
1057 #[inline]
1058 #[must_use = "This method does not mutate the original `Timestamp`."]
1059 pub const fn replace_date(mut self, date: Date) -> Self {
1060 let seconds_after_midnight = self.seconds.get().rem_euclid(Second::per_t(Day));
1061 let seconds = (date.to_julian_day() as i64
1062 - UtcDateTime::UNIX_EPOCH.to_julian_day() as i64)
1063 * Second::per_t::<i64>(Day)
1064 + seconds_after_midnight;
1065 // Safety: The range of valid dates is identical to the range of valid timestamps, so any
1066 // date is necessarily valid.
1067 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1068 self
1069 }
1070
1071 /// Replace the year, preserving the month and day. If the date is February 29 and the resulting
1072 /// year is not a leap year, an error is returned.
1073 ///
1074 /// ```rust
1075 /// # use time_macros::timestamp;
1076 /// assert_eq!(
1077 /// timestamp!(1_546_398_245).replace_year(2020),
1078 /// Ok(timestamp!(1_577_934_245))
1079 /// );
1080 /// assert!(timestamp!(1_546_398_245).replace_year(-1_000_000).is_err()); // -1_000_000 isn't a valid year
1081 /// assert!(timestamp!(1_546_398_245).replace_year(1_000_000).is_err()); // 1_000_000 isn't a valid year
1082 /// ```
1083 #[inline]
1084 #[must_use = "This method does not mutate the original `Timestamp`."]
1085 pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1086 let date = const_try!(self.date().replace_year(year));
1087 Ok(self.replace_date(date))
1088 }
1089
1090 /// Replace the month of the year, preserving the year and day. If the day is invalid for the
1091 /// resulting month, an error is returned.
1092 ///
1093 /// ```rust
1094 /// # use time_macros::timestamp;
1095 /// # use time::Month;
1096 /// assert_eq!(
1097 /// timestamp!(1_546_398_245).replace_month(Month::February),
1098 /// Ok(timestamp!(1_549_076_645))
1099 /// );
1100 /// assert!(
1101 /// timestamp!(1_548_817_445)
1102 /// .replace_month(Month::February)
1103 /// .is_err()
1104 /// ); // the day of the month is 30, which is invalid for February
1105 /// ```
1106 #[inline]
1107 #[must_use = "This method does not mutate the original `Timestamp`."]
1108 pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1109 let date = const_try!(self.date().replace_month(month));
1110 Ok(self.replace_date(date))
1111 }
1112
1113 /// Replace the day of the month.
1114 ///
1115 /// ```rust
1116 /// # use time_macros::timestamp;
1117 /// assert_eq!(
1118 /// timestamp!(1_546_398_245).replace_day(1),
1119 /// Ok(timestamp!(1_546_311_845))
1120 /// );
1121 /// assert!(timestamp!(1_546_398_245).replace_day(0).is_err()); // 00 isn't a valid day
1122 /// assert!(timestamp!(1_546_398_245).replace_day(32).is_err()); // 32 isn't a valid day
1123 /// ```
1124 #[inline]
1125 #[must_use = "This method does not mutate the original `Timestamp`."]
1126 pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1127 let date = const_try!(self.date().replace_day(day));
1128 Ok(self.replace_date(date))
1129 }
1130
1131 /// Replace the day of the year.
1132 ///
1133 /// ```rust
1134 /// # use time_macros::timestamp;
1135 /// assert_eq!(
1136 /// timestamp!(1_546_398_245).replace_ordinal(1),
1137 /// Ok(timestamp!(1_546_311_845))
1138 /// );
1139 /// assert!(timestamp!(1_546_398_245).replace_ordinal(0).is_err()); // 0 isn't a valid day of the year
1140 /// assert!(timestamp!(1_546_398_245).replace_ordinal(366).is_err()); // the timestamp is in 2019, which isn't a leap year
1141 /// ```
1142 #[inline]
1143 #[must_use = "This method does not mutate the original `Timestamp`."]
1144 pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1145 let date = const_try!(self.date().replace_ordinal(ordinal));
1146 Ok(self.replace_date(date))
1147 }
1148
1149 /// Replace the clock hour.
1150 ///
1151 /// ```rust
1152 /// # use time_macros::timestamp;
1153 /// assert_eq!(
1154 /// timestamp!(1_546_398_245).replace_hour(0),
1155 /// Ok(timestamp!(1_546_387_445))
1156 /// );
1157 /// assert!(timestamp!(1_546_398_245).replace_hour(24).is_err()); // 24 isn't a valid hour
1158 /// ```
1159 #[inline]
1160 #[must_use = "This method does not mutate the original `Timestamp`."]
1161 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
1162 ensure_ranged!(ru8<0, 23>: hour);
1163 let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Day))
1164 * Second::per_t::<i64>(Day)
1165 + hour as i64 * Second::per_t::<i64>(Hour)
1166 + self.minute() as i64 * Second::per_t::<i64>(Minute)
1167 + self.second() as i64;
1168 // Safety: Any value is valid so long as `hour` is in range.
1169 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1170 Ok(self)
1171 }
1172
1173 /// Replace the minutes within the hour.
1174 ///
1175 /// ```rust
1176 /// # use time_macros::timestamp;
1177 /// assert_eq!(
1178 /// timestamp!(1_546_398_245).replace_minute(0),
1179 /// Ok(timestamp!(1_546_398_005))
1180 /// );
1181 /// assert!(timestamp!(1_546_398_245).replace_minute(60).is_err()); // 60 isn't a valid minute
1182 /// ```
1183 #[inline]
1184 #[must_use = "This method does not mutate the original `Timestamp`."]
1185 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
1186 ensure_ranged!(ru8<0, 59>: minute);
1187 let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Hour))
1188 * Second::per_t::<i64>(Hour)
1189 + minute as i64 * Second::per_t::<i64>(Minute)
1190 + self.second() as i64;
1191 // Safety: Any value is valid so long as `minute` is in range.
1192 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1193 Ok(self)
1194 }
1195
1196 /// Replace the seconds within the minute.
1197 ///
1198 /// ```rust
1199 /// # use time_macros::timestamp;
1200 /// assert_eq!(
1201 /// timestamp!(1_546_398_245).replace_second(0),
1202 /// Ok(timestamp!(1_546_398_240))
1203 /// );
1204 /// assert!(timestamp!(1_546_398_245).replace_second(60).is_err()); // 60 isn't a valid second
1205 /// ```
1206 #[inline]
1207 #[must_use = "This method does not mutate the original `Timestamp`."]
1208 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
1209 ensure_ranged!(ru8<0, 59>: second);
1210 let seconds = div_floor!(self.seconds.get(), Second::per_t::<i64>(Minute))
1211 * Second::per_t::<i64>(Minute)
1212 + second as i64;
1213 // Safety: Any value is valid so long as `second` is in range.
1214 self.seconds = unsafe { Seconds::new_unchecked(seconds) };
1215 Ok(self)
1216 }
1217
1218 /// Replace the milliseconds within the second.
1219 ///
1220 /// ```rust
1221 /// # use time_macros::timestamp;
1222 /// assert_eq!(
1223 /// timestamp!(1_546_398_245.006).replace_millisecond(7),
1224 /// Ok(timestamp!(1_546_398_245.007))
1225 /// );
1226 /// assert!(
1227 /// timestamp!(1_546_398_245.006)
1228 /// .replace_millisecond(1_000)
1229 /// .is_err()
1230 /// ); // 1_000 isn't a valid millisecond
1231 /// ```
1232 #[inline]
1233 #[must_use = "This method does not mutate the original `Timestamp`."]
1234 pub const fn replace_millisecond(
1235 self,
1236 millisecond: u16,
1237 ) -> Result<Self, error::ComponentRange> {
1238 let nanos =
1239 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
1240 Ok(self.replace_nanosecond_ranged(nanos))
1241 }
1242
1243 /// Replace the microseconds within the second.
1244 ///
1245 /// ```rust
1246 /// # use time_macros::timestamp;
1247 /// assert_eq!(
1248 /// timestamp!(1_546_398_245.006_007).replace_microsecond(123_456),
1249 /// Ok(timestamp!(1_546_398_245.123_456))
1250 /// );
1251 /// assert!(
1252 /// timestamp!(1_546_398_245.006_007)
1253 /// .replace_microsecond(1_000_000)
1254 /// .is_err()
1255 /// ); // 1_000_000 isn't a valid microsecond
1256 /// ```
1257 #[inline]
1258 #[must_use = "This method does not mutate the original `Timestamp`."]
1259 pub const fn replace_microsecond(
1260 self,
1261 microsecond: u32,
1262 ) -> Result<Self, error::ComponentRange> {
1263 let nanos =
1264 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
1265 Ok(self.replace_nanosecond_ranged(nanos))
1266 }
1267
1268 /// Replace the nanoseconds within the second.
1269 ///
1270 /// ```rust
1271 /// # use time_macros::timestamp;
1272 /// assert_eq!(
1273 /// timestamp!(1_546_398_245.006_007_008).replace_nanosecond(123_456_789),
1274 /// Ok(timestamp!(1_546_398_245.123_456_789))
1275 /// );
1276 /// assert!(
1277 /// timestamp!(1_546_398_245.006_007_008)
1278 /// .replace_nanosecond(1_000_000_000)
1279 /// .is_err()
1280 /// ); // 1_000_000_000 isn't a valid nanosecond
1281 /// ```
1282 #[inline]
1283 #[must_use = "This method does not mutate the original `Timestamp`."]
1284 pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1285 let nanos = ensure_ranged!(Nanoseconds: nanosecond);
1286 Ok(self.replace_nanosecond_ranged(nanos))
1287 }
1288
1289 /// Replace the nanoseconds within the second using a range-bounded integer to avoid range
1290 /// checks.
1291 #[inline]
1292 const fn replace_nanosecond_ranged(self, new_nanos: Nanoseconds) -> Self {
1293 let (seconds, nanoseconds) = self.as_parts_ranged();
1294
1295 if seconds.get() >= 0 || nanoseconds.get() == 0 {
1296 Self::new_ranged(seconds, new_nanos)
1297 } else if new_nanos.get() == 0 {
1298 // Safety: The previous conditional guarantees that `seconds` is negative (if it were
1299 // non-negative, we wouldn't be in this branch). Given that the maximum value is
1300 // positive, we can always add one without exceeding the maximum.
1301 Self::new_ranged(unsafe { seconds.unchecked_add(1) }, new_nanos)
1302 } else {
1303 // Safety: Given the range of `new_nanos`, subtracting it from the maximum always
1304 // results in a value in range. Zero is excluded by a previous conditional.
1305 Self::new_ranged(seconds, unsafe {
1306 Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - new_nanos.get())
1307 })
1308 }
1309 }
1310}
1311
1312#[cfg(feature = "formatting")]
1313impl Timestamp {
1314 /// Format the `Timestamp` using the provided [format description](crate::format_description).
1315 #[inline]
1316 pub fn format_into(
1317 self,
1318 output: &mut (impl io::Write + ?Sized),
1319 format: &(impl Formattable + ?Sized),
1320 ) -> Result<usize, error::Format> {
1321 let mut output = crate::formatting::Output {
1322 bytes_written: 0,
1323 output,
1324 };
1325 try_likely_ok!(format.format_into(
1326 &mut output,
1327 &self,
1328 &mut Default::default(),
1329 PrivateMethod,
1330 ));
1331 Ok(output.bytes_written)
1332 }
1333
1334 /// Format the `Timestamp` using the provided [format description](crate::format_description).
1335 ///
1336 /// ```rust
1337 /// # use time_macros::{format_description, timestamp};
1338 /// let format = format_description!("[unix_timestamp]");
1339 /// assert_eq!(timestamp!(1_546_398_245).format(&format)?, "1546398245");
1340 /// # Ok::<_, time::Error>(())
1341 /// ```
1342 #[inline]
1343 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1344 format.format(&self, &mut Default::default(), PrivateMethod)
1345 }
1346}
1347
1348#[cfg(feature = "parsing")]
1349impl Timestamp {
1350 /// Parse a `Timestamp` from the input using the provided [format
1351 /// description](crate::format_description).
1352 ///
1353 /// ```rust
1354 /// # use time::Timestamp;
1355 /// # use time_macros::{format_description, timestamp};
1356 /// let format = format_description!("[unix_timestamp]");
1357 /// assert_eq!(
1358 /// Timestamp::parse("1546398245", &format)?,
1359 /// timestamp!(1_546_398_245),
1360 /// );
1361 /// # Ok::<_, time::Error>(())
1362 /// ```
1363 #[inline]
1364 pub fn parse(
1365 input: &str,
1366 description: &(impl Parsable + ?Sized),
1367 ) -> Result<Self, error::Parse> {
1368 description.parse_timestamp(input.as_bytes(), None, PrivateMethod)
1369 }
1370
1371 /// Parse a `Timestamp` from the input using the provided [format
1372 /// description](crate::format_description) and default values.
1373 ///
1374 /// ```rust
1375 /// # use time::Timestamp;
1376 /// # use time::parsing::Parsed;
1377 /// # use time_macros::{format_description, timestamp};
1378 /// let format = format_description!("[year]-[month]-[day]");
1379 /// let defaults = Parsed::new().with_hour_24(0).expect("0 is a valid hour");
1380 /// assert_eq!(
1381 /// Timestamp::parse_with_defaults(b"2020-01-02", &format, defaults)?,
1382 /// timestamp!(1_577_923_200)
1383 /// );
1384 /// # Ok::<_, time::Error>(())
1385 /// ```
1386 #[inline]
1387 pub fn parse_with_defaults(
1388 input: &[u8],
1389 description: &(impl Parsable + ?Sized),
1390 defaults: Parsed,
1391 ) -> Result<Self, error::Parse> {
1392 description.parse_timestamp(input, Some(defaults), PrivateMethod)
1393 }
1394}
1395
1396impl Timestamp {
1397 /// The maximum number of bytes that the `fmt_into_buffer` method will write, which is also used
1398 /// by the `Display` implementation.
1399 const DISPLAY_BUFFER_SIZE: usize = 25;
1400
1401 /// Format the `Timestamp` into the provided buffer, returning the number of bytes written.
1402 pub(crate) fn fmt_into_buffer(
1403 self,
1404 buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
1405 ) -> usize {
1406 let mut idx = 0;
1407
1408 let mut second = self.seconds.get();
1409 let mut nanosecond = self.nanoseconds;
1410
1411 if second < 0 {
1412 buf[idx] = MaybeUninit::new(b'-');
1413 idx += 1;
1414
1415 second = -second;
1416
1417 if nanosecond != Nanoseconds::new_static::<0>() {
1418 second -= 1;
1419 // Safety: `nanosecond` is in the range 1..=999_999_999, so subtracting it from
1420 // 1_000_000_000 will always yield a value in the range 1..=999_999_999, which is a
1421 // subset of the valid range for `Nanoseconds`.
1422 nanosecond = unsafe {
1423 Nanoseconds::new_unchecked(Nanosecond::per_t::<u32>(Second) - nanosecond.get())
1424 };
1425 }
1426 }
1427
1428 let seconds_str = u64_pad_none(second.cast_unsigned());
1429 let seconds_len = seconds_str.len();
1430 // Safety: `buf` has sufficient capacity for the seconds digits.
1431 unsafe {
1432 seconds_str
1433 .as_ptr()
1434 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), seconds_len);
1435 }
1436 idx += seconds_len;
1437
1438 if nanosecond != Nanoseconds::new_static::<0>() {
1439 buf[idx] = MaybeUninit::new(b'.');
1440 idx += 1;
1441
1442 let subsecond = truncated_subsecond_from_nanos(nanosecond);
1443 // Safety: `buf` has sufficient capacity for the subsecond digits.
1444 unsafe {
1445 subsecond
1446 .as_ptr()
1447 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len());
1448 }
1449 idx += subsecond.len();
1450 }
1451
1452 idx
1453 }
1454}
1455
1456impl fmt::Display for Timestamp {
1457 #[inline]
1458 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1459 let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1460 let len = self.fmt_into_buffer(&mut buf);
1461 // Safety: All bytes up to `len` have been initialized with ASCII characters.
1462 let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1463 f.pad(s)
1464 }
1465}
1466
1467impl fmt::Debug for Timestamp {
1468 #[inline]
1469 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1470 fmt::Display::fmt(self, f)
1471 }
1472}
1473
1474impl Add<SignedDuration> for Timestamp {
1475 type Output = Self;
1476
1477 /// # Panics
1478 ///
1479 /// This may panic if an overflow occurs.
1480 #[inline]
1481 #[track_caller]
1482 fn add(self, rhs: SignedDuration) -> Self::Output {
1483 self.checked_add(rhs)
1484 .expect("resulting value is out of range")
1485 }
1486}
1487
1488impl Add<StdDuration> for Timestamp {
1489 type Output = Self;
1490
1491 /// # Panics
1492 ///
1493 /// This may panic if an overflow occurs.
1494 #[inline]
1495 #[track_caller]
1496 fn add(self, rhs: StdDuration) -> Self::Output {
1497 self.add_std(rhs).expect("resulting value is out of range")
1498 }
1499}
1500
1501impl AddAssign<SignedDuration> for Timestamp {
1502 /// # Panics
1503 ///
1504 /// This may panic if an overflow occurs.
1505 #[inline]
1506 #[track_caller]
1507 fn add_assign(&mut self, rhs: SignedDuration) {
1508 *self = *self + rhs;
1509 }
1510}
1511
1512impl AddAssign<StdDuration> for Timestamp {
1513 /// # Panics
1514 ///
1515 /// This may panic if an overflow occurs.
1516 #[inline]
1517 #[track_caller]
1518 fn add_assign(&mut self, rhs: StdDuration) {
1519 *self = *self + rhs;
1520 }
1521}
1522
1523impl Sub<SignedDuration> for Timestamp {
1524 type Output = Self;
1525
1526 /// # Panics
1527 ///
1528 /// This may panic if an overflow occurs.
1529 #[inline]
1530 #[track_caller]
1531 fn sub(self, rhs: SignedDuration) -> Self::Output {
1532 self.checked_sub(rhs)
1533 .expect("resulting value is out of range")
1534 }
1535}
1536
1537impl Sub<StdDuration> for Timestamp {
1538 type Output = Self;
1539
1540 /// # Panics
1541 ///
1542 /// This may panic if an overflow occurs.
1543 #[inline]
1544 #[track_caller]
1545 fn sub(self, rhs: StdDuration) -> Self::Output {
1546 self.sub_std(rhs).expect("resulting value is out of range")
1547 }
1548}
1549
1550impl SubAssign<SignedDuration> for Timestamp {
1551 /// # Panics
1552 ///
1553 /// This may panic if an overflow occurs.
1554 #[inline]
1555 #[track_caller]
1556 fn sub_assign(&mut self, rhs: SignedDuration) {
1557 *self = *self - rhs;
1558 }
1559}
1560
1561impl SubAssign<StdDuration> for Timestamp {
1562 /// # Panics
1563 ///
1564 /// This may panic if an overflow occurs.
1565 #[inline]
1566 #[track_caller]
1567 fn sub_assign(&mut self, rhs: StdDuration) {
1568 *self = *self - rhs;
1569 }
1570}
1571
1572impl Sub for Timestamp {
1573 type Output = SignedDuration;
1574
1575 #[inline]
1576 fn sub(self, rhs: Self) -> Self::Output {
1577 let seconds = self.seconds.get() - rhs.seconds.get();
1578 let nanoseconds = self.nanoseconds.get() as i32 - rhs.nanoseconds.get() as i32;
1579
1580 if nanoseconds < 0 {
1581 SignedDuration::new(seconds - 1, nanoseconds + Nanosecond::per_t::<i32>(Second))
1582 } else {
1583 SignedDuration::new(seconds, nanoseconds)
1584 }
1585 }
1586}