Skip to main content

jiff/
timestamp.rs

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