Thanks to visit codestin.com
Credit goes to docs.rs

jiff/
timestamp.rs

1use core::time::Duration as UnsignedDuration;
2
3use crate::{
4    duration::{Duration, SDuration},
5    error::{timestamp::Error as E, Error, ErrorContext},
6    fmt::{
7        self,
8        temporal::{self, DEFAULT_DATETIME_PARSER},
9    },
10    shared::util::itime::ITimestamp,
11    tz::{Offset, TimeZone},
12    util::{
13        rangeint::{self, Composite, RFrom, RInto},
14        round::increment,
15        t::{
16            self, FractionalNanosecond, NoUnits, NoUnits128, UnixMicroseconds,
17            UnixMilliseconds, UnixNanoseconds, UnixSeconds, C,
18        },
19    },
20    zoned::Zoned,
21    RoundMode, SignedDuration, Span, SpanRound, Unit,
22};
23
24/// An instant in time represented as the number of nanoseconds since the Unix
25/// epoch.
26///
27/// A timestamp is always in the Unix timescale with a UTC offset of zero.
28///
29/// To obtain civil or "local" datetime units like year, month, day or hour, a
30/// timestamp needs to be combined with a [`TimeZone`] to create a [`Zoned`].
31/// That can be done with [`Timestamp::in_tz`] or [`Timestamp::to_zoned`].
32///
33/// The integer count of nanoseconds since the Unix epoch is signed, where
34/// the Unix epoch is `1970-01-01 00:00:00Z`. A positive timestamp indicates
35/// a point in time after the Unix epoch. A negative timestamp indicates a
36/// point in time before the Unix epoch.
37///
38/// # Parsing and printing
39///
40/// The `Timestamp` type provides convenient trait implementations of
41/// [`std::str::FromStr`] and [`std::fmt::Display`]:
42///
43/// ```
44/// use jiff::Timestamp;
45///
46/// let ts: Timestamp = "2024-06-19 15:22:45-04".parse()?;
47/// assert_eq!(ts.to_string(), "2024-06-19T19:22:45Z");
48///
49/// # Ok::<(), Box<dyn std::error::Error>>(())
50/// ```
51///
52/// A `Timestamp` can also be parsed from something that _contains_ a
53/// timestamp, but with perhaps other data (such as a time zone):
54///
55/// ```
56/// use jiff::Timestamp;
57///
58/// let ts: Timestamp = "2024-06-19T15:22:45-04[America/New_York]".parse()?;
59/// assert_eq!(ts.to_string(), "2024-06-19T19:22:45Z");
60///
61/// # Ok::<(), Box<dyn std::error::Error>>(())
62/// ```
63///
64/// For more information on the specific format supported, see the
65/// [`fmt::temporal`](crate::fmt::temporal) module documentation.
66///
67/// # Default value
68///
69/// For convenience, this type implements the `Default` trait. Its default
70/// value corresponds to `1970-01-01T00:00:00.000000000`. That is, it is the
71/// Unix epoch. One can also access this value via the `Timestamp::UNIX_EPOCH`
72/// constant.
73///
74/// # Leap seconds
75///
76/// Jiff does not support leap seconds. Jiff behaves as if they don't exist.
77/// The only exception is that if one parses a timestamp with a second
78/// component of `60`, then it is automatically constrained to `59`:
79///
80/// ```
81/// use jiff::Timestamp;
82///
83/// let ts: Timestamp = "2016-12-31 23:59:60Z".parse()?;
84/// assert_eq!(ts.to_string(), "2016-12-31T23:59:59Z");
85///
86/// # Ok::<(), Box<dyn std::error::Error>>(())
87/// ```
88///
89/// # Comparisons
90///
91/// The `Timestamp` type provides both `Eq` and `Ord` trait implementations
92/// to facilitate easy comparisons. When a timestamp `ts1` occurs before a
93/// timestamp `ts2`, then `dt1 < dt2`. For example:
94///
95/// ```
96/// use jiff::Timestamp;
97///
98/// let ts1 = Timestamp::from_second(123_456_789)?;
99/// let ts2 = Timestamp::from_second(123_456_790)?;
100/// assert!(ts1 < ts2);
101///
102/// # Ok::<(), Box<dyn std::error::Error>>(())
103/// ```
104///
105/// # Arithmetic
106///
107/// This type provides routines for adding and subtracting spans of time, as
108/// well as computing the span of time between two `Timestamp` values.
109///
110/// For adding or subtracting spans of time, one can use any of the following
111/// routines:
112///
113/// * [`Timestamp::checked_add`] or [`Timestamp::checked_sub`] for checked
114/// arithmetic.
115/// * [`Timestamp::saturating_add`] or [`Timestamp::saturating_sub`] for
116/// saturating arithmetic.
117///
118/// Additionally, checked arithmetic is available via the `Add` and `Sub`
119/// trait implementations. When the result overflows, a panic occurs.
120///
121/// ```
122/// use jiff::{Timestamp, ToSpan};
123///
124/// let ts1: Timestamp = "2024-02-25T15:45Z".parse()?;
125/// let ts2 = ts1 - 24.hours();
126/// assert_eq!(ts2.to_string(), "2024-02-24T15:45:00Z");
127///
128/// # Ok::<(), Box<dyn std::error::Error>>(())
129/// ```
130///
131/// One can compute the span of time between two timestamps using either
132/// [`Timestamp::until`] or [`Timestamp::since`]. It's also possible to
133/// subtract two `Timestamp` values directly via a `Sub` trait implementation:
134///
135/// ```
136/// use jiff::{Timestamp, ToSpan};
137///
138/// let ts1: Timestamp = "2024-05-03 23:30:00.123Z".parse()?;
139/// let ts2: Timestamp = "2024-02-25 07Z".parse()?;
140/// // The default is to return spans with units no bigger than seconds.
141/// assert_eq!(ts1 - ts2, 5934600.seconds().milliseconds(123).fieldwise());
142///
143/// # Ok::<(), Box<dyn std::error::Error>>(())
144/// ```
145///
146/// The `until` and `since` APIs are polymorphic and allow re-balancing and
147/// rounding the span returned. For example, the default largest unit is
148/// seconds (as exemplified above), but we can ask for bigger units (up to
149/// hours):
150///
151/// ```
152/// use jiff::{Timestamp, ToSpan, Unit};
153///
154/// let ts1: Timestamp = "2024-05-03 23:30:00.123Z".parse()?;
155/// let ts2: Timestamp = "2024-02-25 07Z".parse()?;
156/// assert_eq!(
157///     // If you want to deal in units bigger than hours, then you'll have to
158///     // convert your timestamp to a [`Zoned`] first.
159///     ts1.since((Unit::Hour, ts2))?,
160///     1648.hours().minutes(30).milliseconds(123).fieldwise(),
161/// );
162///
163/// # Ok::<(), Box<dyn std::error::Error>>(())
164/// ```
165///
166/// You can also round the span returned:
167///
168/// ```
169/// use jiff::{RoundMode, Timestamp, TimestampDifference, ToSpan, Unit};
170///
171/// let ts1: Timestamp = "2024-05-03 23:30:59.123Z".parse()?;
172/// let ts2: Timestamp = "2024-05-02 07Z".parse()?;
173/// assert_eq!(
174///     ts1.since(
175///         TimestampDifference::new(ts2)
176///             .smallest(Unit::Minute)
177///             .largest(Unit::Hour),
178///     )?,
179///     40.hours().minutes(30).fieldwise(),
180/// );
181/// // `TimestampDifference` uses truncation as a rounding mode by default,
182/// // but you can set the rounding mode to break ties away from zero:
183/// assert_eq!(
184///     ts1.since(
185///         TimestampDifference::new(ts2)
186///             .smallest(Unit::Minute)
187///             .largest(Unit::Hour)
188///             .mode(RoundMode::HalfExpand),
189///     )?,
190///     // Rounds up to 31 minutes.
191///     40.hours().minutes(31).fieldwise(),
192/// );
193///
194/// # Ok::<(), Box<dyn std::error::Error>>(())
195/// ```
196///
197/// # Rounding timestamps
198///
199/// A `Timestamp` can be rounded based on a [`TimestampRound`] configuration of
200/// smallest units, rounding increment and rounding mode. Here's an example
201/// showing how to round to the nearest third hour:
202///
203/// ```
204/// use jiff::{Timestamp, TimestampRound, Unit};
205///
206/// let ts: Timestamp = "2024-06-19 16:27:29.999999999Z".parse()?;
207/// assert_eq!(
208///     ts.round(TimestampRound::new().smallest(Unit::Hour).increment(3))?,
209///     "2024-06-19 15Z".parse::<Timestamp>()?,
210/// );
211/// // Or alternatively, make use of the `From<(Unit, i64)> for TimestampRound`
212/// // trait implementation:
213/// assert_eq!(
214///     ts.round((Unit::Hour, 3))?.to_string(),
215///     "2024-06-19T15:00:00Z",
216/// );
217///
218/// # Ok::<(), Box<dyn std::error::Error>>(())
219/// ```
220///
221/// See [`Timestamp::round`] for more details.
222///
223/// # An instant in time
224///
225/// Unlike a [`civil::DateTime`](crate::civil::DateTime), a `Timestamp`
226/// _always_ corresponds, unambiguously, to a precise instant in time (to
227/// nanosecond precision). This means that attaching a time zone to a timestamp
228/// is always unambiguous because there's never any question as to which
229/// instant it refers to. This is true even for gaps in civil time.
230///
231/// For example, in `America/New_York`, clocks were moved ahead one hour
232/// at clock time `2024-03-10 02:00:00`. That is, the 2 o'clock hour never
233/// appeared on clocks in the `America/New_York` region. Since parsing a
234/// timestamp always requires an offset, the time it refers to is unambiguous.
235/// We can see this by writing a clock time, `02:30`, that never existed but
236/// with two different offsets:
237///
238/// ```
239/// use jiff::Timestamp;
240///
241/// // All we're doing here is attaching an offset to a civil datetime.
242/// // There is no time zone information here, and thus there is no
243/// // accounting for ambiguity due to daylight saving time transitions.
244/// let before_hour_jump: Timestamp = "2024-03-10 02:30-04".parse()?;
245/// let after_hour_jump: Timestamp = "2024-03-10 02:30-05".parse()?;
246/// // This shows the instant in time in UTC.
247/// assert_eq!(before_hour_jump.to_string(), "2024-03-10T06:30:00Z");
248/// assert_eq!(after_hour_jump.to_string(), "2024-03-10T07:30:00Z");
249///
250/// // Now let's attach each instant to an `America/New_York` time zone.
251/// let zdt_before = before_hour_jump.in_tz("America/New_York")?;
252/// let zdt_after = after_hour_jump.in_tz("America/New_York")?;
253/// // And now we can see that even though the original instant refers to
254/// // the 2 o'clock hour, since that hour never existed on the clocks in
255/// // `America/New_York`, an instant with a time zone correctly adjusts.
256/// assert_eq!(
257///     zdt_before.to_string(),
258///     "2024-03-10T01:30:00-05:00[America/New_York]",
259/// );
260/// assert_eq!(
261///     zdt_after.to_string(),
262///     "2024-03-10T03:30:00-04:00[America/New_York]",
263/// );
264///
265/// # Ok::<(), Box<dyn std::error::Error>>(())
266/// ```
267///
268/// In the example above, there is never a step that is incorrect or has an
269/// alternative answer. Every step is unambiguous because we never involve
270/// any [`civil`](crate::civil) datetimes.
271///
272/// But note that if the datetime string you're parsing from lacks an offset,
273/// then it *could* be ambiguous even if a time zone is specified. In this
274/// case, parsing will always fail:
275///
276/// ```
277/// use jiff::Timestamp;
278///
279/// let result = "2024-06-30 08:30[America/New_York]".parse::<Timestamp>();
280/// assert_eq!(
281///     result.unwrap_err().to_string(),
282///     "failed to find offset component, \
283///      which is required for parsing a timestamp",
284/// );
285/// ```
286///
287/// # Converting a civil datetime to a timestamp
288///
289/// Sometimes you want to convert the "time on the clock" to a precise instant
290/// in time. One way to do this was demonstrated in the previous section, but
291/// it only works if you know your current time zone offset:
292///
293/// ```
294/// use jiff::Timestamp;
295///
296/// let ts: Timestamp = "2024-06-30 08:36-04".parse()?;
297/// assert_eq!(ts.to_string(), "2024-06-30T12:36:00Z");
298///
299/// # Ok::<(), Box<dyn std::error::Error>>(())
300/// ```
301///
302/// The above happened to be the precise instant in time I wrote the example.
303/// Since I happened to know the offset, this worked okay. But what if I
304/// didn't? We could instead construct a civil datetime and attach a time zone
305/// to it. This will create a [`Zoned`] value, from which we can access the
306/// timestamp:
307///
308/// ```
309/// use jiff::civil::date;
310///
311/// let clock = date(2024, 6, 30).at(8, 36, 0, 0).in_tz("America/New_York")?;
312/// assert_eq!(clock.timestamp().to_string(), "2024-06-30T12:36:00Z");
313///
314/// # Ok::<(), Box<dyn std::error::Error>>(())
315/// ```
316#[derive(Clone, Copy)]
317pub struct Timestamp {
318    second: UnixSeconds,
319    nanosecond: FractionalNanosecond,
320}
321
322impl Timestamp {
323    /// The minimum representable timestamp.
324    ///
325    /// The minimum is chosen such that it can be combined with
326    /// any legal [`Offset`](crate::tz::Offset) and turned into a
327    /// [`civil::DateTime`](crate::civil::DateTime).
328    ///
329    /// # Example
330    ///
331    /// ```
332    /// use jiff::{civil::date, tz::Offset, Timestamp};
333    ///
334    /// let dt = Offset::MIN.to_datetime(Timestamp::MIN);
335    /// assert_eq!(dt, date(-9999, 1, 1).at(0, 0, 0, 0));
336    /// ```
337    pub const MIN: Timestamp = Timestamp {
338        second: UnixSeconds::MIN_SELF,
339        nanosecond: FractionalNanosecond::N::<0>(),
340    };
341
342    /// The maximum representable timestamp.
343    ///
344    /// The maximum is chosen such that it can be combined with
345    /// any legal [`Offset`](crate::tz::Offset) and turned into a
346    /// [`civil::DateTime`](crate::civil::DateTime).
347    ///
348    /// # Example
349    ///
350    /// ```
351    /// use jiff::{civil::date, tz::Offset, Timestamp};
352    ///
353    /// let dt = Offset::MAX.to_datetime(Timestamp::MAX);
354    /// assert_eq!(dt, date(9999, 12, 31).at(23, 59, 59, 999_999_999));
355    /// ```
356    pub const MAX: Timestamp = Timestamp {
357        second: UnixSeconds::MAX_SELF,
358        nanosecond: FractionalNanosecond::MAX_SELF,
359    };
360
361    /// The Unix epoch represented as a timestamp.
362    ///
363    /// The Unix epoch corresponds to the instant at `1970-01-01T00:00:00Z`.
364    /// As a timestamp, it corresponds to `0` nanoseconds.
365    ///
366    /// A timestamp is positive if and only if it is greater than the Unix
367    /// epoch. A timestamp is negative if and only if it is less than the Unix
368    /// epoch.
369    pub const UNIX_EPOCH: Timestamp = Timestamp {
370        second: UnixSeconds::N::<0>(),
371        nanosecond: FractionalNanosecond::N::<0>(),
372    };
373
374    /// Returns the current system time as a timestamp.
375    ///
376    /// # Panics
377    ///
378    /// This panics if the system clock is set to a time value outside of the
379    /// range `-009999-01-01T00:00:00Z..=9999-12-31T11:59:59.999999999Z`. The
380    /// justification here is that it is reasonable to expect the system clock
381    /// to be set to a somewhat sane, if imprecise, value.
382    ///
383    /// If you want to get the current Unix time fallibly, use
384    /// [`Timestamp::try_from`] with a `std::time::SystemTime` as input.
385    ///
386    /// This may also panic when `SystemTime::now()` itself panics. The most
387    /// common context in which this happens is on the `wasm32-unknown-unknown`
388    /// target. If you're using that target in the context of the web (for
389    /// example, via `wasm-pack`), and you're an application, then you should
390    /// enable Jiff's `js` feature. This will automatically instruct Jiff in
391    /// this very specific circumstance to execute JavaScript code to determine
392    /// the current time from the web browser.
393    ///
394    /// # Example
395    ///
396    /// ```
397    /// use jiff::Timestamp;
398    ///
399    /// assert!(Timestamp::now() > Timestamp::UNIX_EPOCH);
400    /// ```
401    #[cfg(feature = "std")]
402    pub fn now() -> Timestamp {
403        Timestamp::try_from(crate::now::system_time())
404            .expect("system time is valid")
405    }
406
407    /// Creates a new instant in time represented as a timestamp.
408    ///
409    /// While a timestamp is logically a count of nanoseconds since the Unix
410    /// epoch, this constructor provides a convenience way of constructing
411    /// the timestamp from two components: seconds and fractional seconds
412    /// expressed as nanoseconds.
413    ///
414    /// The signs of `second` and `nanosecond` need not be the same.
415    ///
416    /// # Errors
417    ///
418    /// This returns an error if the given components would correspond to
419    /// an instant outside the supported range. Also, `nanosecond` is limited
420    /// to the range `-999,999,999..=999,999,999`.
421    ///
422    /// # Example
423    ///
424    /// This example shows the instant in time 123,456,789 seconds after the
425    /// Unix epoch:
426    ///
427    /// ```
428    /// use jiff::Timestamp;
429    ///
430    /// assert_eq!(
431    ///     Timestamp::new(123_456_789, 0)?.to_string(),
432    ///     "1973-11-29T21:33:09Z",
433    /// );
434    ///
435    /// # Ok::<(), Box<dyn std::error::Error>>(())
436    /// ```
437    ///
438    /// # Example: normalized sign
439    ///
440    /// This example shows how `second` and `nanosecond` are resolved when
441    /// their signs differ.
442    ///
443    /// ```
444    /// use jiff::Timestamp;
445    ///
446    /// let ts = Timestamp::new(2, -999_999_999)?;
447    /// assert_eq!(ts.as_second(), 1);
448    /// assert_eq!(ts.subsec_nanosecond(), 1);
449    ///
450    /// let ts = Timestamp::new(-2, 999_999_999)?;
451    /// assert_eq!(ts.as_second(), -1);
452    /// assert_eq!(ts.subsec_nanosecond(), -1);
453    ///
454    /// # Ok::<(), Box<dyn std::error::Error>>(())
455    /// ```
456    ///
457    /// # Example: limits
458    ///
459    /// The minimum timestamp has nanoseconds set to zero, while the maximum
460    /// timestamp has nanoseconds set to `999,999,999`:
461    ///
462    /// ```
463    /// use jiff::Timestamp;
464    ///
465    /// assert_eq!(Timestamp::MIN.subsec_nanosecond(), 0);
466    /// assert_eq!(Timestamp::MAX.subsec_nanosecond(), 999_999_999);
467    /// ```
468    ///
469    /// As a consequence, nanoseconds cannot be negative when a timestamp has
470    /// minimal seconds:
471    ///
472    /// ```
473    /// use jiff::Timestamp;
474    ///
475    /// assert!(Timestamp::new(Timestamp::MIN.as_second(), -1).is_err());
476    /// // But they can be positive!
477    /// let one_ns_more = Timestamp::new(Timestamp::MIN.as_second(), 1)?;
478    /// assert_eq!(
479    ///     one_ns_more.to_string(),
480    ///     "-009999-01-02T01:59:59.000000001Z",
481    /// );
482    /// // Or, when combined with a minimal offset:
483    /// assert_eq!(
484    ///     jiff::tz::Offset::MIN.to_datetime(one_ns_more).to_string(),
485    ///     "-009999-01-01T00:00:00.000000001",
486    /// );
487    ///
488    /// # Ok::<(), Box<dyn std::error::Error>>(())
489    /// ```
490    #[inline]
491    pub fn new(second: i64, nanosecond: i32) -> Result<Timestamp, Error> {
492        Timestamp::new_ranged(
493            UnixSeconds::try_new("second", second)?,
494            FractionalNanosecond::try_new("nanosecond", nanosecond)?,
495        )
496    }
497
498    /// Creates a new `Timestamp` value in a `const` context.
499    ///
500    /// # Panics
501    ///
502    /// This routine panics when [`Timestamp::new`] would return an error.
503    /// That is, when the given components would correspond to
504    /// an instant outside the supported range. Also, `nanosecond` is limited
505    /// to the range `-999,999,999..=999,999,999`.
506    ///
507    /// # Example
508    ///
509    /// This example shows the instant in time 123,456,789 seconds after the
510    /// Unix epoch:
511    ///
512    /// ```
513    /// use jiff::Timestamp;
514    ///
515    /// assert_eq!(
516    ///     Timestamp::constant(123_456_789, 0).to_string(),
517    ///     "1973-11-29T21:33:09Z",
518    /// );
519    /// ```
520    #[inline]
521    pub const fn constant(mut second: i64, mut nanosecond: i32) -> Timestamp {
522        if second == UnixSeconds::MIN_REPR && nanosecond < 0 {
523            panic!("nanoseconds must be >=0 when seconds are minimal");
524        }
525        // We now normalize our seconds and nanoseconds such that they have
526        // the same sign (or where one is zero). So for example, when given
527        // `-1s 1ns`, then we should turn that into `-999,999,999ns`.
528        //
529        // But first, if we're already normalized, we're done!
530        if second.signum() as i8 == nanosecond.signum() as i8
531            || second == 0
532            || nanosecond == 0
533        {
534            return Timestamp {
535                second: UnixSeconds::new_unchecked(second),
536                nanosecond: FractionalNanosecond::new_unchecked(nanosecond),
537            };
538        }
539        if second < 0 && nanosecond > 0 {
540            second += 1;
541            nanosecond -= t::NANOS_PER_SECOND.value() as i32;
542        } else if second > 0 && nanosecond < 0 {
543            second -= 1;
544            nanosecond += t::NANOS_PER_SECOND.value() as i32;
545        }
546        Timestamp {
547            second: UnixSeconds::new_unchecked(second),
548            nanosecond: FractionalNanosecond::new_unchecked(nanosecond),
549        }
550    }
551
552    /// Creates a new instant in time from the number of seconds elapsed since
553    /// the Unix epoch.
554    ///
555    /// When `second` is negative, it corresponds to an instant in time before
556    /// the Unix epoch. A smaller number corresponds to an instant in time
557    /// further into the past.
558    ///
559    /// # Errors
560    ///
561    /// This returns an error if the given second corresponds to a timestamp
562    /// outside of the [`Timestamp::MIN`] and [`Timestamp::MAX`] boundaries.
563    ///
564    /// It is a semver guarantee that the only way for this to return an error
565    /// is if the given value is out of range. That is, when it is less than
566    /// `Timestamp::MIN` or greater than `Timestamp::MAX`.
567    ///
568    /// # Example
569    ///
570    /// This example shows the instants in time 1 second immediately after and
571    /// before the Unix epoch:
572    ///
573    /// ```
574    /// use jiff::Timestamp;
575    ///
576    /// assert_eq!(
577    ///     Timestamp::from_second(1)?.to_string(),
578    ///     "1970-01-01T00:00:01Z",
579    /// );
580    /// assert_eq!(
581    ///     Timestamp::from_second(-1)?.to_string(),
582    ///     "1969-12-31T23:59:59Z",
583    /// );
584    ///
585    /// # Ok::<(), Box<dyn std::error::Error>>(())
586    /// ```
587    ///
588    /// # Example: saturating construction
589    ///
590    /// If you need a way to build a `Timestamp` value that saturates to
591    /// the minimum and maximum values supported by Jiff, then this is
592    /// guaranteed to work:
593    ///
594    /// ```
595    /// use jiff::Timestamp;
596    ///
597    /// fn from_second_saturating(seconds: i64) -> Timestamp {
598    ///     Timestamp::from_second(seconds).unwrap_or_else(|_| {
599    ///         if seconds < 0 {
600    ///             Timestamp::MIN
601    ///         } else {
602    ///             Timestamp::MAX
603    ///         }
604    ///     })
605    /// }
606    ///
607    /// assert_eq!(from_second_saturating(0), Timestamp::UNIX_EPOCH);
608    /// assert_eq!(
609    ///     from_second_saturating(-999999999999999999),
610    ///     Timestamp::MIN
611    /// );
612    /// assert_eq!(
613    ///     from_second_saturating(999999999999999999),
614    ///     Timestamp::MAX
615    /// );
616    /// ```
617    #[inline]
618    pub fn from_second(second: i64) -> Result<Timestamp, Error> {
619        Timestamp::new(second, 0)
620    }
621
622    /// Creates a new instant in time from the number of milliseconds elapsed
623    /// since the Unix epoch.
624    ///
625    /// When `millisecond` is negative, it corresponds to an instant in time
626    /// before the Unix epoch. A smaller number corresponds to an instant in
627    /// time further into the past.
628    ///
629    /// # Errors
630    ///
631    /// This returns an error if the given millisecond corresponds to a
632    /// timestamp outside of the [`Timestamp::MIN`] and [`Timestamp::MAX`]
633    /// boundaries.
634    ///
635    /// It is a semver guarantee that the only way for this to return an error
636    /// is if the given value is out of range. That is, when it is less than
637    /// `Timestamp::MIN` or greater than `Timestamp::MAX`.
638    ///
639    /// # Example
640    ///
641    /// This example shows the instants in time 1 millisecond immediately after
642    /// and before the Unix epoch:
643    ///
644    /// ```
645    /// use jiff::Timestamp;
646    ///
647    /// assert_eq!(
648    ///     Timestamp::from_millisecond(1)?.to_string(),
649    ///     "1970-01-01T00:00:00.001Z",
650    /// );
651    /// assert_eq!(
652    ///     Timestamp::from_millisecond(-1)?.to_string(),
653    ///     "1969-12-31T23:59:59.999Z",
654    /// );
655    ///
656    /// # Ok::<(), Box<dyn std::error::Error>>(())
657    /// ```
658    ///
659    /// # Example: saturating construction
660    ///
661    /// If you need a way to build a `Timestamp` value that saturates to
662    /// the minimum and maximum values supported by Jiff, then this is
663    /// guaranteed to work:
664    ///
665    /// ```
666    /// use jiff::Timestamp;
667    ///
668    /// fn from_millisecond_saturating(millis: i64) -> Timestamp {
669    ///     Timestamp::from_millisecond(millis).unwrap_or_else(|_| {
670    ///         if millis < 0 {
671    ///             Timestamp::MIN
672    ///         } else {
673    ///             Timestamp::MAX
674    ///         }
675    ///     })
676    /// }
677    ///
678    /// assert_eq!(from_millisecond_saturating(0), Timestamp::UNIX_EPOCH);
679    /// assert_eq!(
680    ///     from_millisecond_saturating(-999999999999999999),
681    ///     Timestamp::MIN
682    /// );
683    /// assert_eq!(
684    ///     from_millisecond_saturating(999999999999999999),
685    ///     Timestamp::MAX
686    /// );
687    /// ```
688    #[inline]
689    pub fn from_millisecond(millisecond: i64) -> Result<Timestamp, Error> {
690        let millisecond = UnixMilliseconds::try_new128(
691            "millisecond timestamp",
692            millisecond,
693        )?;
694        Ok(Timestamp::from_millisecond_ranged(millisecond))
695    }
696
697    /// Creates a new instant in time from the number of microseconds elapsed
698    /// since the Unix epoch.
699    ///
700    /// When `microsecond` is negative, it corresponds to an instant in time
701    /// before the Unix epoch. A smaller number corresponds to an instant in
702    /// time further into the past.
703    ///
704    /// # Errors
705    ///
706    /// This returns an error if the given microsecond corresponds to a
707    /// timestamp outside of the [`Timestamp::MIN`] and [`Timestamp::MAX`]
708    /// boundaries.
709    ///
710    /// It is a semver guarantee that the only way for this to return an error
711    /// is if the given value is out of range. That is, when it is less than
712    /// `Timestamp::MIN` or greater than `Timestamp::MAX`.
713    ///
714    /// # Example
715    ///
716    /// This example shows the instants in time 1 microsecond immediately after
717    /// and before the Unix epoch:
718    ///
719    /// ```
720    /// use jiff::Timestamp;
721    ///
722    /// assert_eq!(
723    ///     Timestamp::from_microsecond(1)?.to_string(),
724    ///     "1970-01-01T00:00:00.000001Z",
725    /// );
726    /// assert_eq!(
727    ///     Timestamp::from_microsecond(-1)?.to_string(),
728    ///     "1969-12-31T23:59:59.999999Z",
729    /// );
730    ///
731    /// # Ok::<(), Box<dyn std::error::Error>>(())
732    /// ```
733    ///
734    /// # Example: saturating construction
735    ///
736    /// If you need a way to build a `Timestamp` value that saturates to
737    /// the minimum and maximum values supported by Jiff, then this is
738    /// guaranteed to work:
739    ///
740    /// ```
741    /// use jiff::Timestamp;
742    ///
743    /// fn from_microsecond_saturating(micros: i64) -> Timestamp {
744    ///     Timestamp::from_microsecond(micros).unwrap_or_else(|_| {
745    ///         if micros < 0 {
746    ///             Timestamp::MIN
747    ///         } else {
748    ///             Timestamp::MAX
749    ///         }
750    ///     })
751    /// }
752    ///
753    /// assert_eq!(from_microsecond_saturating(0), Timestamp::UNIX_EPOCH);
754    /// assert_eq!(
755    ///     from_microsecond_saturating(-999999999999999999),
756    ///     Timestamp::MIN
757    /// );
758    /// assert_eq!(
759    ///     from_microsecond_saturating(999999999999999999),
760    ///     Timestamp::MAX
761    /// );
762    /// ```
763    #[inline]
764    pub fn from_microsecond(microsecond: i64) -> Result<Timestamp, Error> {
765        let microsecond = UnixMicroseconds::try_new128(
766            "microsecond timestamp",
767            microsecond,
768        )?;
769        Ok(Timestamp::from_microsecond_ranged(microsecond))
770    }
771
772    /// Creates a new instant in time from the number of nanoseconds elapsed
773    /// since the Unix epoch.
774    ///
775    /// When `nanosecond` is negative, it corresponds to an instant in time
776    /// before the Unix epoch. A smaller number corresponds to an instant in
777    /// time further into the past.
778    ///
779    /// # Errors
780    ///
781    /// This returns an error if the given nanosecond corresponds to a
782    /// timestamp outside of the [`Timestamp::MIN`] and [`Timestamp::MAX`]
783    /// boundaries.
784    ///
785    /// It is a semver guarantee that the only way for this to return an error
786    /// is if the given value is out of range. That is, when it is less than
787    /// `Timestamp::MIN` or greater than `Timestamp::MAX`.
788    ///
789    /// # Example
790    ///
791    /// This example shows the instants in time 1 nanosecond immediately after
792    /// and before the Unix epoch:
793    ///
794    /// ```
795    /// use jiff::Timestamp;
796    ///
797    /// assert_eq!(
798    ///     Timestamp::from_nanosecond(1)?.to_string(),
799    ///     "1970-01-01T00:00:00.000000001Z",
800    /// );
801    /// assert_eq!(
802    ///     Timestamp::from_nanosecond(-1)?.to_string(),
803    ///     "1969-12-31T23:59:59.999999999Z",
804    /// );
805    ///
806    /// # Ok::<(), Box<dyn std::error::Error>>(())
807    /// ```
808    ///
809    /// # Example: saturating construction
810    ///
811    /// If you need a way to build a `Timestamp` value that saturates to
812    /// the minimum and maximum values supported by Jiff, then this is
813    /// guaranteed to work:
814    ///
815    /// ```
816    /// use jiff::Timestamp;
817    ///
818    /// fn from_nanosecond_saturating(nanos: i128) -> Timestamp {
819    ///     Timestamp::from_nanosecond(nanos).unwrap_or_else(|_| {
820    ///         if nanos < 0 {
821    ///             Timestamp::MIN
822    ///         } else {
823    ///             Timestamp::MAX
824    ///         }
825    ///     })
826    /// }
827    ///
828    /// assert_eq!(from_nanosecond_saturating(0), Timestamp::UNIX_EPOCH);
829    /// assert_eq!(
830    ///     from_nanosecond_saturating(-9999999999999999999999999999999999),
831    ///     Timestamp::MIN
832    /// );
833    /// assert_eq!(
834    ///     from_nanosecond_saturating(9999999999999999999999999999999999),
835    ///     Timestamp::MAX
836    /// );
837    /// ```
838    #[inline]
839    pub fn from_nanosecond(nanosecond: i128) -> Result<Timestamp, Error> {
840        let nanosecond =
841            UnixNanoseconds::try_new128("nanosecond timestamp", nanosecond)?;
842        Ok(Timestamp::from_nanosecond_ranged(nanosecond))
843    }
844
845    /// Creates a new timestamp from a `Duration` with the given sign since the
846    /// Unix epoch.
847    ///
848    /// Positive durations result in a timestamp after the Unix epoch. Negative
849    /// durations result in a timestamp before the Unix epoch.
850    ///
851    /// # Errors
852    ///
853    /// This returns an error if the given duration corresponds to a timestamp
854    /// outside of the [`Timestamp::MIN`] and [`Timestamp::MAX`] boundaries.
855    ///
856    /// It is a semver guarantee that the only way for this to return an error
857    /// is if the given value is out of range. That is, when it is less than
858    /// `Timestamp::MIN` or greater than `Timestamp::MAX`.
859    ///
860    /// # Example
861    ///
862    /// How one might construct a `Timestamp` from a `SystemTime`:
863    ///
864    /// ```
865    /// use std::time::SystemTime;
866    /// use jiff::{SignedDuration, Timestamp};
867    ///
868    /// let unix_epoch = SystemTime::UNIX_EPOCH;
869    /// let now = SystemTime::now();
870    /// let duration = SignedDuration::system_until(unix_epoch, now)?;
871    /// let ts = Timestamp::from_duration(duration)?;
872    /// assert!(ts > Timestamp::UNIX_EPOCH);
873    ///
874    /// # Ok::<(), Box<dyn std::error::Error>>(())
875    /// ```
876    ///
877    /// Of course, one should just use [`Timestamp::try_from`] for this
878    /// instead. Indeed, the above example is copied almost exactly from the
879    /// `TryFrom` implementation.
880    ///
881    /// # Example: out of bounds
882    ///
883    /// This example shows how some of the boundary conditions are dealt with.
884    ///
885    /// ```
886    /// use jiff::{SignedDuration, Timestamp};
887    ///
888    /// // OK, we get the minimum timestamp supported by Jiff:
889    /// let duration = SignedDuration::new(-377705023201, 0);
890    /// let ts = Timestamp::from_duration(duration)?;
891    /// assert_eq!(ts, Timestamp::MIN);
892    ///
893    /// // We use the minimum number of seconds, but even subtracting
894    /// // one more nanosecond after it will result in an error.
895    /// let duration = SignedDuration::new(-377705023201, -1);
896    /// assert_eq!(
897    ///     Timestamp::from_duration(duration).unwrap_err().to_string(),
898    ///     "parameter 'seconds and nanoseconds' with value -1 is not \
899    ///      in the required range of 0..=1000000000",
900    /// );
901    ///
902    /// # Ok::<(), Box<dyn std::error::Error>>(())
903    /// ```
904    ///
905    /// # Example: saturating construction
906    ///
907    /// If you need a way to build a `Timestamp` value that saturates to
908    /// the minimum and maximum values supported by Jiff, then this is
909    /// guaranteed to work:
910    ///
911    /// ```
912    /// use jiff::{SignedDuration, Timestamp};
913    ///
914    /// fn from_duration_saturating(dur: SignedDuration) -> Timestamp {
915    ///     Timestamp::from_duration(dur).unwrap_or_else(|_| {
916    ///         if dur.is_negative() {
917    ///             Timestamp::MIN
918    ///         } else {
919    ///             Timestamp::MAX
920    ///         }
921    ///     })
922    /// }
923    ///
924    /// assert_eq!(
925    ///     from_duration_saturating(SignedDuration::ZERO),
926    ///     Timestamp::UNIX_EPOCH,
927    /// );
928    /// assert_eq!(
929    ///     from_duration_saturating(SignedDuration::from_secs(-999999999999)),
930    ///     Timestamp::MIN
931    /// );
932    /// assert_eq!(
933    ///     from_duration_saturating(SignedDuration::from_secs(999999999999)),
934    ///     Timestamp::MAX
935    /// );
936    /// ```
937    #[inline]
938    pub fn from_duration(
939        duration: SignedDuration,
940    ) -> Result<Timestamp, Error> {
941        // As an optimization, we don't need to go through `Timestamp::new`
942        // (or `Timestamp::new_ranged`) here. That's because a `SignedDuration`
943        // already guarantees that its seconds and nanoseconds are "coherent."
944        // That is, we know we can't have a negative second with a positive
945        // nanosecond (or vice versa).
946        let second = UnixSeconds::try_new("second", duration.as_secs())?;
947        let nanosecond = FractionalNanosecond::try_new(
948            "nanosecond",
949            duration.subsec_nanos(),
950        )?;
951        // ... but we do have to check that the *combination* of seconds and
952        // nanoseconds aren't out of bounds, which is possible even when both
953        // are, on their own, legal values.
954        if second == UnixSeconds::MIN_SELF && nanosecond < C(0) {
955            return Err(Error::range(
956                "seconds and nanoseconds",
957                nanosecond,
958                0,
959                1_000_000_000,
960            ));
961        }
962        Ok(Timestamp { second, nanosecond })
963    }
964
965    /// Returns this timestamp as a number of seconds since the Unix epoch.
966    ///
967    /// This only returns the number of whole seconds. That is, if there are
968    /// any fractional seconds in this timestamp, then they are truncated.
969    ///
970    /// # Example
971    ///
972    /// ```
973    /// use jiff::Timestamp;
974    ///
975    /// let ts = Timestamp::new(5, 123_456_789)?;
976    /// assert_eq!(ts.as_second(), 5);
977    /// let ts = Timestamp::new(5, 999_999_999)?;
978    /// assert_eq!(ts.as_second(), 5);
979    ///
980    /// let ts = Timestamp::new(-5, -123_456_789)?;
981    /// assert_eq!(ts.as_second(), -5);
982    /// let ts = Timestamp::new(-5, -999_999_999)?;
983    /// assert_eq!(ts.as_second(), -5);
984    ///
985    /// # Ok::<(), Box<dyn std::error::Error>>(())
986    /// ```
987    #[inline]
988    pub fn as_second(self) -> i64 {
989        self.as_second_ranged().get()
990    }
991
992    /// Returns this timestamp as a number of milliseconds since the Unix
993    /// epoch.
994    ///
995    /// This only returns the number of whole milliseconds. That is, if there
996    /// are any fractional milliseconds in this timestamp, then they are
997    /// truncated.
998    ///
999    /// # Example
1000    ///
1001    /// ```
1002    /// use jiff::Timestamp;
1003    ///
1004    /// let ts = Timestamp::new(5, 123_456_789)?;
1005    /// assert_eq!(ts.as_millisecond(), 5_123);
1006    /// let ts = Timestamp::new(5, 999_999_999)?;
1007    /// assert_eq!(ts.as_millisecond(), 5_999);
1008    ///
1009    /// let ts = Timestamp::new(-5, -123_456_789)?;
1010    /// assert_eq!(ts.as_millisecond(), -5_123);
1011    /// let ts = Timestamp::new(-5, -999_999_999)?;
1012    /// assert_eq!(ts.as_millisecond(), -5_999);
1013    ///
1014    /// # Ok::<(), Box<dyn std::error::Error>>(())
1015    /// ```
1016    #[inline]
1017    pub fn as_millisecond(self) -> i64 {
1018        self.as_millisecond_ranged().get()
1019    }
1020
1021    /// Returns this timestamp as a number of microseconds since the Unix
1022    /// epoch.
1023    ///
1024    /// This only returns the number of whole microseconds. That is, if there
1025    /// are any fractional microseconds in this timestamp, then they are
1026    /// truncated.
1027    ///
1028    /// # Example
1029    ///
1030    /// ```
1031    /// use jiff::Timestamp;
1032    ///
1033    /// let ts = Timestamp::new(5, 123_456_789)?;
1034    /// assert_eq!(ts.as_microsecond(), 5_123_456);
1035    /// let ts = Timestamp::new(5, 999_999_999)?;
1036    /// assert_eq!(ts.as_microsecond(), 5_999_999);
1037    ///
1038    /// let ts = Timestamp::new(-5, -123_456_789)?;
1039    /// assert_eq!(ts.as_microsecond(), -5_123_456);
1040    /// let ts = Timestamp::new(-5, -999_999_999)?;
1041    /// assert_eq!(ts.as_microsecond(), -5_999_999);
1042    ///
1043    /// # Ok::<(), Box<dyn std::error::Error>>(())
1044    /// ```
1045    #[inline]
1046    pub fn as_microsecond(self) -> i64 {
1047        self.as_microsecond_ranged().get()
1048    }
1049
1050    /// Returns this timestamp as a number of nanoseconds since the Unix
1051    /// epoch.
1052    ///
1053    /// Since a `Timestamp` has a nanosecond precision, the nanoseconds
1054    /// returned here represent this timestamp losslessly. That is, the
1055    /// nanoseconds returned can be used with [`Timestamp::from_nanosecond`] to
1056    /// create an identical timestamp with no loss of precision.
1057    ///
1058    /// # Example
1059    ///
1060    /// ```
1061    /// use jiff::Timestamp;
1062    ///
1063    /// let ts = Timestamp::new(5, 123_456_789)?;
1064    /// assert_eq!(ts.as_nanosecond(), 5_123_456_789);
1065    /// let ts = Timestamp::new(5, 999_999_999)?;
1066    /// assert_eq!(ts.as_nanosecond(), 5_999_999_999);
1067    ///
1068    /// let ts = Timestamp::new(-5, -123_456_789)?;
1069    /// assert_eq!(ts.as_nanosecond(), -5_123_456_789);
1070    /// let ts = Timestamp::new(-5, -999_999_999)?;
1071    /// assert_eq!(ts.as_nanosecond(), -5_999_999_999);
1072    ///
1073    /// # Ok::<(), Box<dyn std::error::Error>>(())
1074    /// ```
1075    #[inline]
1076    pub fn as_nanosecond(self) -> i128 {
1077        self.as_nanosecond_ranged().get()
1078    }
1079
1080    /// Returns the fractional second component of this timestamp in units
1081    /// of milliseconds.
1082    ///
1083    /// It is guaranteed that this will never return a value that is greater
1084    /// than 1 second (or less than -1 second).
1085    ///
1086    /// This only returns the number of whole milliseconds. That is, if there
1087    /// are any fractional milliseconds in this timestamp, then they are
1088    /// truncated.
1089    ///
1090    /// # Example
1091    ///
1092    /// ```
1093    /// use jiff::Timestamp;
1094    ///
1095    /// let ts = Timestamp::new(5, 123_456_789)?;
1096    /// assert_eq!(ts.subsec_millisecond(), 123);
1097    /// let ts = Timestamp::new(5, 999_999_999)?;
1098    /// assert_eq!(ts.subsec_millisecond(), 999);
1099    ///
1100    /// let ts = Timestamp::new(-5, -123_456_789)?;
1101    /// assert_eq!(ts.subsec_millisecond(), -123);
1102    /// let ts = Timestamp::new(-5, -999_999_999)?;
1103    /// assert_eq!(ts.subsec_millisecond(), -999);
1104    ///
1105    /// # Ok::<(), Box<dyn std::error::Error>>(())
1106    /// ```
1107    #[inline]
1108    pub fn subsec_millisecond(self) -> i32 {
1109        self.subsec_millisecond_ranged().get()
1110    }
1111
1112    /// Returns the fractional second component of this timestamp in units of
1113    /// microseconds.
1114    ///
1115    /// It is guaranteed that this will never return a value that is greater
1116    /// than 1 second (or less than -1 second).
1117    ///
1118    /// This only returns the number of whole microseconds. That is, if there
1119    /// are any fractional microseconds in this timestamp, then they are
1120    /// truncated.
1121    ///
1122    /// # Example
1123    ///
1124    /// ```
1125    /// use jiff::Timestamp;
1126    ///
1127    /// let ts = Timestamp::new(5, 123_456_789)?;
1128    /// assert_eq!(ts.subsec_microsecond(), 123_456);
1129    /// let ts = Timestamp::new(5, 999_999_999)?;
1130    /// assert_eq!(ts.subsec_microsecond(), 999_999);
1131    ///
1132    /// let ts = Timestamp::new(-5, -123_456_789)?;
1133    /// assert_eq!(ts.subsec_microsecond(), -123_456);
1134    /// let ts = Timestamp::new(-5, -999_999_999)?;
1135    /// assert_eq!(ts.subsec_microsecond(), -999_999);
1136    ///
1137    /// # Ok::<(), Box<dyn std::error::Error>>(())
1138    /// ```
1139    #[inline]
1140    pub fn subsec_microsecond(self) -> i32 {
1141        self.subsec_microsecond_ranged().get()
1142    }
1143
1144    /// Returns the fractional second component of this timestamp in units of
1145    /// nanoseconds.
1146    ///
1147    /// It is guaranteed that this will never return a value that is greater
1148    /// than 1 second (or less than -1 second).
1149    ///
1150    /// # Example
1151    ///
1152    /// ```
1153    /// use jiff::Timestamp;
1154    ///
1155    /// let ts = Timestamp::new(5, 123_456_789)?;
1156    /// assert_eq!(ts.subsec_nanosecond(), 123_456_789);
1157    /// let ts = Timestamp::new(5, 999_999_999)?;
1158    /// assert_eq!(ts.subsec_nanosecond(), 999_999_999);
1159    ///
1160    /// let ts = Timestamp::new(-5, -123_456_789)?;
1161    /// assert_eq!(ts.subsec_nanosecond(), -123_456_789);
1162    /// let ts = Timestamp::new(-5, -999_999_999)?;
1163    /// assert_eq!(ts.subsec_nanosecond(), -999_999_999);
1164    ///
1165    /// # Ok::<(), Box<dyn std::error::Error>>(())
1166    /// ```
1167    #[inline]
1168    pub fn subsec_nanosecond(self) -> i32 {
1169        self.subsec_nanosecond_ranged().get()
1170    }
1171
1172    /// Returns this timestamp as a [`SignedDuration`] since the Unix epoch.
1173    ///
1174    /// # Example
1175    ///
1176    /// ```
1177    /// use jiff::{SignedDuration, Timestamp};
1178    ///
1179    /// assert_eq!(
1180    ///     Timestamp::UNIX_EPOCH.as_duration(),
1181    ///     SignedDuration::ZERO,
1182    /// );
1183    /// assert_eq!(
1184    ///     Timestamp::new(5, 123_456_789)?.as_duration(),
1185    ///     SignedDuration::new(5, 123_456_789),
1186    /// );
1187    /// assert_eq!(
1188    ///     Timestamp::new(-5, -123_456_789)?.as_duration(),
1189    ///     SignedDuration::new(-5, -123_456_789),
1190    /// );
1191    ///
1192    /// # Ok::<(), Box<dyn std::error::Error>>(())
1193    /// ```
1194    #[inline]
1195    pub fn as_duration(self) -> SignedDuration {
1196        SignedDuration::from_timestamp(self)
1197    }
1198
1199    /// Returns the sign of this timestamp.
1200    ///
1201    /// This can return one of three possible values:
1202    ///
1203    /// * `0` when this timestamp is precisely equivalent to
1204    /// [`Timestamp::UNIX_EPOCH`].
1205    /// * `1` when this timestamp occurs after the Unix epoch.
1206    /// * `-1` when this timestamp occurs before the Unix epoch.
1207    ///
1208    /// The sign returned is guaranteed to match the sign of all "getter"
1209    /// methods on `Timestamp`. For example, [`Timestamp::as_second`] and
1210    /// [`Timestamp::subsec_nanosecond`]. This is true even if the signs
1211    /// of the `second` and `nanosecond` components were mixed when given to
1212    /// the [`Timestamp::new`] constructor.
1213    ///
1214    /// # Example
1215    ///
1216    /// ```
1217    /// use jiff::Timestamp;
1218    ///
1219    /// let ts = Timestamp::new(5, -999_999_999)?;
1220    /// assert_eq!(ts.signum(), 1);
1221    /// // The mixed signs were normalized away!
1222    /// assert_eq!(ts.as_second(), 4);
1223    /// assert_eq!(ts.subsec_nanosecond(), 1);
1224    ///
1225    /// // The same applies for negative timestamps.
1226    /// let ts = Timestamp::new(-5, 999_999_999)?;
1227    /// assert_eq!(ts.signum(), -1);
1228    /// assert_eq!(ts.as_second(), -4);
1229    /// assert_eq!(ts.subsec_nanosecond(), -1);
1230    ///
1231    /// # Ok::<(), Box<dyn std::error::Error>>(())
1232    /// ```
1233    #[inline]
1234    pub fn signum(self) -> i8 {
1235        if self.is_zero() {
1236            0
1237        } else if self.as_second() > 0 || self.subsec_nanosecond() > 0 {
1238            1
1239        } else {
1240            -1
1241        }
1242    }
1243
1244    /// Returns true if and only if this timestamp corresponds to the instant
1245    /// in time known as the Unix epoch.
1246    ///
1247    /// # Example
1248    ///
1249    /// ```
1250    /// use jiff::Timestamp;
1251    ///
1252    /// assert!(Timestamp::UNIX_EPOCH.is_zero());
1253    /// ```
1254    #[inline]
1255    pub fn is_zero(self) -> bool {
1256        self.as_second() == 0 && self.subsec_nanosecond() == 0
1257    }
1258
1259    /// Creates a [`Zoned`] value by attaching a time zone for the given name
1260    /// to this instant in time.
1261    ///
1262    /// The name given is resolved to a [`TimeZone`] by using the default
1263    /// [`TimeZoneDatabase`](crate::tz::TimeZoneDatabase) created by
1264    /// [`tz::db`](crate::tz::db). Indeed, this is a convenience function
1265    /// for [`Timestamp::to_zoned`] where the time zone database lookup
1266    /// is done automatically.
1267    ///
1268    /// Assuming the time zone name could be resolved to a [`TimeZone`], this
1269    /// routine is otherwise infallible and never results in any ambiguity
1270    /// since both a [`Timestamp`] and a [`Zoned`] correspond to precise
1271    /// instant in time. This is unlike
1272    /// [`civil::DateTime::to_zoned`](crate::civil::DateTime::to_zoned),
1273    /// where a civil datetime might correspond to more than one instant in
1274    /// time (i.e., a fold, typically DST ending) or no instants in time (i.e.,
1275    /// a gap, typically DST starting).
1276    ///
1277    /// # Errors
1278    ///
1279    /// This returns an error when the given time zone name could not be found
1280    /// in the default time zone database.
1281    ///
1282    /// # Example
1283    ///
1284    /// This is a simple example of converting the instant that is `123,456,789`
1285    /// seconds after the Unix epoch to an instant that is aware of its time
1286    /// zone:
1287    ///
1288    /// ```
1289    /// use jiff::Timestamp;
1290    ///
1291    /// let ts = Timestamp::new(123_456_789, 0).unwrap();
1292    /// let zdt = ts.in_tz("America/New_York")?;
1293    /// assert_eq!(zdt.to_string(), "1973-11-29T16:33:09-05:00[America/New_York]");
1294    ///
1295    /// # Ok::<(), Box<dyn std::error::Error>>(())
1296    /// ```
1297    ///
1298    /// This can be used to answer questions like, "What time was it at the
1299    /// Unix epoch in Tasmania?"
1300    ///
1301    /// ```
1302    /// use jiff::Timestamp;
1303    ///
1304    /// // Time zone database lookups are case insensitive!
1305    /// let zdt = Timestamp::UNIX_EPOCH.in_tz("australia/tasmania")?;
1306    /// assert_eq!(zdt.to_string(), "1970-01-01T11:00:00+11:00[Australia/Tasmania]");
1307    ///
1308    /// # Ok::<(), Box<dyn std::error::Error>>(())
1309    /// ```
1310    ///
1311    /// # Example: errors
1312    ///
1313    /// This routine can return an error when the time zone is unrecognized:
1314    ///
1315    /// ```
1316    /// use jiff::Timestamp;
1317    ///
1318    /// assert!(Timestamp::UNIX_EPOCH.in_tz("does not exist").is_err());
1319    /// ```
1320    #[inline]
1321    pub fn in_tz(self, time_zone_name: &str) -> Result<Zoned, Error> {
1322        let tz = crate::tz::db().get(time_zone_name)?;
1323        Ok(self.to_zoned(tz))
1324    }
1325
1326    /// Creates a [`Zoned`] value by attaching the given time zone to this
1327    /// instant in time.
1328    ///
1329    /// This is infallible and never results in any ambiguity since both a
1330    /// [`Timestamp`] and a [`Zoned`] correspond to precise instant in time.
1331    /// This is unlike
1332    /// [`civil::DateTime::to_zoned`](crate::civil::DateTime::to_zoned),
1333    /// where a civil datetime might correspond to more than one instant in
1334    /// time (i.e., a fold, typically DST ending) or no instants in time (i.e.,
1335    /// a gap, typically DST starting).
1336    ///
1337    /// In the common case of a time zone being represented as a name string,
1338    /// like `Australia/Tasmania`, consider using [`Timestamp::in_tz`]
1339    /// instead.
1340    ///
1341    /// # Example
1342    ///
1343    /// This example shows how to create a zoned value with a fixed time zone
1344    /// offset:
1345    ///
1346    /// ```
1347    /// use jiff::{tz::{self, TimeZone}, Timestamp};
1348    ///
1349    /// let ts = Timestamp::new(123_456_789, 0).unwrap();
1350    /// let tz = TimeZone::fixed(tz::offset(-4));
1351    /// let zdt = ts.to_zoned(tz);
1352    /// // A time zone annotation is still included in the printable version
1353    /// // of the Zoned value, but it is fixed to a particular offset.
1354    /// assert_eq!(zdt.to_string(), "1973-11-29T17:33:09-04:00[-04:00]");
1355    /// ```
1356    ///
1357    /// # Example: POSIX time zone strings
1358    ///
1359    /// This example shows how to create a time zone from a POSIX time zone
1360    /// string that describes the transition to and from daylight saving
1361    /// time for `America/St_Johns`. In particular, this rule uses non-zero
1362    /// minutes, which is atypical.
1363    ///
1364    /// ```
1365    /// use jiff::{tz::TimeZone, Timestamp};
1366    ///
1367    /// let ts = Timestamp::new(123_456_789, 0)?;
1368    /// let tz = TimeZone::posix("NST3:30NDT,M3.2.0,M11.1.0")?;
1369    /// let zdt = ts.to_zoned(tz);
1370    /// // There isn't any agreed upon mechanism for transmitting a POSIX time
1371    /// // zone string within an RFC 9557 TZ annotation, so Jiff just emits the
1372    /// // offset. In practice, POSIX TZ strings are rarely user facing anyway.
1373    /// // (They are still in widespread use as an implementation detail of the
1374    /// // IANA Time Zone Database however.)
1375    /// assert_eq!(zdt.to_string(), "1973-11-29T18:03:09-03:30[-03:30]");
1376    ///
1377    /// # Ok::<(), Box<dyn std::error::Error>>(())
1378    /// ```
1379    #[inline]
1380    pub fn to_zoned(self, tz: TimeZone) -> Zoned {
1381        Zoned::new(self, tz)
1382    }
1383
1384    /// Add the given span of time to this timestamp.
1385    ///
1386    /// This operation accepts three different duration types: [`Span`],
1387    /// [`SignedDuration`] or [`std::time::Duration`]. This is achieved via
1388    /// `From` trait implementations for the [`TimestampArithmetic`] type.
1389    ///
1390    /// # Properties
1391    ///
1392    /// Given a timestamp `ts1` and a span `s`, and assuming `ts2 = ts1 + s`
1393    /// exists, it follows then that `ts1 = ts2 - s` for all values of `ts1`
1394    /// and `s` that sum to a valid `ts2`.
1395    ///
1396    /// In short, subtracting the given span from the sum returned by this
1397    /// function is guaranteed to result in precisely the original timestamp.
1398    ///
1399    /// # Errors
1400    ///
1401    /// If the sum would overflow the minimum or maximum timestamp values, then
1402    /// an error is returned.
1403    ///
1404    /// This also returns an error if the given duration is a `Span` with any
1405    /// non-zero units greater than hours. If you want to use bigger units,
1406    /// convert this timestamp to a `Zoned` and use [`Zoned::checked_add`].
1407    /// This error occurs because a `Timestamp` has no time zone attached to
1408    /// it, and thus cannot unambiguously resolve the length of a single day.
1409    ///
1410    /// # Example
1411    ///
1412    /// This shows how to add `5` hours to the Unix epoch:
1413    ///
1414    /// ```
1415    /// use jiff::{Timestamp, ToSpan};
1416    ///
1417    /// let ts = Timestamp::UNIX_EPOCH.checked_add(5.hours())?;
1418    /// assert_eq!(ts.to_string(), "1970-01-01T05:00:00Z");
1419    ///
1420    /// # Ok::<(), Box<dyn std::error::Error>>(())
1421    /// ```
1422    ///
1423    /// # Example: negative spans are supported
1424    ///
1425    /// This shows how to add `-5` hours to the Unix epoch. This is the same
1426    /// as subtracting `5` hours from the Unix epoch.
1427    ///
1428    /// ```
1429    /// use jiff::{Timestamp, ToSpan};
1430    ///
1431    /// let ts = Timestamp::UNIX_EPOCH.checked_add(-5.hours())?;
1432    /// assert_eq!(ts.to_string(), "1969-12-31T19:00:00Z");
1433    ///
1434    /// # Ok::<(), Box<dyn std::error::Error>>(())
1435    /// ```
1436    ///
1437    /// # Example: available via addition operator
1438    ///
1439    /// This routine can be used via the `+` operator. Note though that if it
1440    /// fails, it will result in a panic.
1441    ///
1442    /// ```
1443    /// use jiff::{Timestamp, ToSpan};
1444    ///
1445    /// let ts1 = Timestamp::new(2_999_999_999, 0)?;
1446    /// assert_eq!(ts1.to_string(), "2065-01-24T05:19:59Z");
1447    ///
1448    /// let ts2 = ts1 + 1.hour().minutes(30).nanoseconds(123);
1449    /// assert_eq!(ts2.to_string(), "2065-01-24T06:49:59.000000123Z");
1450    ///
1451    /// # Ok::<(), Box<dyn std::error::Error>>(())
1452    /// ```
1453    ///
1454    /// # Example: error on overflow
1455    ///
1456    /// ```
1457    /// use jiff::{Timestamp, ToSpan};
1458    ///
1459    /// let ts = Timestamp::MAX;
1460    /// assert_eq!(ts.to_string(), "9999-12-30T22:00:00.999999999Z");
1461    /// assert!(ts.checked_add(1.nanosecond()).is_err());
1462    ///
1463    /// let ts = Timestamp::MIN;
1464    /// assert_eq!(ts.to_string(), "-009999-01-02T01:59:59Z");
1465    /// assert!(ts.checked_add(-1.nanosecond()).is_err());
1466    /// ```
1467    ///
1468    /// # Example: adding absolute durations
1469    ///
1470    /// This shows how to add signed and unsigned absolute durations to a
1471    /// `Timestamp`.
1472    ///
1473    /// ```
1474    /// use std::time::Duration;
1475    ///
1476    /// use jiff::{SignedDuration, Timestamp};
1477    ///
1478    /// let ts1 = Timestamp::new(2_999_999_999, 0)?;
1479    /// assert_eq!(ts1.to_string(), "2065-01-24T05:19:59Z");
1480    ///
1481    /// let dur = SignedDuration::new(60 * 60 + 30 * 60, 123);
1482    /// assert_eq!(
1483    ///     ts1.checked_add(dur)?.to_string(),
1484    ///     "2065-01-24T06:49:59.000000123Z",
1485    /// );
1486    ///
1487    /// let dur = Duration::new(60 * 60 + 30 * 60, 123);
1488    /// assert_eq!(
1489    ///     ts1.checked_add(dur)?.to_string(),
1490    ///     "2065-01-24T06:49:59.000000123Z",
1491    /// );
1492    ///
1493    /// # Ok::<(), Box<dyn std::error::Error>>(())
1494    /// ```
1495    #[inline]
1496    pub fn checked_add<A: Into<TimestampArithmetic>>(
1497        self,
1498        duration: A,
1499    ) -> Result<Timestamp, Error> {
1500        let duration: TimestampArithmetic = duration.into();
1501        duration.checked_add(self)
1502    }
1503
1504    #[inline]
1505    fn checked_add_span(self, span: Span) -> Result<Timestamp, Error> {
1506        if let Some(err) = span.smallest_non_time_non_zero_unit_error() {
1507            return Err(err);
1508        }
1509        if span.is_zero() {
1510            return Ok(self);
1511        }
1512        // The common case is probably a span without fractional seconds, so
1513        // we specialize for that since it requires a fair bit less math.
1514        //
1515        // Note that this only works when *both* the span and timestamp lack
1516        // fractional seconds.
1517        if self.subsec_nanosecond_ranged() == C(0) {
1518            if let Some(span_seconds) = span.to_invariant_seconds() {
1519                let time_seconds = self.as_second_ranged();
1520                let sum = time_seconds
1521                    .try_checked_add("span", span_seconds)
1522                    .context(E::OverflowAddSpan)?;
1523                return Ok(Timestamp::from_second_ranged(sum));
1524            }
1525        }
1526        let time_nanos = self.as_nanosecond_ranged();
1527        let span_nanos = span.to_invariant_nanoseconds();
1528        let sum = time_nanos
1529            .try_checked_add("span", span_nanos)
1530            .context(E::OverflowAddSpan)?;
1531        Ok(Timestamp::from_nanosecond_ranged(sum))
1532    }
1533
1534    #[inline]
1535    fn checked_add_duration(
1536        self,
1537        duration: SignedDuration,
1538    ) -> Result<Timestamp, Error> {
1539        let start = self.as_duration();
1540        let end = start.checked_add(duration).ok_or(E::OverflowAddDuration)?;
1541        Timestamp::from_duration(end)
1542    }
1543
1544    /// This routine is identical to [`Timestamp::checked_add`] with the
1545    /// duration negated.
1546    ///
1547    /// # Errors
1548    ///
1549    /// This has the same error conditions as [`Timestamp::checked_add`].
1550    ///
1551    /// # Example
1552    ///
1553    /// This routine can be used via the `-` operator. Note though that if it
1554    /// fails, it will result in a panic.
1555    ///
1556    /// ```
1557    /// use jiff::{SignedDuration, Timestamp, ToSpan};
1558    ///
1559    /// let ts1 = Timestamp::new(2_999_999_999, 0)?;
1560    /// assert_eq!(ts1.to_string(), "2065-01-24T05:19:59Z");
1561    ///
1562    /// let ts2 = ts1 - 1.hour().minutes(30).nanoseconds(123);
1563    /// assert_eq!(ts2.to_string(), "2065-01-24T03:49:58.999999877Z");
1564    ///
1565    /// # Ok::<(), Box<dyn std::error::Error>>(())
1566    /// ```
1567    ///
1568    /// # Example: use with [`SignedDuration`] and [`std::time::Duration`]
1569    ///
1570    /// ```
1571    /// use std::time::Duration;
1572    ///
1573    /// use jiff::{SignedDuration, Timestamp};
1574    ///
1575    /// let ts1 = Timestamp::new(2_999_999_999, 0)?;
1576    /// assert_eq!(ts1.to_string(), "2065-01-24T05:19:59Z");
1577    ///
1578    /// let dur = SignedDuration::new(60 * 60 + 30 * 60, 123);
1579    /// assert_eq!(
1580    ///     ts1.checked_sub(dur)?.to_string(),
1581    ///     "2065-01-24T03:49:58.999999877Z",
1582    /// );
1583    ///
1584    /// let dur = Duration::new(60 * 60 + 30 * 60, 123);
1585    /// assert_eq!(
1586    ///     ts1.checked_sub(dur)?.to_string(),
1587    ///     "2065-01-24T03:49:58.999999877Z",
1588    /// );
1589    ///
1590    /// # Ok::<(), Box<dyn std::error::Error>>(())
1591    /// ```
1592    #[inline]
1593    pub fn checked_sub<A: Into<TimestampArithmetic>>(
1594        self,
1595        duration: A,
1596    ) -> Result<Timestamp, Error> {
1597        let duration: TimestampArithmetic = duration.into();
1598        duration.checked_neg().and_then(|ta| ta.checked_add(self))
1599    }
1600
1601    /// This routine is identical to [`Timestamp::checked_add`], except the
1602    /// result saturates on overflow. That is, instead of overflow, either
1603    /// [`Timestamp::MIN`] or [`Timestamp::MAX`] is returned.
1604    ///
1605    /// # Errors
1606    ///
1607    /// This returns an error if the given `Span` contains any non-zero units
1608    /// greater than hours.
1609    ///
1610    /// # Example
1611    ///
1612    /// This example shows that arithmetic saturates on overflow.
1613    ///
1614    /// ```
1615    /// use jiff::{SignedDuration, Timestamp, ToSpan};
1616    ///
1617    /// assert_eq!(
1618    ///     Timestamp::MAX,
1619    ///     Timestamp::MAX.saturating_add(1.nanosecond())?,
1620    /// );
1621    /// assert_eq!(
1622    ///     Timestamp::MIN,
1623    ///     Timestamp::MIN.saturating_add(-1.nanosecond())?,
1624    /// );
1625    /// assert_eq!(
1626    ///     Timestamp::MAX,
1627    ///     Timestamp::UNIX_EPOCH.saturating_add(SignedDuration::MAX)?,
1628    /// );
1629    /// assert_eq!(
1630    ///     Timestamp::MIN,
1631    ///     Timestamp::UNIX_EPOCH.saturating_add(SignedDuration::MIN)?,
1632    /// );
1633    /// assert_eq!(
1634    ///     Timestamp::MAX,
1635    ///     Timestamp::UNIX_EPOCH.saturating_add(std::time::Duration::MAX)?,
1636    /// );
1637    ///
1638    /// # Ok::<(), Box<dyn std::error::Error>>(())
1639    /// ```
1640    #[inline]
1641    pub fn saturating_add<A: Into<TimestampArithmetic>>(
1642        self,
1643        duration: A,
1644    ) -> Result<Timestamp, Error> {
1645        let duration: TimestampArithmetic = duration.into();
1646        duration.saturating_add(self).context(E::RequiresSaturatingTimeUnits)
1647    }
1648
1649    /// This routine is identical to [`Timestamp::saturating_add`] with the
1650    /// span parameter negated.
1651    ///
1652    /// # Errors
1653    ///
1654    /// This returns an error if the given `Span` contains any non-zero units
1655    /// greater than hours.
1656    ///
1657    /// # Example
1658    ///
1659    /// This example shows that arithmetic saturates on overflow.
1660    ///
1661    /// ```
1662    /// use jiff::{SignedDuration, Timestamp, ToSpan};
1663    ///
1664    /// assert_eq!(
1665    ///     Timestamp::MIN,
1666    ///     Timestamp::MIN.saturating_sub(1.nanosecond())?,
1667    /// );
1668    /// assert_eq!(
1669    ///     Timestamp::MAX,
1670    ///     Timestamp::MAX.saturating_sub(-1.nanosecond())?,
1671    /// );
1672    /// assert_eq!(
1673    ///     Timestamp::MIN,
1674    ///     Timestamp::UNIX_EPOCH.saturating_sub(SignedDuration::MAX)?,
1675    /// );
1676    /// assert_eq!(
1677    ///     Timestamp::MAX,
1678    ///     Timestamp::UNIX_EPOCH.saturating_sub(SignedDuration::MIN)?,
1679    /// );
1680    /// assert_eq!(
1681    ///     Timestamp::MIN,
1682    ///     Timestamp::UNIX_EPOCH.saturating_sub(std::time::Duration::MAX)?,
1683    /// );
1684    ///
1685    /// # Ok::<(), Box<dyn std::error::Error>>(())
1686    /// ```
1687    #[inline]
1688    pub fn saturating_sub<A: Into<TimestampArithmetic>>(
1689        self,
1690        duration: A,
1691    ) -> Result<Timestamp, Error> {
1692        let duration: TimestampArithmetic = duration.into();
1693        let Ok(duration) = duration.checked_neg() else {
1694            return Ok(Timestamp::MIN);
1695        };
1696        self.saturating_add(duration)
1697    }
1698
1699    /// Returns a span representing the elapsed time from this timestamp until
1700    /// the given `other` timestamp.
1701    ///
1702    /// When `other` occurs before this timestamp, then the span returned will
1703    /// be negative.
1704    ///
1705    /// Depending on the input provided, the span returned is rounded. It may
1706    /// also be balanced up to bigger units than the default. By default,
1707    /// the span returned is balanced such that the biggest possible unit is
1708    /// seconds.
1709    ///
1710    /// This operation is configured by providing a [`TimestampDifference`]
1711    /// value. Since this routine accepts anything that implements
1712    /// `Into<TimestampDifference>`, once can pass a `Timestamp` directly.
1713    /// One can also pass a `(Unit, Timestamp)`, where `Unit` is treated as
1714    /// [`TimestampDifference::largest`].
1715    ///
1716    /// # Properties
1717    ///
1718    /// It is guaranteed that if the returned span is subtracted from `other`,
1719    /// and if no rounding is requested, then the original timestamp will be
1720    /// returned.
1721    ///
1722    /// This routine is equivalent to `self.since(other).map(|span| -span)`
1723    /// if no rounding options are set. If rounding options are set, then
1724    /// it's equivalent to
1725    /// `self.since(other_without_rounding_options).map(|span| -span)`,
1726    /// followed by a call to [`Span::round`] with the appropriate rounding
1727    /// options set. This is because the negation of a span can result in
1728    /// different rounding results depending on the rounding mode.
1729    ///
1730    /// # Errors
1731    ///
1732    /// An error can occur in some cases when the requested configuration
1733    /// would result in a span that is beyond allowable limits. For example,
1734    /// the nanosecond component of a span cannot represent the span of
1735    /// time between the minimum and maximum timestamps supported by Jiff.
1736    /// Therefore, if one requests a span with its largest unit set to
1737    /// [`Unit::Nanosecond`], then it's possible for this routine to fail.
1738    ///
1739    /// An error can also occur if `TimestampDifference` is misconfigured. For
1740    /// example, if the smallest unit provided is bigger than the largest unit,
1741    /// or if the largest unit provided is bigger than hours. (To use bigger
1742    /// units with an instant in time, use [`Zoned::until`] instead.)
1743    ///
1744    /// It is guaranteed that if one provides a timestamp with the default
1745    /// [`TimestampDifference`] configuration, then this routine will never
1746    /// fail.
1747    ///
1748    /// # Example
1749    ///
1750    /// ```
1751    /// use jiff::{Timestamp, ToSpan};
1752    ///
1753    /// let earlier: Timestamp = "2006-08-24T22:30:00Z".parse()?;
1754    /// let later: Timestamp = "2019-01-31 21:00:00Z".parse()?;
1755    /// assert_eq!(earlier.until(later)?, 392509800.seconds().fieldwise());
1756    ///
1757    /// // Flipping the timestamps is fine, but you'll get a negative span.
1758    /// assert_eq!(later.until(earlier)?, -392509800.seconds().fieldwise());
1759    ///
1760    /// # Ok::<(), Box<dyn std::error::Error>>(())
1761    /// ```
1762    ///
1763    /// # Example: using bigger units
1764    ///
1765    /// This example shows how to expand the span returned to bigger units.
1766    /// This makes use of a `From<(Unit, Timestamp)> for TimestampDifference`
1767    /// trait implementation.
1768    ///
1769    /// ```
1770    /// use jiff::{Timestamp, ToSpan, Unit};
1771    ///
1772    /// let ts1: Timestamp = "1995-12-07T03:24:30.000003500Z".parse()?;
1773    /// let ts2: Timestamp = "2019-01-31 15:30:00Z".parse()?;
1774    ///
1775    /// // The default limits durations to using "seconds" as the biggest unit.
1776    /// let span = ts1.until(ts2)?;
1777    /// assert_eq!(span.to_string(), "PT730641929.9999965S");
1778    ///
1779    /// // But we can ask for units all the way up to hours.
1780    /// let span = ts1.until((Unit::Hour, ts2))?;
1781    /// assert_eq!(span.to_string(), "PT202956H5M29.9999965S");
1782    ///
1783    /// # Ok::<(), Box<dyn std::error::Error>>(())
1784    /// ```
1785    ///
1786    /// # Example: rounding the result
1787    ///
1788    /// This shows how one might find the difference between two timestamps and
1789    /// have the result rounded such that sub-seconds are removed.
1790    ///
1791    /// In this case, we need to hand-construct a [`TimestampDifference`]
1792    /// in order to gain full configurability.
1793    ///
1794    /// ```
1795    /// use jiff::{Timestamp, TimestampDifference, ToSpan, Unit};
1796    ///
1797    /// let ts1: Timestamp = "1995-12-07 03:24:30.000003500Z".parse()?;
1798    /// let ts2: Timestamp = "2019-01-31 15:30:00Z".parse()?;
1799    ///
1800    /// let span = ts1.until(
1801    ///     TimestampDifference::from(ts2).smallest(Unit::Second),
1802    /// )?;
1803    /// assert_eq!(span.to_string(), "PT730641929S");
1804    ///
1805    /// // We can combine smallest and largest units too!
1806    /// let span = ts1.until(
1807    ///     TimestampDifference::from(ts2)
1808    ///         .smallest(Unit::Second)
1809    ///         .largest(Unit::Hour),
1810    /// )?;
1811    /// assert_eq!(span.to_string(), "PT202956H5M29S");
1812    /// # Ok::<(), Box<dyn std::error::Error>>(())
1813    /// ```
1814    #[inline]
1815    pub fn until<A: Into<TimestampDifference>>(
1816        self,
1817        other: A,
1818    ) -> Result<Span, Error> {
1819        let args: TimestampDifference = other.into();
1820        let span = args.until_with_largest_unit(self)?;
1821        if args.rounding_may_change_span() {
1822            span.round(args.round)
1823        } else {
1824            Ok(span)
1825        }
1826    }
1827
1828    /// This routine is identical to [`Timestamp::until`], but the order of the
1829    /// parameters is flipped.
1830    ///
1831    /// # Errors
1832    ///
1833    /// This has the same error conditions as [`Timestamp::until`].
1834    ///
1835    /// # Example
1836    ///
1837    /// This routine can be used via the `-` operator. Since the default
1838    /// configuration is used and because a `Span` can represent the difference
1839    /// between any two possible timestamps, it will never panic.
1840    ///
1841    /// ```
1842    /// use jiff::{Timestamp, ToSpan};
1843    ///
1844    /// let earlier: Timestamp = "2006-08-24T22:30:00Z".parse()?;
1845    /// let later: Timestamp = "2019-01-31 21:00:00Z".parse()?;
1846    /// assert_eq!(later - earlier, 392509800.seconds().fieldwise());
1847    ///
1848    /// # Ok::<(), Box<dyn std::error::Error>>(())
1849    /// ```
1850    #[inline]
1851    pub fn since<A: Into<TimestampDifference>>(
1852        self,
1853        other: A,
1854    ) -> Result<Span, Error> {
1855        let args: TimestampDifference = other.into();
1856        let span = -args.until_with_largest_unit(self)?;
1857        if args.rounding_may_change_span() {
1858            span.round(args.round)
1859        } else {
1860            Ok(span)
1861        }
1862    }
1863
1864    /// Returns an absolute duration representing the elapsed time from this
1865    /// timestamp until the given `other` timestamp.
1866    ///
1867    /// When `other` occurs before this timestamp, then the duration returned
1868    /// will be negative.
1869    ///
1870    /// Unlike [`Timestamp::until`], this always returns a duration
1871    /// corresponding to a 96-bit integer of nanoseconds between two
1872    /// timestamps.
1873    ///
1874    /// # Fallibility
1875    ///
1876    /// This routine never panics or returns an error. Since there are no
1877    /// configuration options that can be incorrectly provided, no error is
1878    /// possible when calling this routine. In contrast, [`Timestamp::until`]
1879    /// can return an error in some cases due to misconfiguration. But like
1880    /// this routine, [`Timestamp::until`] never panics or returns an error in
1881    /// its default configuration.
1882    ///
1883    /// # When should I use this versus [`Timestamp::until`]?
1884    ///
1885    /// See the type documentation for [`SignedDuration`] for the section on
1886    /// when one should use [`Span`] and when one should use `SignedDuration`.
1887    /// In short, use `Span` (and therefore `Timestamp::until`) unless you have
1888    /// a specific reason to do otherwise.
1889    ///
1890    /// # Example
1891    ///
1892    /// ```
1893    /// use jiff::{Timestamp, SignedDuration};
1894    ///
1895    /// let earlier: Timestamp = "2006-08-24T22:30:00Z".parse()?;
1896    /// let later: Timestamp = "2019-01-31 21:00:00Z".parse()?;
1897    /// assert_eq!(
1898    ///     earlier.duration_until(later),
1899    ///     SignedDuration::from_secs(392509800),
1900    /// );
1901    ///
1902    /// // Flipping the timestamps is fine, but you'll get a negative span.
1903    /// assert_eq!(
1904    ///     later.duration_until(earlier),
1905    ///     SignedDuration::from_secs(-392509800),
1906    /// );
1907    ///
1908    /// # Ok::<(), Box<dyn std::error::Error>>(())
1909    /// ```
1910    ///
1911    /// # Example: difference with [`Timestamp::until`]
1912    ///
1913    /// The primary difference between this routine and
1914    /// `Timestamp::until`, other than the return type, is that this
1915    /// routine is likely to be faster. Namely, it does simple 96-bit
1916    /// integer math, where as `Timestamp::until` has to do a bit more
1917    /// work to deal with the different types of units on a `Span`.
1918    ///
1919    /// Additionally, since the difference between two timestamps is always
1920    /// expressed in units of hours or smaller, and units of hours or smaller
1921    /// are always uniform, there is no "expressive" difference between this
1922    /// routine and `Timestamp::until`. Because of this, one can always
1923    /// convert between `Span` and `SignedDuration` as returned by methods
1924    /// on `Timestamp` without a relative datetime:
1925    ///
1926    /// ```
1927    /// use jiff::{SignedDuration, Span, Timestamp};
1928    ///
1929    /// let ts1: Timestamp = "2024-02-28T00:00:00Z".parse()?;
1930    /// let ts2: Timestamp = "2024-03-01T00:00:00Z".parse()?;
1931    /// let dur = ts1.duration_until(ts2);
1932    /// // Guaranteed to never fail because the duration
1933    /// // between two civil times never exceeds the limits
1934    /// // of a `Span`.
1935    /// let span = Span::try_from(dur).unwrap();
1936    /// assert_eq!(format!("{span:#}"), "172800s");
1937    /// // Guaranteed to succeed and always return the original
1938    /// // duration because the units are always hours or smaller,
1939    /// // and thus uniform. This means a relative datetime is
1940    /// // never required to do this conversion.
1941    /// let dur = SignedDuration::try_from(span).unwrap();
1942    /// assert_eq!(dur, SignedDuration::from_secs(172_800));
1943    ///
1944    /// # Ok::<(), Box<dyn std::error::Error>>(())
1945    /// ```
1946    ///
1947    /// This conversion guarantee also applies to [`Timestamp::until`] since it
1948    /// always returns a balanced span. That is, it never returns spans like
1949    /// `1 second 1000 milliseconds`. (Those cannot be losslessly converted to
1950    /// a `SignedDuration` since a `SignedDuration` is only represented as a
1951    /// single 96-bit integer of nanoseconds.)
1952    #[inline]
1953    pub fn duration_until(self, other: Timestamp) -> SignedDuration {
1954        SignedDuration::timestamp_until(self, other)
1955    }
1956
1957    /// This routine is identical to [`Timestamp::duration_until`], but the
1958    /// order of the parameters is flipped.
1959    ///
1960    /// # Example
1961    ///
1962    /// ```
1963    /// use jiff::{SignedDuration, Timestamp};
1964    ///
1965    /// let earlier: Timestamp = "2006-08-24T22:30:00Z".parse()?;
1966    /// let later: Timestamp = "2019-01-31 21:00:00Z".parse()?;
1967    /// assert_eq!(
1968    ///     later.duration_since(earlier),
1969    ///     SignedDuration::from_secs(392509800),
1970    /// );
1971    ///
1972    /// # Ok::<(), Box<dyn std::error::Error>>(())
1973    /// ```
1974    #[inline]
1975    pub fn duration_since(self, other: Timestamp) -> SignedDuration {
1976        SignedDuration::timestamp_until(other, self)
1977    }
1978
1979    /// Rounds this timestamp according to the [`TimestampRound`] configuration
1980    /// given.
1981    ///
1982    /// The principal option is [`TimestampRound::smallest`], which allows
1983    /// one to configure the smallest units in the returned timestamp.
1984    /// Rounding is what determines whether the specified smallest unit
1985    /// should keep its current value or whether it should be incremented.
1986    /// Moreover, the amount it should be incremented can be configured via
1987    /// [`TimestampRound::increment`]. Finally, the rounding strategy itself
1988    /// can be configured via [`TimestampRound::mode`].
1989    ///
1990    /// Note that this routine is generic and accepts anything that
1991    /// implements `Into<TimestampRound>`. Some notable implementations are:
1992    ///
1993    /// * `From<Unit> for TimestampRound`, which will automatically create a
1994    /// `TimestampRound::new().smallest(unit)` from the unit provided.
1995    /// * `From<(Unit, i64)> for TimestampRound`, which will automatically
1996    /// create a `TimestampRound::new().smallest(unit).increment(number)` from
1997    /// the unit and increment provided.
1998    ///
1999    /// # Errors
2000    ///
2001    /// This returns an error if the smallest unit configured on the given
2002    /// [`TimestampRound`] is bigger than hours.
2003    ///
2004    /// The rounding increment, when combined with the smallest unit (which
2005    /// defaults to [`Unit::Nanosecond`]), must divide evenly into `86,400`
2006    /// seconds (one 24-hour civil day). For example, increments of both
2007    /// 45 seconds and 15 minutes are allowed, but 7 seconds and 25 minutes are
2008    /// both not allowed.
2009    ///
2010    /// # Example
2011    ///
2012    /// This is a basic example that demonstrates rounding a timestamp to the
2013    /// nearest hour. This also demonstrates calling this method with the
2014    /// smallest unit directly, instead of constructing a `TimestampRound`
2015    /// manually.
2016    ///
2017    /// ```
2018    /// use jiff::{Timestamp, Unit};
2019    ///
2020    /// let ts: Timestamp = "2024-06-19 15:30:00Z".parse()?;
2021    /// assert_eq!(
2022    ///     ts.round(Unit::Hour)?.to_string(),
2023    ///     "2024-06-19T16:00:00Z",
2024    /// );
2025    /// let ts: Timestamp = "2024-06-19 15:29:59Z".parse()?;
2026    /// assert_eq!(
2027    ///     ts.round(Unit::Hour)?.to_string(),
2028    ///     "2024-06-19T15:00:00Z",
2029    /// );
2030    ///
2031    /// # Ok::<(), Box<dyn std::error::Error>>(())
2032    /// ```
2033    ///
2034    /// # Example: changing the rounding mode
2035    ///
2036    /// The default rounding mode is [`RoundMode::HalfExpand`], which
2037    /// breaks ties by rounding away from zero. But other modes like
2038    /// [`RoundMode::Trunc`] can be used too:
2039    ///
2040    /// ```
2041    /// use jiff::{RoundMode, Timestamp, TimestampRound, Unit};
2042    ///
2043    /// // The default will round up to the next hour for any time past the
2044    /// // 30 minute mark, but using truncation rounding will always round
2045    /// // down.
2046    /// let ts: Timestamp = "2024-06-19 15:30:00Z".parse()?;
2047    /// assert_eq!(
2048    ///     ts.round(
2049    ///         TimestampRound::new()
2050    ///             .smallest(Unit::Hour)
2051    ///             .mode(RoundMode::Trunc),
2052    ///     )?.to_string(),
2053    ///     "2024-06-19T15:00:00Z",
2054    /// );
2055    ///
2056    /// # Ok::<(), Box<dyn std::error::Error>>(())
2057    /// ```
2058    ///
2059    /// # Example: rounding to the nearest 5 minute increment
2060    ///
2061    /// ```
2062    /// use jiff::{Timestamp, Unit};
2063    ///
2064    /// // rounds down
2065    /// let ts: Timestamp = "2024-06-19T15:27:29.999999999Z".parse()?;
2066    /// assert_eq!(
2067    ///     ts.round((Unit::Minute, 5))?.to_string(),
2068    ///     "2024-06-19T15:25:00Z",
2069    /// );
2070    /// // rounds up
2071    /// let ts: Timestamp = "2024-06-19T15:27:30Z".parse()?;
2072    /// assert_eq!(
2073    ///     ts.round((Unit::Minute, 5))?.to_string(),
2074    ///     "2024-06-19T15:30:00Z",
2075    /// );
2076    ///
2077    /// # Ok::<(), Box<dyn std::error::Error>>(())
2078    /// ```
2079    #[inline]
2080    pub fn round<R: Into<TimestampRound>>(
2081        self,
2082        options: R,
2083    ) -> Result<Timestamp, Error> {
2084        let options: TimestampRound = options.into();
2085        options.round(self)
2086    }
2087
2088    /// Return an iterator of periodic timestamps determined by the given span.
2089    ///
2090    /// The given span may be negative, in which case, the iterator will move
2091    /// backwards through time. The iterator won't stop until either the span
2092    /// itself overflows, or it would otherwise exceed the minimum or maximum
2093    /// `Timestamp` value.
2094    ///
2095    /// # Example: when to check a glucose monitor
2096    ///
2097    /// When my cat had diabetes, my veterinarian installed a glucose monitor
2098    /// and instructed me to scan it about every 5 hours. This example lists
2099    /// all of the times I need to scan it for the 2 days following its
2100    /// installation:
2101    ///
2102    /// ```
2103    /// use jiff::{Timestamp, ToSpan};
2104    ///
2105    /// let start: Timestamp = "2023-07-15 16:30:00-04".parse()?;
2106    /// let end = start.checked_add(48.hours())?;
2107    /// let mut scan_times = vec![];
2108    /// for ts in start.series(5.hours()).take_while(|&ts| ts <= end) {
2109    ///     scan_times.push(ts);
2110    /// }
2111    /// assert_eq!(scan_times, vec![
2112    ///     "2023-07-15 16:30:00-04:00".parse::<Timestamp>()?,
2113    ///     "2023-07-15 21:30:00-04:00".parse::<Timestamp>()?,
2114    ///     "2023-07-16 02:30:00-04:00".parse::<Timestamp>()?,
2115    ///     "2023-07-16 07:30:00-04:00".parse::<Timestamp>()?,
2116    ///     "2023-07-16 12:30:00-04:00".parse::<Timestamp>()?,
2117    ///     "2023-07-16 17:30:00-04:00".parse::<Timestamp>()?,
2118    ///     "2023-07-16 22:30:00-04:00".parse::<Timestamp>()?,
2119    ///     "2023-07-17 03:30:00-04:00".parse::<Timestamp>()?,
2120    ///     "2023-07-17 08:30:00-04:00".parse::<Timestamp>()?,
2121    ///     "2023-07-17 13:30:00-04:00".parse::<Timestamp>()?,
2122    /// ]);
2123    ///
2124    /// # Ok::<(), Box<dyn std::error::Error>>(())
2125    /// ```
2126    #[inline]
2127    pub fn series(self, period: Span) -> TimestampSeries {
2128        TimestampSeries::new(self, period)
2129    }
2130}
2131
2132/// Parsing and formatting APIs.
2133impl Timestamp {
2134    /// Parses a timestamp (expressed as broken down time) in `input` matching
2135    /// the given `format`.
2136    ///
2137    /// The format string uses a "printf"-style API where conversion
2138    /// specifiers can be used as place holders to match components of
2139    /// a datetime. For details on the specifiers supported, see the
2140    /// [`fmt::strtime`] module documentation.
2141    ///
2142    /// # Errors
2143    ///
2144    /// This returns an error when parsing failed. This might happen because
2145    /// the format string itself was invalid, or because the input didn't match
2146    /// the format string.
2147    ///
2148    /// This also returns an error if there wasn't sufficient information to
2149    /// construct a timestamp. For example, if an offset wasn't parsed. (The
2150    /// offset is needed to turn the civil time parsed into a precise instant
2151    /// in time.)
2152    ///
2153    /// # Example
2154    ///
2155    /// This example shows how to parse a datetime string into a timestamp:
2156    ///
2157    /// ```
2158    /// use jiff::Timestamp;
2159    ///
2160    /// let ts = Timestamp::strptime("%F %H:%M %:z", "2024-07-14 21:14 -04:00")?;
2161    /// assert_eq!(ts.to_string(), "2024-07-15T01:14:00Z");
2162    ///
2163    /// # Ok::<(), Box<dyn std::error::Error>>(())
2164    /// ```
2165    #[inline]
2166    pub fn strptime(
2167        format: impl AsRef<[u8]>,
2168        input: impl AsRef<[u8]>,
2169    ) -> Result<Timestamp, Error> {
2170        fmt::strtime::parse(format, input).and_then(|tm| tm.to_timestamp())
2171    }
2172
2173    /// Formats this timestamp according to the given `format`.
2174    ///
2175    /// The format string uses a "printf"-style API where conversion
2176    /// specifiers can be used as place holders to format components of
2177    /// a datetime. For details on the specifiers supported, see the
2178    /// [`fmt::strtime`] module documentation.
2179    ///
2180    /// # Errors and panics
2181    ///
2182    /// While this routine itself does not error or panic, using the value
2183    /// returned may result in a panic if formatting fails. See the
2184    /// documentation on [`fmt::strtime::Display`] for more information.
2185    ///
2186    /// To format in a way that surfaces errors without panicking, use either
2187    /// [`fmt::strtime::format`] or [`fmt::strtime::BrokenDownTime::format`].
2188    ///
2189    /// # Example
2190    ///
2191    /// This shows how to format a timestamp into a human readable datetime
2192    /// in UTC:
2193    ///
2194    /// ```
2195    /// use jiff::{civil::date, Timestamp};
2196    ///
2197    /// let ts = Timestamp::from_second(86_400)?;
2198    /// let string = ts.strftime("%a %b %e %I:%M:%S %p UTC %Y").to_string();
2199    /// assert_eq!(string, "Fri Jan  2 12:00:00 AM UTC 1970");
2200    ///
2201    /// # Ok::<(), Box<dyn std::error::Error>>(())
2202    /// ```
2203    #[inline]
2204    pub fn strftime<'f, F: 'f + ?Sized + AsRef<[u8]>>(
2205        &self,
2206        format: &'f F,
2207    ) -> fmt::strtime::Display<'f> {
2208        fmt::strtime::Display { fmt: format.as_ref(), tm: (*self).into() }
2209    }
2210
2211    /// Format a `Timestamp` datetime into a string with the given offset.
2212    ///
2213    /// This will format to an RFC 3339 compatible string with an offset.
2214    ///
2215    /// This will never use either `Z` (for Zulu time) or `-00:00` as an
2216    /// offset. This is because Zulu time (and `-00:00`) mean "the time in UTC
2217    /// is known, but the offset to local time is unknown." Since this routine
2218    /// accepts an explicit offset, the offset is known. For example,
2219    /// `Offset::UTC` will be formatted as `+00:00`.
2220    ///
2221    /// To format an RFC 3339 string in Zulu time, use the default
2222    /// [`std::fmt::Display`] trait implementation on `Timestamp`.
2223    ///
2224    /// # Example
2225    ///
2226    /// ```
2227    /// use jiff::{tz, Timestamp};
2228    ///
2229    /// let ts = Timestamp::from_second(1)?;
2230    /// assert_eq!(
2231    ///     ts.display_with_offset(tz::offset(-5)).to_string(),
2232    ///     "1969-12-31T19:00:01-05:00",
2233    /// );
2234    ///
2235    /// # Ok::<(), Box<dyn std::error::Error>>(())
2236    /// ```
2237    #[inline]
2238    pub fn display_with_offset(
2239        &self,
2240        offset: Offset,
2241    ) -> TimestampDisplayWithOffset {
2242        TimestampDisplayWithOffset { timestamp: *self, offset }
2243    }
2244}
2245
2246/// Internal APIs using Jiff ranged integers.
2247impl Timestamp {
2248    #[inline]
2249    pub(crate) fn new_ranged(
2250        second: UnixSeconds,
2251        nanosecond: FractionalNanosecond,
2252    ) -> Result<Timestamp, Error> {
2253        if second == UnixSeconds::MIN_SELF && nanosecond < C(0) {
2254            return Err(Error::range(
2255                "seconds and nanoseconds",
2256                nanosecond,
2257                0,
2258                1_000_000_000,
2259            ));
2260        }
2261        // We now normalize our seconds and nanoseconds such that they have
2262        // the same sign (or where one is zero). So for example, when given
2263        // `-1s 1ns`, then we should turn that into `-999,999,999ns`.
2264        //
2265        // But first, if we're already normalized, we're done!
2266        if second.signum() == nanosecond.signum()
2267            || second == C(0)
2268            || nanosecond == C(0)
2269        {
2270            return Ok(Timestamp { second, nanosecond });
2271        }
2272        let second = second.without_bounds();
2273        let nanosecond = nanosecond.without_bounds();
2274        let [delta_second, delta_nanosecond] = t::NoUnits::vary_many(
2275            [second, nanosecond],
2276            |[second, nanosecond]| {
2277                if second < C(0) && nanosecond > C(0) {
2278                    [C(1), (-t::NANOS_PER_SECOND).rinto()]
2279                } else if second > C(0) && nanosecond < C(0) {
2280                    [C(-1), t::NANOS_PER_SECOND.rinto()]
2281                } else {
2282                    [C(0), C(0)]
2283                }
2284            },
2285        );
2286        Ok(Timestamp {
2287            second: (second + delta_second).rinto(),
2288            nanosecond: (nanosecond + delta_nanosecond).rinto(),
2289        })
2290    }
2291
2292    #[inline]
2293    fn from_second_ranged(second: UnixSeconds) -> Timestamp {
2294        Timestamp { second, nanosecond: FractionalNanosecond::N::<0>() }
2295    }
2296
2297    #[inline]
2298    fn from_millisecond_ranged(millisecond: UnixMilliseconds) -> Timestamp {
2299        let second =
2300            UnixSeconds::rfrom(millisecond.div_ceil(t::MILLIS_PER_SECOND));
2301        let nanosecond = FractionalNanosecond::rfrom(
2302            millisecond.rem_ceil(t::MILLIS_PER_SECOND) * t::NANOS_PER_MILLI,
2303        );
2304        Timestamp { second, nanosecond }
2305    }
2306
2307    #[inline]
2308    fn from_microsecond_ranged(microsecond: UnixMicroseconds) -> Timestamp {
2309        let second =
2310            UnixSeconds::rfrom(microsecond.div_ceil(t::MICROS_PER_SECOND));
2311        let nanosecond = FractionalNanosecond::rfrom(
2312            microsecond.rem_ceil(t::MICROS_PER_SECOND) * t::NANOS_PER_MICRO,
2313        );
2314        Timestamp { second, nanosecond }
2315    }
2316
2317    #[inline]
2318    pub(crate) fn from_nanosecond_ranged(
2319        nanosecond: UnixNanoseconds,
2320    ) -> Timestamp {
2321        let second =
2322            UnixSeconds::rfrom(nanosecond.div_ceil(t::NANOS_PER_SECOND));
2323        let nanosecond = nanosecond.rem_ceil(t::NANOS_PER_SECOND).rinto();
2324        Timestamp { second, nanosecond }
2325    }
2326
2327    #[inline]
2328    pub(crate) fn from_itimestamp(
2329        its: Composite<ITimestamp>,
2330    ) -> Result<Timestamp, Error> {
2331        let (second, nanosecond) =
2332            rangeint::uncomposite!(its, c => (c.second, c.nanosecond));
2333        Ok(Timestamp {
2334            second: second.try_to_rint("unix-seconds")?,
2335            nanosecond: nanosecond.to_rint(),
2336        })
2337    }
2338
2339    #[inline]
2340    pub(crate) fn to_itimestamp(&self) -> Composite<ITimestamp> {
2341        rangeint::composite! {
2342            (second = self.second, nanosecond = self.nanosecond) => {
2343                ITimestamp { second, nanosecond }
2344            }
2345        }
2346    }
2347
2348    #[inline]
2349    pub(crate) const fn from_itimestamp_const(its: ITimestamp) -> Timestamp {
2350        Timestamp {
2351            second: UnixSeconds::new_unchecked(its.second),
2352            nanosecond: FractionalNanosecond::new_unchecked(its.nanosecond),
2353        }
2354    }
2355
2356    #[inline]
2357    pub(crate) const fn to_itimestamp_const(&self) -> ITimestamp {
2358        ITimestamp {
2359            second: self.second.get_unchecked(),
2360            nanosecond: self.nanosecond.get_unchecked(),
2361        }
2362    }
2363
2364    #[inline]
2365    pub(crate) fn as_second_ranged(self) -> UnixSeconds {
2366        self.second
2367    }
2368
2369    #[inline]
2370    fn as_millisecond_ranged(self) -> UnixMilliseconds {
2371        let second = NoUnits::rfrom(self.as_second_ranged());
2372        let nanosecond = NoUnits::rfrom(self.subsec_nanosecond_ranged());
2373        // The minimum value of a timestamp has the fractional nanosecond set
2374        // to 0, but otherwise its minimum value is -999_999_999. So to avoid
2375        // a case where we return a ranged integer with a minimum value less
2376        // than the actual minimum, we clamp the fractional part to 0 when the
2377        // second value is the minimum.
2378        let [second, nanosecond] =
2379            NoUnits::vary_many([second, nanosecond], |[second, nanosecond]| {
2380                if second == UnixSeconds::MIN_SELF && nanosecond < C(0) {
2381                    [second, C(0).rinto()]
2382                } else {
2383                    [second, nanosecond]
2384                }
2385            });
2386        UnixMilliseconds::rfrom(
2387            (second * t::MILLIS_PER_SECOND)
2388                + (nanosecond.div_ceil(t::NANOS_PER_MILLI)),
2389        )
2390    }
2391
2392    #[inline]
2393    fn as_microsecond_ranged(self) -> UnixMicroseconds {
2394        let second = NoUnits::rfrom(self.as_second_ranged());
2395        let nanosecond = NoUnits::rfrom(self.subsec_nanosecond_ranged());
2396        // The minimum value of a timestamp has the fractional nanosecond set
2397        // to 0, but otherwise its minimum value is -999_999_999. So to avoid
2398        // a case where we return a ranged integer with a minimum value less
2399        // than the actual minimum, we clamp the fractional part to 0 when the
2400        // second value is the minimum.
2401        let [second, nanosecond] =
2402            NoUnits::vary_many([second, nanosecond], |[second, nanosecond]| {
2403                if second == UnixSeconds::MIN_SELF && nanosecond < C(0) {
2404                    [second, C(0).rinto()]
2405                } else {
2406                    [second, nanosecond]
2407                }
2408            });
2409        UnixMicroseconds::rfrom(
2410            (second * t::MICROS_PER_SECOND)
2411                + (nanosecond.div_ceil(t::NANOS_PER_MICRO)),
2412        )
2413    }
2414
2415    #[inline]
2416    pub(crate) fn as_nanosecond_ranged(self) -> UnixNanoseconds {
2417        let second = NoUnits128::rfrom(self.as_second_ranged());
2418        let nanosecond = NoUnits128::rfrom(self.subsec_nanosecond_ranged());
2419        // The minimum value of a timestamp has the fractional nanosecond set
2420        // to 0, but otherwise its minimum value is -999_999_999. So to avoid
2421        // a case where we return a ranged integer with a minimum value less
2422        // than the actual minimum, we clamp the fractional part to 0 when the
2423        // second value is the minimum.
2424        let [second, nanosecond] = NoUnits128::vary_many(
2425            [second, nanosecond],
2426            |[second, nanosecond]| {
2427                if second == UnixSeconds::MIN_SELF && nanosecond < C(0) {
2428                    [second, C(0).rinto()]
2429                } else {
2430                    [second, nanosecond]
2431                }
2432            },
2433        );
2434        UnixNanoseconds::rfrom(second * t::NANOS_PER_SECOND + nanosecond)
2435    }
2436
2437    #[inline]
2438    fn subsec_millisecond_ranged(self) -> t::FractionalMillisecond {
2439        let millis =
2440            self.subsec_nanosecond_ranged().div_ceil(t::NANOS_PER_MILLI);
2441        t::FractionalMillisecond::rfrom(millis)
2442    }
2443
2444    #[inline]
2445    fn subsec_microsecond_ranged(self) -> t::FractionalMicrosecond {
2446        let micros =
2447            self.subsec_nanosecond_ranged().div_ceil(t::NANOS_PER_MICRO);
2448        t::FractionalMicrosecond::rfrom(micros)
2449    }
2450
2451    #[inline]
2452    pub(crate) fn subsec_nanosecond_ranged(self) -> FractionalNanosecond {
2453        self.nanosecond
2454    }
2455}
2456
2457impl Default for Timestamp {
2458    #[inline]
2459    fn default() -> Timestamp {
2460        Timestamp::UNIX_EPOCH
2461    }
2462}
2463
2464/// Converts a `Timestamp` datetime into a human readable datetime string.
2465///
2466/// (This `Debug` representation currently emits the same string as the
2467/// `Display` representation, but this is not a guarantee.)
2468///
2469/// Options currently supported:
2470///
2471/// * [`std::fmt::Formatter::precision`] can be set to control the precision
2472/// of the fractional second component.
2473///
2474/// # Example
2475///
2476/// ```
2477/// use jiff::Timestamp;
2478///
2479/// let ts = Timestamp::new(1_123_456_789, 123_000_000)?;
2480/// assert_eq!(
2481///     format!("{ts:.6?}"),
2482///     "2005-08-07T23:19:49.123000Z",
2483/// );
2484/// // Precision values greater than 9 are clamped to 9.
2485/// assert_eq!(
2486///     format!("{ts:.300?}"),
2487///     "2005-08-07T23:19:49.123000000Z",
2488/// );
2489/// // A precision of 0 implies the entire fractional
2490/// // component is always truncated.
2491/// assert_eq!(
2492///     format!("{ts:.0?}"),
2493///     "2005-08-07T23:19:49Z",
2494/// );
2495///
2496/// # Ok::<(), Box<dyn std::error::Error>>(())
2497/// ```
2498impl core::fmt::Debug for Timestamp {
2499    #[inline]
2500    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2501        core::fmt::Display::fmt(self, f)
2502    }
2503}
2504
2505/// Converts a `Timestamp` datetime into a RFC 3339 compliant string.
2506///
2507/// Since a `Timestamp` never has an offset associated with it and is always
2508/// in UTC, the string emitted by this trait implementation uses `Z` for "Zulu"
2509/// time. The significance of Zulu time is prescribed by RFC 9557 and means
2510/// that "the time in UTC is known, but the offset to local time is unknown."
2511/// If you need to emit an RFC 3339 compliant string with a specific offset,
2512/// then use [`Timestamp::display_with_offset`].
2513///
2514/// # Formatting options supported
2515///
2516/// * [`std::fmt::Formatter::precision`] can be set to control the precision
2517/// of the fractional second component. When not set, the minimum precision
2518/// required to losslessly render the value is used.
2519///
2520/// # Example
2521///
2522/// This shows the default rendering:
2523///
2524/// ```
2525/// use jiff::Timestamp;
2526///
2527/// // No fractional seconds.
2528/// let ts = Timestamp::from_second(1_123_456_789)?;
2529/// assert_eq!(format!("{ts}"), "2005-08-07T23:19:49Z");
2530///
2531/// // With fractional seconds.
2532/// let ts = Timestamp::new(1_123_456_789, 123_000_000)?;
2533/// assert_eq!(format!("{ts}"), "2005-08-07T23:19:49.123Z");
2534///
2535/// # Ok::<(), Box<dyn std::error::Error>>(())
2536/// ```
2537///
2538/// # Example: setting the precision
2539///
2540/// ```
2541/// use jiff::Timestamp;
2542///
2543/// let ts = Timestamp::new(1_123_456_789, 123_000_000)?;
2544/// assert_eq!(
2545///     format!("{ts:.6}"),
2546///     "2005-08-07T23:19:49.123000Z",
2547/// );
2548/// // Precision values greater than 9 are clamped to 9.
2549/// assert_eq!(
2550///     format!("{ts:.300}"),
2551///     "2005-08-07T23:19:49.123000000Z",
2552/// );
2553/// // A precision of 0 implies the entire fractional
2554/// // component is always truncated.
2555/// assert_eq!(
2556///     format!("{ts:.0}"),
2557///     "2005-08-07T23:19:49Z",
2558/// );
2559///
2560/// # Ok::<(), Box<dyn std::error::Error>>(())
2561/// ```
2562impl core::fmt::Display for Timestamp {
2563    #[inline]
2564    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2565        use crate::fmt::StdFmtWrite;
2566
2567        let precision =
2568            f.precision().map(|p| u8::try_from(p).unwrap_or(u8::MAX));
2569        temporal::DateTimePrinter::new()
2570            .precision(precision)
2571            .print_timestamp(self, StdFmtWrite(f))
2572            .map_err(|_| core::fmt::Error)
2573    }
2574}
2575
2576impl core::str::FromStr for Timestamp {
2577    type Err = Error;
2578
2579    #[inline]
2580    fn from_str(string: &str) -> Result<Timestamp, Error> {
2581        DEFAULT_DATETIME_PARSER.parse_timestamp(string)
2582    }
2583}
2584
2585impl Eq for Timestamp {}
2586
2587impl PartialEq for Timestamp {
2588    #[inline]
2589    fn eq(&self, rhs: &Timestamp) -> bool {
2590        self.as_second_ranged().get() == rhs.as_second_ranged().get()
2591            && self.subsec_nanosecond_ranged().get()
2592                == rhs.subsec_nanosecond_ranged().get()
2593    }
2594}
2595
2596impl Ord for Timestamp {
2597    #[inline]
2598    fn cmp(&self, rhs: &Timestamp) -> core::cmp::Ordering {
2599        (self.as_second_ranged().get(), self.subsec_nanosecond_ranged().get())
2600            .cmp(&(
2601                rhs.as_second_ranged().get(),
2602                rhs.subsec_nanosecond_ranged().get(),
2603            ))
2604    }
2605}
2606
2607impl PartialOrd for Timestamp {
2608    #[inline]
2609    fn partial_cmp(&self, rhs: &Timestamp) -> Option<core::cmp::Ordering> {
2610        Some(self.cmp(rhs))
2611    }
2612}
2613
2614impl core::hash::Hash for Timestamp {
2615    #[inline]
2616    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
2617        self.as_second_ranged().get().hash(state);
2618        self.subsec_nanosecond_ranged().get().hash(state);
2619    }
2620}
2621
2622/// Adds a span of time to a timestamp.
2623///
2624/// This uses checked arithmetic and panics when it fails. To handle arithmetic
2625/// without panics, use [`Timestamp::checked_add`]. Note that the failure
2626/// condition includes overflow and using a `Span` with non-zero units greater
2627/// than hours.
2628impl core::ops::Add<Span> for Timestamp {
2629    type Output = Timestamp;
2630
2631    #[inline]
2632    fn add(self, rhs: Span) -> Timestamp {
2633        self.checked_add_span(rhs).expect("adding span to timestamp failed")
2634    }
2635}
2636
2637/// Adds a span of time to a timestamp in place.
2638///
2639/// This uses checked arithmetic and panics when it fails. To handle arithmetic
2640/// without panics, use [`Timestamp::checked_add`]. Note that the failure
2641/// condition includes overflow and using a `Span` with non-zero units greater
2642/// than hours.
2643impl core::ops::AddAssign<Span> for Timestamp {
2644    #[inline]
2645    fn add_assign(&mut self, rhs: Span) {
2646        *self = *self + rhs
2647    }
2648}
2649
2650/// Subtracts a span of time from a timestamp.
2651///
2652/// This uses checked arithmetic and panics when it fails. To handle arithmetic
2653/// without panics, use [`Timestamp::checked_sub`]. Note that the failure
2654/// condition includes overflow and using a `Span` with non-zero units greater
2655/// than hours.
2656impl core::ops::Sub<Span> for Timestamp {
2657    type Output = Timestamp;
2658
2659    #[inline]
2660    fn sub(self, rhs: Span) -> Timestamp {
2661        self.checked_add_span(rhs.negate())
2662            .expect("subtracting span from timestamp failed")
2663    }
2664}
2665
2666/// Subtracts a span of time from a timestamp in place.
2667///
2668/// This uses checked arithmetic and panics when it fails. To handle arithmetic
2669/// without panics, use [`Timestamp::checked_sub`]. Note that the failure
2670/// condition includes overflow and using a `Span` with non-zero units greater
2671/// than hours.
2672impl core::ops::SubAssign<Span> for Timestamp {
2673    #[inline]
2674    fn sub_assign(&mut self, rhs: Span) {
2675        *self = *self - rhs
2676    }
2677}
2678
2679/// Computes the span of time between two timestamps.
2680///
2681/// This will return a negative span when the timestamp being subtracted is
2682/// greater.
2683///
2684/// Since this uses the default configuration for calculating a span between
2685/// two timestamps (no rounding and largest units is seconds), this will never
2686/// panic or fail in any way.
2687///
2688/// To configure the largest unit or enable rounding, use [`Timestamp::since`].
2689impl core::ops::Sub for Timestamp {
2690    type Output = Span;
2691
2692    #[inline]
2693    fn sub(self, rhs: Timestamp) -> Span {
2694        self.since(rhs).expect("since never fails when given Timestamp")
2695    }
2696}
2697
2698/// Adds a signed duration of time to a timestamp.
2699///
2700/// This uses checked arithmetic and panics on overflow. To handle overflow
2701/// without panics, use [`Timestamp::checked_add`].
2702impl core::ops::Add<SignedDuration> for Timestamp {
2703    type Output = Timestamp;
2704
2705    #[inline]
2706    fn add(self, rhs: SignedDuration) -> Timestamp {
2707        self.checked_add_duration(rhs)
2708            .expect("adding signed duration to timestamp overflowed")
2709    }
2710}
2711
2712/// Adds a signed duration of time to a timestamp in place.
2713///
2714/// This uses checked arithmetic and panics on overflow. To handle overflow
2715/// without panics, use [`Timestamp::checked_add`].
2716impl core::ops::AddAssign<SignedDuration> for Timestamp {
2717    #[inline]
2718    fn add_assign(&mut self, rhs: SignedDuration) {
2719        *self = *self + rhs
2720    }
2721}
2722
2723/// Subtracts a signed duration of time from a timestamp.
2724///
2725/// This uses checked arithmetic and panics on overflow. To handle overflow
2726/// without panics, use [`Timestamp::checked_sub`].
2727impl core::ops::Sub<SignedDuration> for Timestamp {
2728    type Output = Timestamp;
2729
2730    #[inline]
2731    fn sub(self, rhs: SignedDuration) -> Timestamp {
2732        let rhs = rhs
2733            .checked_neg()
2734            .expect("signed duration negation resulted in overflow");
2735        self.checked_add_duration(rhs)
2736            .expect("subtracting signed duration from timestamp overflowed")
2737    }
2738}
2739
2740/// Subtracts a signed duration of time from a timestamp in place.
2741///
2742/// This uses checked arithmetic and panics on overflow. To handle overflow
2743/// without panics, use [`Timestamp::checked_sub`].
2744impl core::ops::SubAssign<SignedDuration> for Timestamp {
2745    #[inline]
2746    fn sub_assign(&mut self, rhs: SignedDuration) {
2747        *self = *self - rhs
2748    }
2749}
2750
2751/// Adds an unsigned duration of time to a timestamp.
2752///
2753/// This uses checked arithmetic and panics on overflow. To handle overflow
2754/// without panics, use [`Timestamp::checked_add`].
2755impl core::ops::Add<UnsignedDuration> for Timestamp {
2756    type Output = Timestamp;
2757
2758    #[inline]
2759    fn add(self, rhs: UnsignedDuration) -> Timestamp {
2760        self.checked_add(rhs)
2761            .expect("adding unsigned duration to timestamp overflowed")
2762    }
2763}
2764
2765/// Adds an unsigned duration of time to a timestamp in place.
2766///
2767/// This uses checked arithmetic and panics on overflow. To handle overflow
2768/// without panics, use [`Timestamp::checked_add`].
2769impl core::ops::AddAssign<UnsignedDuration> for Timestamp {
2770    #[inline]
2771    fn add_assign(&mut self, rhs: UnsignedDuration) {
2772        *self = *self + rhs
2773    }
2774}
2775
2776/// Subtracts an unsigned duration of time from a timestamp.
2777///
2778/// This uses checked arithmetic and panics on overflow. To handle overflow
2779/// without panics, use [`Timestamp::checked_sub`].
2780impl core::ops::Sub<UnsignedDuration> for Timestamp {
2781    type Output = Timestamp;
2782
2783    #[inline]
2784    fn sub(self, rhs: UnsignedDuration) -> Timestamp {
2785        self.checked_sub(rhs)
2786            .expect("subtracting unsigned duration from timestamp overflowed")
2787    }
2788}
2789
2790/// Subtracts an unsigned duration of time from a timestamp in place.
2791///
2792/// This uses checked arithmetic and panics on overflow. To handle overflow
2793/// without panics, use [`Timestamp::checked_sub`].
2794impl core::ops::SubAssign<UnsignedDuration> for Timestamp {
2795    #[inline]
2796    fn sub_assign(&mut self, rhs: UnsignedDuration) {
2797        *self = *self - rhs
2798    }
2799}
2800
2801impl From<Zoned> for Timestamp {
2802    #[inline]
2803    fn from(zdt: Zoned) -> Timestamp {
2804        zdt.timestamp()
2805    }
2806}
2807
2808impl<'a> From<&'a Zoned> for Timestamp {
2809    #[inline]
2810    fn from(zdt: &'a Zoned) -> Timestamp {
2811        zdt.timestamp()
2812    }
2813}
2814
2815#[cfg(feature = "std")]
2816impl From<Timestamp> for std::time::SystemTime {
2817    #[inline]
2818    fn from(time: Timestamp) -> std::time::SystemTime {
2819        let unix_epoch = std::time::SystemTime::UNIX_EPOCH;
2820        let sdur = time.as_duration();
2821        let dur = sdur.unsigned_abs();
2822        // These are guaranteed to succeed because we assume that SystemTime
2823        // uses at least 64 bits for the time, and our durations are capped via
2824        // the range on UnixSeconds.
2825        if sdur.is_negative() {
2826            unix_epoch.checked_sub(dur).expect("duration too big (negative)")
2827        } else {
2828            unix_epoch.checked_add(dur).expect("duration too big (positive)")
2829        }
2830    }
2831}
2832
2833#[cfg(feature = "std")]
2834impl TryFrom<std::time::SystemTime> for Timestamp {
2835    type Error = Error;
2836
2837    #[inline]
2838    fn try_from(
2839        system_time: std::time::SystemTime,
2840    ) -> Result<Timestamp, Error> {
2841        let unix_epoch = std::time::SystemTime::UNIX_EPOCH;
2842        let dur = SignedDuration::system_until(unix_epoch, system_time)?;
2843        Timestamp::from_duration(dur)
2844    }
2845}
2846
2847#[cfg(feature = "serde")]
2848impl serde_core::Serialize for Timestamp {
2849    #[inline]
2850    fn serialize<S: serde_core::Serializer>(
2851        &self,
2852        serializer: S,
2853    ) -> Result<S::Ok, S::Error> {
2854        serializer.collect_str(self)
2855    }
2856}
2857
2858#[cfg(feature = "serde")]
2859impl<'de> serde_core::Deserialize<'de> for Timestamp {
2860    #[inline]
2861    fn deserialize<D: serde_core::Deserializer<'de>>(
2862        deserializer: D,
2863    ) -> Result<Timestamp, D::Error> {
2864        use serde_core::de;
2865
2866        struct TimestampVisitor;
2867
2868        impl<'de> de::Visitor<'de> for TimestampVisitor {
2869            type Value = Timestamp;
2870
2871            fn expecting(
2872                &self,
2873                f: &mut core::fmt::Formatter,
2874            ) -> core::fmt::Result {
2875                f.write_str("a timestamp string")
2876            }
2877
2878            #[inline]
2879            fn visit_bytes<E: de::Error>(
2880                self,
2881                value: &[u8],
2882            ) -> Result<Timestamp, E> {
2883                DEFAULT_DATETIME_PARSER
2884                    .parse_timestamp(value)
2885                    .map_err(de::Error::custom)
2886            }
2887
2888            #[inline]
2889            fn visit_str<E: de::Error>(
2890                self,
2891                value: &str,
2892            ) -> Result<Timestamp, E> {
2893                self.visit_bytes(value.as_bytes())
2894            }
2895        }
2896
2897        deserializer.deserialize_str(TimestampVisitor)
2898    }
2899}
2900
2901#[cfg(test)]
2902impl quickcheck::Arbitrary for Timestamp {
2903    fn arbitrary(g: &mut quickcheck::Gen) -> Timestamp {
2904        use quickcheck::Arbitrary;
2905
2906        let seconds: UnixSeconds = Arbitrary::arbitrary(g);
2907        let mut nanoseconds: FractionalNanosecond = Arbitrary::arbitrary(g);
2908        // nanoseconds must be zero for the minimum second value,
2909        // so just clamp it to 0.
2910        if seconds == UnixSeconds::MIN_SELF && nanoseconds < C(0) {
2911            nanoseconds = C(0).rinto();
2912        }
2913        Timestamp::new_ranged(seconds, nanoseconds).unwrap_or_default()
2914    }
2915
2916    fn shrink(&self) -> alloc::boxed::Box<dyn Iterator<Item = Self>> {
2917        let second = self.as_second_ranged();
2918        let nanosecond = self.subsec_nanosecond_ranged();
2919        alloc::boxed::Box::new((second, nanosecond).shrink().filter_map(
2920            |(second, nanosecond)| {
2921                if second == UnixSeconds::MIN_SELF && nanosecond > C(0) {
2922                    None
2923                } else {
2924                    Timestamp::new_ranged(second, nanosecond).ok()
2925                }
2926            },
2927        ))
2928    }
2929}
2930
2931/// A type for formatting a [`Timestamp`] with a specific offset.
2932///
2933/// This type is created by the [`Timestamp::display_with_offset`] method.
2934///
2935/// Like the [`std::fmt::Display`] trait implementation for `Timestamp`, this
2936/// always emits an RFC 3339 compliant string. Unlike `Timestamp`'s `Display`
2937/// trait implementation, which always uses `Z` or "Zulu" time, this always
2938/// uses an offset.
2939///
2940/// # Formatting options supported
2941///
2942/// * [`std::fmt::Formatter::precision`] can be set to control the precision
2943/// of the fractional second component.
2944///
2945/// # Example
2946///
2947/// ```
2948/// use jiff::{tz, Timestamp};
2949///
2950/// let offset = tz::offset(-5);
2951/// let ts = Timestamp::new(1_123_456_789, 123_000_000)?;
2952/// assert_eq!(
2953///     format!("{ts:.6}", ts = ts.display_with_offset(offset)),
2954///     "2005-08-07T18:19:49.123000-05:00",
2955/// );
2956/// // Precision values greater than 9 are clamped to 9.
2957/// assert_eq!(
2958///     format!("{ts:.300}", ts = ts.display_with_offset(offset)),
2959///     "2005-08-07T18:19:49.123000000-05:00",
2960/// );
2961/// // A precision of 0 implies the entire fractional
2962/// // component is always truncated.
2963/// assert_eq!(
2964///     format!("{ts:.0}", ts = ts.display_with_offset(tz::Offset::UTC)),
2965///     "2005-08-07T23:19:49+00:00",
2966/// );
2967///
2968/// # Ok::<(), Box<dyn std::error::Error>>(())
2969/// ```
2970#[derive(Clone, Copy, Debug)]
2971pub struct TimestampDisplayWithOffset {
2972    timestamp: Timestamp,
2973    offset: Offset,
2974}
2975
2976impl core::fmt::Display for TimestampDisplayWithOffset {
2977    #[inline]
2978    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2979        use crate::fmt::StdFmtWrite;
2980
2981        let precision =
2982            f.precision().map(|p| u8::try_from(p).unwrap_or(u8::MAX));
2983        temporal::DateTimePrinter::new()
2984            .precision(precision)
2985            .print_timestamp_with_offset(
2986                &self.timestamp,
2987                self.offset,
2988                StdFmtWrite(f),
2989            )
2990            .map_err(|_| core::fmt::Error)
2991    }
2992}
2993
2994/// An iterator over periodic timestamps, created by [`Timestamp::series`].
2995///
2996/// It is exhausted when the next value would exceed the limits of a [`Span`]
2997/// or [`Timestamp`] value.
2998///
2999/// This iterator is created by [`Timestamp::series`].
3000#[derive(Clone, Debug)]
3001pub struct TimestampSeries {
3002    ts: Timestamp,
3003    duration: Option<SignedDuration>,
3004}
3005
3006impl TimestampSeries {
3007    #[inline]
3008    fn new(ts: Timestamp, period: Span) -> TimestampSeries {
3009        let duration = SignedDuration::try_from(period).ok();
3010        TimestampSeries { ts, duration }
3011    }
3012}
3013
3014impl Iterator for TimestampSeries {
3015    type Item = Timestamp;
3016
3017    #[inline]
3018    fn next(&mut self) -> Option<Timestamp> {
3019        let duration = self.duration?;
3020        let this = self.ts;
3021        self.ts = self.ts.checked_add_duration(duration).ok()?;
3022        Some(this)
3023    }
3024}
3025
3026impl core::iter::FusedIterator for TimestampSeries {}
3027
3028/// Options for [`Timestamp::checked_add`] and [`Timestamp::checked_sub`].
3029///
3030/// This type provides a way to ergonomically add one of a few different
3031/// duration types to a [`Timestamp`].
3032///
3033/// The main way to construct values of this type is with its `From` trait
3034/// implementations:
3035///
3036/// * `From<Span> for TimestampArithmetic` adds (or subtracts) the given span
3037/// to the receiver timestamp.
3038/// * `From<SignedDuration> for TimestampArithmetic` adds (or subtracts)
3039/// the given signed duration to the receiver timestamp.
3040/// * `From<std::time::Duration> for TimestampArithmetic` adds (or subtracts)
3041/// the given unsigned duration to the receiver timestamp.
3042///
3043/// # Example
3044///
3045/// ```
3046/// use std::time::Duration;
3047///
3048/// use jiff::{SignedDuration, Timestamp, ToSpan};
3049///
3050/// let ts: Timestamp = "2024-02-28T00:00:00Z".parse()?;
3051/// assert_eq!(
3052///     ts.checked_add(48.hours())?,
3053///     "2024-03-01T00:00:00Z".parse()?,
3054/// );
3055/// assert_eq!(
3056///     ts.checked_add(SignedDuration::from_hours(48))?,
3057///     "2024-03-01T00:00:00Z".parse()?,
3058/// );
3059/// assert_eq!(
3060///     ts.checked_add(Duration::from_secs(48 * 60 * 60))?,
3061///     "2024-03-01T00:00:00Z".parse()?,
3062/// );
3063///
3064/// # Ok::<(), Box<dyn std::error::Error>>(())
3065/// ```
3066#[derive(Clone, Copy, Debug)]
3067pub struct TimestampArithmetic {
3068    duration: Duration,
3069}
3070
3071impl TimestampArithmetic {
3072    #[inline]
3073    fn checked_add(self, ts: Timestamp) -> Result<Timestamp, Error> {
3074        match self.duration.to_signed()? {
3075            SDuration::Span(span) => ts.checked_add_span(span),
3076            SDuration::Absolute(sdur) => ts.checked_add_duration(sdur),
3077        }
3078    }
3079
3080    #[inline]
3081    fn saturating_add(self, ts: Timestamp) -> Result<Timestamp, Error> {
3082        let Ok(signed) = self.duration.to_signed() else {
3083            return Ok(Timestamp::MAX);
3084        };
3085        let result = match signed {
3086            SDuration::Span(span) => {
3087                if let Some(err) = span.smallest_non_time_non_zero_unit_error()
3088                {
3089                    return Err(err);
3090                }
3091                ts.checked_add_span(span)
3092            }
3093            SDuration::Absolute(sdur) => ts.checked_add_duration(sdur),
3094        };
3095        Ok(result.unwrap_or_else(|_| {
3096            if self.is_negative() {
3097                Timestamp::MIN
3098            } else {
3099                Timestamp::MAX
3100            }
3101        }))
3102    }
3103
3104    #[inline]
3105    fn checked_neg(self) -> Result<TimestampArithmetic, Error> {
3106        let duration = self.duration.checked_neg()?;
3107        Ok(TimestampArithmetic { duration })
3108    }
3109
3110    #[inline]
3111    fn is_negative(&self) -> bool {
3112        self.duration.is_negative()
3113    }
3114}
3115
3116impl From<Span> for TimestampArithmetic {
3117    fn from(span: Span) -> TimestampArithmetic {
3118        let duration = Duration::from(span);
3119        TimestampArithmetic { duration }
3120    }
3121}
3122
3123impl From<SignedDuration> for TimestampArithmetic {
3124    fn from(sdur: SignedDuration) -> TimestampArithmetic {
3125        let duration = Duration::from(sdur);
3126        TimestampArithmetic { duration }
3127    }
3128}
3129
3130impl From<UnsignedDuration> for TimestampArithmetic {
3131    fn from(udur: UnsignedDuration) -> TimestampArithmetic {
3132        let duration = Duration::from(udur);
3133        TimestampArithmetic { duration }
3134    }
3135}
3136
3137impl<'a> From<&'a Span> for TimestampArithmetic {
3138    fn from(span: &'a Span) -> TimestampArithmetic {
3139        TimestampArithmetic::from(*span)
3140    }
3141}
3142
3143impl<'a> From<&'a SignedDuration> for TimestampArithmetic {
3144    fn from(sdur: &'a SignedDuration) -> TimestampArithmetic {
3145        TimestampArithmetic::from(*sdur)
3146    }
3147}
3148
3149impl<'a> From<&'a UnsignedDuration> for TimestampArithmetic {
3150    fn from(udur: &'a UnsignedDuration) -> TimestampArithmetic {
3151        TimestampArithmetic::from(*udur)
3152    }
3153}
3154
3155/// Options for [`Timestamp::since`] and [`Timestamp::until`].
3156///
3157/// This type provides a way to configure the calculation of
3158/// spans between two [`Timestamp`] values. In particular, both
3159/// `Timestamp::since` and `Timestamp::until` accept anything that implements
3160/// `Into<TimestampDifference>`. There are a few key trait implementations that
3161/// make this convenient:
3162///
3163/// * `From<Timestamp> for TimestampDifference` will construct a
3164/// configuration consisting of just the timestamp. So for example,
3165/// `timestamp1.until(timestamp2)` will return the span from `timestamp1` to
3166/// `timestamp2`.
3167/// * `From<Zoned> for TimestampDifference` will construct a configuration
3168/// consisting of the timestamp from the given zoned datetime. So for example,
3169/// `timestamp.since(zoned)` returns the span from `zoned.to_timestamp()` to
3170/// `timestamp`.
3171/// * `From<(Unit, Timestamp)>` is a convenient way to specify the largest
3172/// units that should be present on the span returned. By default, the largest
3173/// units are seconds. Using this trait implementation is equivalent to
3174/// `TimestampDifference::new(timestamp).largest(unit)`.
3175/// * `From<(Unit, Zoned)>` is like the one above, but with the time from
3176/// the given zoned datetime.
3177///
3178/// One can also provide a `TimestampDifference` value directly. Doing so
3179/// is necessary to use the rounding features of calculating a span. For
3180/// example, setting the smallest unit (defaults to [`Unit::Nanosecond`]), the
3181/// rounding mode (defaults to [`RoundMode::Trunc`]) and the rounding increment
3182/// (defaults to `1`). The defaults are selected such that no rounding occurs.
3183///
3184/// Rounding a span as part of calculating it is provided as a convenience.
3185/// Callers may choose to round the span as a distinct step via
3186/// [`Span::round`].
3187///
3188/// # Example
3189///
3190/// This example shows how to round a span between two timestamps to the
3191/// nearest half-hour, with ties breaking away from zero.
3192///
3193/// ```
3194/// use jiff::{RoundMode, Timestamp, TimestampDifference, ToSpan, Unit};
3195///
3196/// let ts1 = "2024-03-15 08:14:00.123456789Z".parse::<Timestamp>()?;
3197/// let ts2 = "2024-03-22 15:00Z".parse::<Timestamp>()?;
3198/// let span = ts1.until(
3199///     TimestampDifference::new(ts2)
3200///         .smallest(Unit::Minute)
3201///         .largest(Unit::Hour)
3202///         .mode(RoundMode::HalfExpand)
3203///         .increment(30),
3204/// )?;
3205/// assert_eq!(format!("{span:#}"), "175h");
3206///
3207/// // One less minute, and because of the HalfExpand mode, the span would
3208/// // get rounded down.
3209/// let ts2 = "2024-03-22 14:59Z".parse::<Timestamp>()?;
3210/// let span = ts1.until(
3211///     TimestampDifference::new(ts2)
3212///         .smallest(Unit::Minute)
3213///         .largest(Unit::Hour)
3214///         .mode(RoundMode::HalfExpand)
3215///         .increment(30),
3216/// )?;
3217/// assert_eq!(span, 174.hours().minutes(30).fieldwise());
3218///
3219/// # Ok::<(), Box<dyn std::error::Error>>(())
3220/// ```
3221#[derive(Clone, Copy, Debug)]
3222pub struct TimestampDifference {
3223    timestamp: Timestamp,
3224    round: SpanRound<'static>,
3225}
3226
3227impl TimestampDifference {
3228    /// Create a new default configuration for computing the span between
3229    /// the given timestamp and some other time (specified as the receiver in
3230    /// [`Timestamp::since`] or [`Timestamp::until`]).
3231    #[inline]
3232    pub fn new(timestamp: Timestamp) -> TimestampDifference {
3233        // We use truncation rounding by default since it seems that's
3234        // what is generally expected when computing the difference between
3235        // datetimes.
3236        //
3237        // See: https://github.com/tc39/proposal-temporal/issues/1122
3238        let round = SpanRound::new().mode(RoundMode::Trunc);
3239        TimestampDifference { timestamp, round }
3240    }
3241
3242    /// Set the smallest units allowed in the span returned.
3243    ///
3244    /// # Errors
3245    ///
3246    /// The smallest units must be no greater than the largest units. If this
3247    /// is violated, then computing a span with this configuration will result
3248    /// in an error.
3249    ///
3250    /// # Example
3251    ///
3252    /// This shows how to round a span between two timestamps to units no less
3253    /// than seconds.
3254    ///
3255    /// ```
3256    /// use jiff::{RoundMode, Timestamp, TimestampDifference, ToSpan, Unit};
3257    ///
3258    /// let ts1 = "2024-03-15 08:14:02.5001Z".parse::<Timestamp>()?;
3259    /// let ts2 = "2024-03-15T08:16:03.0001Z".parse::<Timestamp>()?;
3260    /// let span = ts1.until(
3261    ///     TimestampDifference::new(ts2)
3262    ///         .smallest(Unit::Second)
3263    ///         .mode(RoundMode::HalfExpand),
3264    /// )?;
3265    /// assert_eq!(span, 121.seconds().fieldwise());
3266    ///
3267    /// // Because of the rounding mode, a small less-than-1-second increase in
3268    /// // the first timestamp can change the result of rounding.
3269    /// let ts1 = "2024-03-15 08:14:02.5002Z".parse::<Timestamp>()?;
3270    /// let span = ts1.until(
3271    ///     TimestampDifference::new(ts2)
3272    ///         .smallest(Unit::Second)
3273    ///         .mode(RoundMode::HalfExpand),
3274    /// )?;
3275    /// assert_eq!(span, 120.seconds().fieldwise());
3276    ///
3277    /// # Ok::<(), Box<dyn std::error::Error>>(())
3278    /// ```
3279    #[inline]
3280    pub fn smallest(self, unit: Unit) -> TimestampDifference {
3281        TimestampDifference { round: self.round.smallest(unit), ..self }
3282    }
3283
3284    /// Set the largest units allowed in the span returned.
3285    ///
3286    /// When a largest unit is not specified, computing a span between
3287    /// timestamps behaves as if it were set to [`Unit::Second`]. Unless
3288    /// [`TimestampDifference::smallest`] is bigger than `Unit::Second`, then
3289    /// the largest unit is set to the smallest unit.
3290    ///
3291    /// # Errors
3292    ///
3293    /// The largest units, when set, must be at least as big as the smallest
3294    /// units (which defaults to [`Unit::Nanosecond`]). If this is violated,
3295    /// then computing a span with this configuration will result in an error.
3296    ///
3297    /// # Example
3298    ///
3299    /// This shows how to round a span between two timestamps to units no
3300    /// bigger than seconds.
3301    ///
3302    /// ```
3303    /// use jiff::{Timestamp, TimestampDifference, ToSpan, Unit};
3304    ///
3305    /// let ts1 = "2024-03-15 08:14Z".parse::<Timestamp>()?;
3306    /// let ts2 = "2030-11-22 08:30Z".parse::<Timestamp>()?;
3307    /// let span = ts1.until(
3308    ///     TimestampDifference::new(ts2).largest(Unit::Second),
3309    /// )?;
3310    /// assert_eq!(format!("{span:#}"), "211076160s");
3311    ///
3312    /// # Ok::<(), Box<dyn std::error::Error>>(())
3313    /// ```
3314    #[inline]
3315    pub fn largest(self, unit: Unit) -> TimestampDifference {
3316        TimestampDifference { round: self.round.largest(unit), ..self }
3317    }
3318
3319    /// Set the rounding mode.
3320    ///
3321    /// This defaults to [`RoundMode::Trunc`] since it's plausible that
3322    /// rounding "up" in the context of computing the span between
3323    /// two timestamps could be surprising in a number of cases. The
3324    /// [`RoundMode::HalfExpand`] mode corresponds to typical rounding you
3325    /// might have learned about in school. But a variety of other rounding
3326    /// modes exist.
3327    ///
3328    /// # Example
3329    ///
3330    /// This shows how to always round "up" towards positive infinity.
3331    ///
3332    /// ```
3333    /// use jiff::{RoundMode, Timestamp, TimestampDifference, ToSpan, Unit};
3334    ///
3335    /// let ts1 = "2024-03-15 08:10Z".parse::<Timestamp>()?;
3336    /// let ts2 = "2024-03-15 08:11Z".parse::<Timestamp>()?;
3337    /// let span = ts1.until(
3338    ///     TimestampDifference::new(ts2)
3339    ///         .smallest(Unit::Hour)
3340    ///         .mode(RoundMode::Ceil),
3341    /// )?;
3342    /// // Only one minute elapsed, but we asked to always round up!
3343    /// assert_eq!(span, 1.hour().fieldwise());
3344    ///
3345    /// // Since `Ceil` always rounds toward positive infinity, the behavior
3346    /// // flips for a negative span.
3347    /// let span = ts1.since(
3348    ///     TimestampDifference::new(ts2)
3349    ///         .smallest(Unit::Hour)
3350    ///         .mode(RoundMode::Ceil),
3351    /// )?;
3352    /// assert_eq!(span, 0.hour().fieldwise());
3353    ///
3354    /// # Ok::<(), Box<dyn std::error::Error>>(())
3355    /// ```
3356    #[inline]
3357    pub fn mode(self, mode: RoundMode) -> TimestampDifference {
3358        TimestampDifference { round: self.round.mode(mode), ..self }
3359    }
3360
3361    /// Set the rounding increment for the smallest unit.
3362    ///
3363    /// The default value is `1`. Other values permit rounding the smallest
3364    /// unit to the nearest integer increment specified. For example, if the
3365    /// smallest unit is set to [`Unit::Minute`], then a rounding increment of
3366    /// `30` would result in rounding in increments of a half hour. That is,
3367    /// the only minute value that could result would be `0` or `30`.
3368    ///
3369    /// # Errors
3370    ///
3371    /// The rounding increment must divide evenly into the next highest unit
3372    /// after the smallest unit configured (and must not be equivalent to it).
3373    /// For example, if the smallest unit is [`Unit::Nanosecond`], then *some*
3374    /// of the valid values for the rounding increment are `1`, `2`, `4`, `5`,
3375    /// `100` and `500`. Namely, any integer that divides evenly into `1,000`
3376    /// nanoseconds since there are `1,000` nanoseconds in the next highest
3377    /// unit (microseconds).
3378    ///
3379    /// The error will occur when computing the span, and not when setting
3380    /// the increment here.
3381    ///
3382    /// # Example
3383    ///
3384    /// This shows how to round the span between two timestamps to the nearest
3385    /// 5 minute increment.
3386    ///
3387    /// ```
3388    /// use jiff::{RoundMode, Timestamp, TimestampDifference, ToSpan, Unit};
3389    ///
3390    /// let ts1 = "2024-03-15 08:19Z".parse::<Timestamp>()?;
3391    /// let ts2 = "2024-03-15 12:52Z".parse::<Timestamp>()?;
3392    /// let span = ts1.until(
3393    ///     TimestampDifference::new(ts2)
3394    ///         .smallest(Unit::Minute)
3395    ///         .increment(5)
3396    ///         .mode(RoundMode::HalfExpand),
3397    /// )?;
3398    /// assert_eq!(span.to_string(), "PT275M");
3399    ///
3400    /// # Ok::<(), Box<dyn std::error::Error>>(())
3401    /// ```
3402    #[inline]
3403    pub fn increment(self, increment: i64) -> TimestampDifference {
3404        TimestampDifference { round: self.round.increment(increment), ..self }
3405    }
3406
3407    /// Returns true if and only if this configuration could change the span
3408    /// via rounding.
3409    #[inline]
3410    fn rounding_may_change_span(&self) -> bool {
3411        self.round.rounding_may_change_span_ignore_largest()
3412    }
3413
3414    /// Returns the span of time from `ts1` to the timestamp in this
3415    /// configuration. The biggest units allowed are determined by the
3416    /// `smallest` and `largest` settings, but defaults to `Unit::Second`.
3417    #[inline]
3418    fn until_with_largest_unit(&self, t1: Timestamp) -> Result<Span, Error> {
3419        let t2 = self.timestamp;
3420        let largest = self
3421            .round
3422            .get_largest()
3423            .unwrap_or_else(|| self.round.get_smallest().max(Unit::Second));
3424        if largest >= Unit::Day {
3425            return Err(Error::from(
3426                crate::error::util::RoundingIncrementError::Unsupported {
3427                    unit: largest,
3428                },
3429            ));
3430        }
3431        let nano1 = t1.as_nanosecond_ranged().without_bounds();
3432        let nano2 = t2.as_nanosecond_ranged().without_bounds();
3433        let diff = nano2 - nano1;
3434        // This can fail when `largest` is nanoseconds since not all intervals
3435        // can be represented by a single i64 in units of nanoseconds.
3436        Span::from_invariant_nanoseconds(largest, diff)
3437    }
3438}
3439
3440impl From<Timestamp> for TimestampDifference {
3441    #[inline]
3442    fn from(ts: Timestamp) -> TimestampDifference {
3443        TimestampDifference::new(ts)
3444    }
3445}
3446
3447impl From<Zoned> for TimestampDifference {
3448    #[inline]
3449    fn from(zdt: Zoned) -> TimestampDifference {
3450        TimestampDifference::new(Timestamp::from(zdt))
3451    }
3452}
3453
3454impl<'a> From<&'a Zoned> for TimestampDifference {
3455    #[inline]
3456    fn from(zdt: &'a Zoned) -> TimestampDifference {
3457        TimestampDifference::from(Timestamp::from(zdt))
3458    }
3459}
3460
3461impl From<(Unit, Timestamp)> for TimestampDifference {
3462    #[inline]
3463    fn from((largest, ts): (Unit, Timestamp)) -> TimestampDifference {
3464        TimestampDifference::from(ts).largest(largest)
3465    }
3466}
3467
3468impl From<(Unit, Zoned)> for TimestampDifference {
3469    #[inline]
3470    fn from((largest, zdt): (Unit, Zoned)) -> TimestampDifference {
3471        TimestampDifference::from((largest, Timestamp::from(zdt)))
3472    }
3473}
3474
3475impl<'a> From<(Unit, &'a Zoned)> for TimestampDifference {
3476    #[inline]
3477    fn from((largest, zdt): (Unit, &'a Zoned)) -> TimestampDifference {
3478        TimestampDifference::from((largest, Timestamp::from(zdt)))
3479    }
3480}
3481
3482/// Options for [`Timestamp::round`].
3483///
3484/// This type provides a way to configure the rounding of a timestamp. In
3485/// particular, `Timestamp::round` accepts anything that implements the
3486/// `Into<TimestampRound>` trait. There are some trait implementations that
3487/// therefore make calling `Timestamp::round` in some common cases more
3488/// ergonomic:
3489///
3490/// * `From<Unit> for TimestampRound` will construct a rounding
3491/// configuration that rounds to the unit given. Specifically,
3492/// `TimestampRound::new().smallest(unit)`.
3493/// * `From<(Unit, i64)> for TimestampRound` is like the one above, but also
3494/// specifies the rounding increment for [`TimestampRound::increment`].
3495///
3496/// Note that in the default configuration, no rounding occurs.
3497///
3498/// # Example
3499///
3500/// This example shows how to round a timestamp to the nearest second:
3501///
3502/// ```
3503/// use jiff::{Timestamp, Unit};
3504///
3505/// let ts: Timestamp = "2024-06-20 16:24:59.5Z".parse()?;
3506/// assert_eq!(
3507///     ts.round(Unit::Second)?.to_string(),
3508///     // The second rounds up and causes minutes to increase.
3509///     "2024-06-20T16:25:00Z",
3510/// );
3511///
3512/// # Ok::<(), Box<dyn std::error::Error>>(())
3513/// ```
3514///
3515/// The above makes use of the fact that `Unit` implements
3516/// `Into<TimestampRound>`. If you want to change the rounding mode to, say,
3517/// truncation, then you'll need to construct a `TimestampRound` explicitly
3518/// since there are no convenience `Into` trait implementations for
3519/// [`RoundMode`].
3520///
3521/// ```
3522/// use jiff::{RoundMode, Timestamp, TimestampRound, Unit};
3523///
3524/// let ts: Timestamp = "2024-06-20 16:24:59.5Z".parse()?;
3525/// assert_eq!(
3526///     ts.round(
3527///         TimestampRound::new().smallest(Unit::Second).mode(RoundMode::Trunc),
3528///     )?.to_string(),
3529///     // The second just gets truncated as if it wasn't there.
3530///     "2024-06-20T16:24:59Z",
3531/// );
3532///
3533/// # Ok::<(), Box<dyn std::error::Error>>(())
3534/// ```
3535#[derive(Clone, Copy, Debug)]
3536pub struct TimestampRound {
3537    smallest: Unit,
3538    mode: RoundMode,
3539    increment: i64,
3540}
3541
3542impl TimestampRound {
3543    /// Create a new default configuration for rounding a [`Timestamp`].
3544    #[inline]
3545    pub fn new() -> TimestampRound {
3546        TimestampRound {
3547            smallest: Unit::Nanosecond,
3548            mode: RoundMode::HalfExpand,
3549            increment: 1,
3550        }
3551    }
3552
3553    /// Set the smallest units allowed in the timestamp returned after
3554    /// rounding.
3555    ///
3556    /// Any units below the smallest configured unit will be used, along with
3557    /// the rounding increment and rounding mode, to determine the value of the
3558    /// smallest unit. For example, when rounding `2024-06-20T03:25:30Z` to the
3559    /// nearest minute, the `30` second unit will result in rounding the minute
3560    /// unit of `25` up to `26` and zeroing out everything below minutes.
3561    ///
3562    /// This defaults to [`Unit::Nanosecond`].
3563    ///
3564    /// # Errors
3565    ///
3566    /// The smallest units must be no greater than [`Unit::Hour`].
3567    ///
3568    /// # Example
3569    ///
3570    /// ```
3571    /// use jiff::{Timestamp, TimestampRound, Unit};
3572    ///
3573    /// let ts: Timestamp = "2024-06-20T03:25:30Z".parse()?;
3574    /// assert_eq!(
3575    ///     ts.round(TimestampRound::new().smallest(Unit::Minute))?.to_string(),
3576    ///     "2024-06-20T03:26:00Z",
3577    /// );
3578    /// // Or, utilize the `From<Unit> for TimestampRound` impl:
3579    /// assert_eq!(
3580    ///     ts.round(Unit::Minute)?.to_string(),
3581    ///     "2024-06-20T03:26:00Z",
3582    /// );
3583    ///
3584    /// # Ok::<(), Box<dyn std::error::Error>>(())
3585    /// ```
3586    #[inline]
3587    pub fn smallest(self, unit: Unit) -> TimestampRound {
3588        TimestampRound { smallest: unit, ..self }
3589    }
3590
3591    /// Set the rounding mode.
3592    ///
3593    /// This defaults to [`RoundMode::HalfExpand`], which rounds away from
3594    /// zero. It matches the kind of rounding you might have been taught in
3595    /// school.
3596    ///
3597    /// # Example
3598    ///
3599    /// This shows how to always round timestamps up towards positive infinity.
3600    ///
3601    /// ```
3602    /// use jiff::{RoundMode, Timestamp, TimestampRound, Unit};
3603    ///
3604    /// let ts: Timestamp = "2024-06-20 03:25:01Z".parse()?;
3605    /// assert_eq!(
3606    ///     ts.round(
3607    ///         TimestampRound::new()
3608    ///             .smallest(Unit::Minute)
3609    ///             .mode(RoundMode::Ceil),
3610    ///     )?.to_string(),
3611    ///     "2024-06-20T03:26:00Z",
3612    /// );
3613    ///
3614    /// # Ok::<(), Box<dyn std::error::Error>>(())
3615    /// ```
3616    #[inline]
3617    pub fn mode(self, mode: RoundMode) -> TimestampRound {
3618        TimestampRound { mode, ..self }
3619    }
3620
3621    /// Set the rounding increment for the smallest unit.
3622    ///
3623    /// The default value is `1`. Other values permit rounding the smallest
3624    /// unit to the nearest integer increment specified. For example, if the
3625    /// smallest unit is set to [`Unit::Minute`], then a rounding increment of
3626    /// `30` would result in rounding in increments of a half hour. That is,
3627    /// the only minute value that could result would be `0` or `30`.
3628    ///
3629    /// # Errors
3630    ///
3631    /// The rounding increment, when combined with the smallest unit (which
3632    /// defaults to [`Unit::Nanosecond`]), must divide evenly into `86,400`
3633    /// seconds (one 24-hour civil day). For example, increments of both
3634    /// 45 seconds and 15 minutes are allowed, but 7 seconds and 25 minutes are
3635    /// both not allowed.
3636    ///
3637    /// # Example
3638    ///
3639    /// This example shows how to round a timestamp to the nearest 10 minute
3640    /// increment.
3641    ///
3642    /// ```
3643    /// use jiff::{RoundMode, Timestamp, TimestampRound, Unit};
3644    ///
3645    /// let ts: Timestamp = "2024-06-20 03:24:59Z".parse()?;
3646    /// assert_eq!(
3647    ///     ts.round((Unit::Minute, 10))?.to_string(),
3648    ///     "2024-06-20T03:20:00Z",
3649    /// );
3650    ///
3651    /// # Ok::<(), Box<dyn std::error::Error>>(())
3652    /// ```
3653    #[inline]
3654    pub fn increment(self, increment: i64) -> TimestampRound {
3655        TimestampRound { increment, ..self }
3656    }
3657
3658    /// Does the actual rounding.
3659    pub(crate) fn round(
3660        &self,
3661        timestamp: Timestamp,
3662    ) -> Result<Timestamp, Error> {
3663        let increment =
3664            increment::for_timestamp(self.smallest, self.increment)?;
3665        let nanosecond = timestamp.as_nanosecond_ranged().without_bounds();
3666        let rounded = self.mode.round_by_unit_in_nanoseconds(
3667            nanosecond,
3668            self.smallest,
3669            increment,
3670        );
3671        let nanosecond = UnixNanoseconds::rfrom(rounded);
3672        Ok(Timestamp::from_nanosecond_ranged(nanosecond))
3673    }
3674}
3675
3676impl Default for TimestampRound {
3677    #[inline]
3678    fn default() -> TimestampRound {
3679        TimestampRound::new()
3680    }
3681}
3682
3683impl From<Unit> for TimestampRound {
3684    #[inline]
3685    fn from(unit: Unit) -> TimestampRound {
3686        TimestampRound::default().smallest(unit)
3687    }
3688}
3689
3690impl From<(Unit, i64)> for TimestampRound {
3691    #[inline]
3692    fn from((unit, increment): (Unit, i64)) -> TimestampRound {
3693        TimestampRound::from(unit).increment(increment)
3694    }
3695}
3696
3697#[cfg(test)]
3698mod tests {
3699    use alloc::string::ToString;
3700
3701    use std::io::Cursor;
3702
3703    use crate::{
3704        civil::{self, datetime},
3705        tz::Offset,
3706        ToSpan,
3707    };
3708
3709    use super::*;
3710
3711    fn mktime(seconds: i64, nanos: i32) -> Timestamp {
3712        Timestamp::new(seconds, nanos).unwrap()
3713    }
3714
3715    fn mkdt(
3716        year: i16,
3717        month: i8,
3718        day: i8,
3719        hour: i8,
3720        minute: i8,
3721        second: i8,
3722        nano: i32,
3723    ) -> civil::DateTime {
3724        let date = civil::Date::new(year, month, day).unwrap();
3725        let time = civil::Time::new(hour, minute, second, nano).unwrap();
3726        civil::DateTime::from_parts(date, time)
3727    }
3728
3729    #[test]
3730    fn to_datetime_specific_examples() {
3731        let tests = [
3732            ((UnixSeconds::MIN_REPR, 0), (-9999, 1, 2, 1, 59, 59, 0)),
3733            (
3734                (UnixSeconds::MIN_REPR + 1, -999_999_999),
3735                (-9999, 1, 2, 1, 59, 59, 1),
3736            ),
3737            ((-1, 1), (1969, 12, 31, 23, 59, 59, 1)),
3738            ((UnixSeconds::MAX_REPR, 0), (9999, 12, 30, 22, 0, 0, 0)),
3739            ((UnixSeconds::MAX_REPR - 1, 0), (9999, 12, 30, 21, 59, 59, 0)),
3740            (
3741                (UnixSeconds::MAX_REPR - 1, 999_999_999),
3742                (9999, 12, 30, 21, 59, 59, 999_999_999),
3743            ),
3744            (
3745                (UnixSeconds::MAX_REPR, 999_999_999),
3746                (9999, 12, 30, 22, 0, 0, 999_999_999),
3747            ),
3748            ((-2, -1), (1969, 12, 31, 23, 59, 57, 999_999_999)),
3749            ((-86398, -1), (1969, 12, 31, 0, 0, 1, 999_999_999)),
3750            ((-86399, -1), (1969, 12, 31, 0, 0, 0, 999_999_999)),
3751            ((-86400, -1), (1969, 12, 30, 23, 59, 59, 999_999_999)),
3752        ];
3753        for (t, dt) in tests {
3754            let timestamp = mktime(t.0, t.1);
3755            let datetime = mkdt(dt.0, dt.1, dt.2, dt.3, dt.4, dt.5, dt.6);
3756            assert_eq!(
3757                Offset::UTC.to_datetime(timestamp),
3758                datetime,
3759                "timestamp: {t:?}"
3760            );
3761            assert_eq!(
3762                timestamp,
3763                datetime.to_zoned(TimeZone::UTC).unwrap().timestamp(),
3764                "datetime: {datetime:?}"
3765            );
3766        }
3767    }
3768
3769    #[test]
3770    fn to_datetime_many_seconds_in_some_days() {
3771        let days = [
3772            i64::from(t::UnixEpochDay::MIN_REPR),
3773            -1000,
3774            -5,
3775            23,
3776            2000,
3777            i64::from(t::UnixEpochDay::MAX_REPR),
3778        ];
3779        let seconds = [
3780            -86_400, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4,
3781            5, 6, 7, 8, 9, 10, 86_400,
3782        ];
3783        let nanos = [0, 1, 5, 999_999_999];
3784        for day in days {
3785            let midpoint = day * 86_400;
3786            for second in seconds {
3787                let second = midpoint + second;
3788                if !UnixSeconds::contains(second) {
3789                    continue;
3790                }
3791                for nano in nanos {
3792                    if second == UnixSeconds::MIN_REPR && nano != 0 {
3793                        continue;
3794                    }
3795                    let t = Timestamp::new(second, nano).unwrap();
3796                    let Ok(got) =
3797                        Offset::UTC.to_datetime(t).to_zoned(TimeZone::UTC)
3798                    else {
3799                        continue;
3800                    };
3801                    assert_eq!(t, got.timestamp());
3802                }
3803            }
3804        }
3805    }
3806
3807    #[test]
3808    fn invalid_time() {
3809        assert!(Timestamp::new(UnixSeconds::MIN_REPR, -1).is_err());
3810        assert!(Timestamp::new(UnixSeconds::MIN_REPR, -999_999_999).is_err());
3811        // These are greater than the minimum and thus okay!
3812        assert!(Timestamp::new(UnixSeconds::MIN_REPR, 1).is_ok());
3813        assert!(Timestamp::new(UnixSeconds::MIN_REPR, 999_999_999).is_ok());
3814    }
3815
3816    #[cfg(target_pointer_width = "64")]
3817    #[test]
3818    fn timestamp_size() {
3819        #[cfg(debug_assertions)]
3820        {
3821            assert_eq!(40, core::mem::size_of::<Timestamp>());
3822        }
3823        #[cfg(not(debug_assertions))]
3824        {
3825            assert_eq!(16, core::mem::size_of::<Timestamp>());
3826        }
3827    }
3828
3829    #[test]
3830    fn nanosecond_roundtrip_boundaries() {
3831        let inst = Timestamp::MIN;
3832        let nanos = inst.as_nanosecond_ranged();
3833        assert_eq!(C(0), nanos % t::NANOS_PER_SECOND);
3834        let got = Timestamp::from_nanosecond_ranged(nanos);
3835        assert_eq!(inst, got);
3836
3837        let inst = Timestamp::MAX;
3838        let nanos = inst.as_nanosecond_ranged();
3839        assert_eq!(
3840            FractionalNanosecond::MAX_SELF,
3841            nanos % t::NANOS_PER_SECOND
3842        );
3843        let got = Timestamp::from_nanosecond_ranged(nanos);
3844        assert_eq!(inst, got);
3845    }
3846
3847    #[test]
3848    fn timestamp_saturating_add() {
3849        insta::assert_snapshot!(
3850            Timestamp::MIN.saturating_add(Span::new().days(1)).unwrap_err(),
3851            @"saturating timestamp arithmetic requires only time units: operation can only be performed with units of hours or smaller, but found non-zero 'day' units (operations on `jiff::Timestamp`, `jiff::tz::Offset` and `jiff::civil::Time` don't support calendar units in a `jiff::Span`)",
3852        )
3853    }
3854
3855    #[test]
3856    fn timestamp_saturating_sub() {
3857        insta::assert_snapshot!(
3858            Timestamp::MAX.saturating_sub(Span::new().days(1)).unwrap_err(),
3859            @"saturating timestamp arithmetic requires only time units: operation can only be performed with units of hours or smaller, but found non-zero 'day' units (operations on `jiff::Timestamp`, `jiff::tz::Offset` and `jiff::civil::Time` don't support calendar units in a `jiff::Span`)",
3860        )
3861    }
3862
3863    quickcheck::quickcheck! {
3864        fn prop_unix_seconds_roundtrip(t: Timestamp) -> quickcheck::TestResult {
3865            let dt = t.to_zoned(TimeZone::UTC).datetime();
3866            let Ok(got) = dt.to_zoned(TimeZone::UTC) else {
3867                return quickcheck::TestResult::discard();
3868            };
3869            quickcheck::TestResult::from_bool(t == got.timestamp())
3870        }
3871
3872        fn prop_nanos_roundtrip_unix_ranged(t: Timestamp) -> bool {
3873            let nanos = t.as_nanosecond_ranged();
3874            let got = Timestamp::from_nanosecond_ranged(nanos);
3875            t == got
3876        }
3877
3878        fn prop_nanos_roundtrip_unix(t: Timestamp) -> bool {
3879            let nanos = t.as_nanosecond();
3880            let got = Timestamp::from_nanosecond(nanos).unwrap();
3881            t == got
3882        }
3883
3884        fn timestamp_constant_and_new_are_same1(t: Timestamp) -> bool {
3885            let got = Timestamp::constant(t.as_second(), t.subsec_nanosecond());
3886            t == got
3887        }
3888
3889        fn timestamp_constant_and_new_are_same2(
3890            secs: i64,
3891            nanos: i32
3892        ) -> quickcheck::TestResult {
3893            let Ok(ts) = Timestamp::new(secs, nanos) else {
3894                return quickcheck::TestResult::discard();
3895            };
3896            let got = Timestamp::constant(secs, nanos);
3897            quickcheck::TestResult::from_bool(ts == got)
3898        }
3899    }
3900
3901    /// A `serde` deserializer compatibility test.
3902    ///
3903    /// Serde YAML used to be unable to deserialize `jiff` types,
3904    /// as deserializing from bytes is not supported by the deserializer.
3905    ///
3906    /// - <https://github.com/BurntSushi/jiff/issues/138>
3907    /// - <https://github.com/BurntSushi/jiff/discussions/148>
3908    #[test]
3909    fn timestamp_deserialize_yaml() {
3910        let expected = datetime(2024, 10, 31, 16, 33, 53, 123456789)
3911            .to_zoned(TimeZone::UTC)
3912            .unwrap()
3913            .timestamp();
3914
3915        let deserialized: Timestamp =
3916            serde_yaml::from_str("2024-10-31T16:33:53.123456789+00:00")
3917                .unwrap();
3918
3919        assert_eq!(deserialized, expected);
3920
3921        let deserialized: Timestamp = serde_yaml::from_slice(
3922            "2024-10-31T16:33:53.123456789+00:00".as_bytes(),
3923        )
3924        .unwrap();
3925
3926        assert_eq!(deserialized, expected);
3927
3928        let cursor = Cursor::new(b"2024-10-31T16:33:53.123456789+00:00");
3929        let deserialized: Timestamp = serde_yaml::from_reader(cursor).unwrap();
3930
3931        assert_eq!(deserialized, expected);
3932    }
3933
3934    #[test]
3935    fn timestamp_precision_loss() {
3936        let ts1: Timestamp =
3937            "2025-01-25T19:32:21.783444592+01:00".parse().unwrap();
3938        let span = 1.second();
3939        let ts2 = ts1 + span;
3940        assert_eq!(ts2.to_string(), "2025-01-25T18:32:22.783444592Z");
3941        assert_eq!(ts1, ts2 - span, "should be reversible");
3942    }
3943}