jiff/
timestamp.rs

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