jiff/
signed_duration.rs

1use core::time::Duration;
2
3use crate::{
4    civil::{Date, DateTime, Time},
5    error::{err, ErrorContext},
6    fmt::{friendly, temporal},
7    tz::Offset,
8    util::{escape, rangeint::TryRFrom, t},
9    Error, RoundMode, Timestamp, Unit, Zoned,
10};
11
12#[cfg(not(feature = "std"))]
13use crate::util::libm::Float;
14
15/// A signed duration of time represented as a 96-bit integer of nanoseconds.
16///
17/// Each duration is made up of a 64-bit integer of whole seconds and a
18/// 32-bit integer of fractional nanoseconds less than 1 whole second. Unlike
19/// [`std::time::Duration`], this duration is signed. The sign applies
20/// to the entire duration. That is, either _both_ the seconds and the
21/// fractional nanoseconds are negative or _neither_ are. Stated differently,
22/// it is guaranteed that the signs of [`SignedDuration::as_secs`] and
23/// [`SignedDuration::subsec_nanos`] are always the same, or one component is
24/// zero. (For example, `-1 seconds` and `0 nanoseconds`, or `0 seconds` and
25/// `-1 nanoseconds`.)
26///
27/// # Parsing and printing
28///
29/// Like the [`Span`](crate::Span) type, the `SignedDuration` type
30/// provides convenient trait implementations of [`std::str::FromStr`] and
31/// [`std::fmt::Display`]:
32///
33/// ```
34/// use jiff::SignedDuration;
35///
36/// let duration: SignedDuration = "PT2h30m".parse()?;
37/// assert_eq!(duration.to_string(), "PT2H30M");
38///
39/// // Or use the "friendly" format by invoking the alternate:
40/// assert_eq!(format!("{duration:#}"), "2h 30m");
41///
42/// // Parsing automatically supports both the ISO 8601 and "friendly" formats:
43/// let duration: SignedDuration = "2h 30m".parse()?;
44/// assert_eq!(duration, SignedDuration::new(2 * 60 * 60 + 30 * 60, 0));
45/// let duration: SignedDuration = "2 hours, 30 minutes".parse()?;
46/// assert_eq!(duration, SignedDuration::new(2 * 60 * 60 + 30 * 60, 0));
47///
48/// # Ok::<(), Box<dyn std::error::Error>>(())
49/// ```
50///
51/// Unlike the `Span` type, though, only uniform units are supported. This
52/// means that ISO 8601 durations with non-zero units of days or greater cannot
53/// be parsed directly into a `SignedDuration`:
54///
55/// ```
56/// use jiff::SignedDuration;
57///
58/// assert_eq!(
59///     "P1d".parse::<SignedDuration>().unwrap_err().to_string(),
60///     "failed to parse ISO 8601 duration string into `SignedDuration`: \
61///      parsing ISO 8601 duration into SignedDuration requires that the \
62///      duration contain a time component and no components of days or \
63///      greater",
64/// );
65///
66/// # Ok::<(), Box<dyn std::error::Error>>(())
67/// ```
68///
69/// To parse such durations, one should first parse them into a `Span` and
70/// then convert them to a `SignedDuration` by providing a relative date:
71///
72/// ```
73/// use jiff::{civil::date, SignedDuration, Span};
74///
75/// let span: Span = "P1d".parse()?;
76/// let relative = date(2024, 11, 3).in_tz("US/Eastern")?;
77/// let duration = span.to_duration(&relative)?;
78/// // This example also motivates *why* a relative date
79/// // is required. Not all days are the same length!
80/// assert_eq!(duration.to_string(), "PT25H");
81///
82/// # Ok::<(), Box<dyn std::error::Error>>(())
83/// ```
84///
85/// The format supported is a variation (nearly a subset) of the duration
86/// format specified in [ISO 8601] _and_ a Jiff-specific "friendly" format.
87/// Here are more examples:
88///
89/// ```
90/// use jiff::SignedDuration;
91///
92/// let durations = [
93///     // ISO 8601
94///     ("PT2H30M", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
95///     ("PT2.5h", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
96///     ("PT1m", SignedDuration::from_mins(1)),
97///     ("PT1.5m", SignedDuration::from_secs(90)),
98///     ("PT0.0021s", SignedDuration::new(0, 2_100_000)),
99///     ("PT0s", SignedDuration::ZERO),
100///     ("PT0.000000001s", SignedDuration::from_nanos(1)),
101///     // Jiff's "friendly" format
102///     ("2h30m", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
103///     ("2 hrs 30 mins", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
104///     ("2 hours 30 minutes", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
105///     ("2.5h", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
106///     ("1m", SignedDuration::from_mins(1)),
107///     ("1.5m", SignedDuration::from_secs(90)),
108///     ("0.0021s", SignedDuration::new(0, 2_100_000)),
109///     ("0s", SignedDuration::ZERO),
110///     ("0.000000001s", SignedDuration::from_nanos(1)),
111/// ];
112/// for (string, duration) in durations {
113///     let parsed: SignedDuration = string.parse()?;
114///     assert_eq!(duration, parsed, "result of parsing {string:?}");
115/// }
116///
117/// # Ok::<(), Box<dyn std::error::Error>>(())
118/// ```
119///
120/// For more details, see the [`fmt::temporal`](temporal) and
121/// [`fmt::friendly`](friendly) modules.
122///
123/// [ISO 8601]: https://www.iso.org/iso-8601-date-and-time-format.html
124///
125/// # API design
126///
127/// A `SignedDuration` is, as much as is possible, a replica of the
128/// `std::time::Duration` API. While there are probably some quirks in the API
129/// of `std::time::Duration` that could have been fixed here, it is probably
130/// more important that it behave "exactly like a `std::time::Duration` but
131/// with a sign." That is, this type mirrors the parallels between signed and
132/// unsigned integer types.
133///
134/// While the goal was to match the `std::time::Duration` API as much as
135/// possible, there are some differences worth highlighting:
136///
137/// * As stated, a `SignedDuration` has a sign. Therefore, it uses `i64` and
138/// `i32` instead of `u64` and `u32` to represent its 96-bit integer.
139/// * Because it's signed, the range of possible values is different. For
140/// example, a `SignedDuration::MAX` has a whole number of seconds equivalent
141/// to `i64::MAX`, which is less than `u64::MAX`.
142/// * There are some additional APIs that don't make sense on an unsigned
143/// duration, like [`SignedDuration::abs`] and [`SignedDuration::checked_neg`].
144/// * A [`SignedDuration::system_until`] routine is provided as a replacement
145/// for [`std::time::SystemTime::duration_since`], but with signed durations.
146/// * Constructors and getters for units of hours and minutes are provided,
147/// where as these routines are unstable in the standard library.
148/// * Unlike the standard library, this type implements the `std::fmt::Display`
149/// and `std::str::FromStr` traits via the ISO 8601 duration format, just
150/// like the [`Span`](crate::Span) type does. Also like `Span`, the ISO
151/// 8601 duration format is used to implement the serde `Serialize` and
152/// `Deserialize` traits when the `serde` crate feature is enabled.
153/// * The `std::fmt::Debug` trait implementation is a bit different. If you
154/// have a problem with it, please file an issue.
155/// * At present, there is no `SignedDuration::abs_diff` since there are some
156/// API design questions. If you want it, please file an issue.
157///
158/// # When should I use `SignedDuration` versus [`Span`](crate::Span)?
159///
160/// Jiff's primary duration type is `Span`. The key differences between it and
161/// `SignedDuration` are:
162///
163/// * A `Span` keeps track of each individual unit separately. That is, even
164/// though `1 hour 60 minutes` and `2 hours` are equivalent durations
165/// of time, representing each as a `Span` corresponds to two distinct values
166/// in memory. And serializing them to the ISO 8601 duration format will also
167/// preserve the units, for example, `PT1h60m` and `PT2h`.
168/// * A `Span` supports non-uniform units like days, weeks, months and years.
169/// Since not all days, weeks, months and years have the same length, they
170/// cannot be represented by a `SignedDuration`. In some cases, it may be
171/// appropriate, for example, to assume that all days are 24 hours long. But
172/// since Jiff sometimes assumes all days are 24 hours (for civil time) and
173/// sometimes doesn't (like for `Zoned` when respecting time zones), it would
174/// be inappropriate to bake one of those assumptions into a `SignedDuration`.
175/// * A `SignedDuration` is a much smaller type than a `Span`. Specifically,
176/// it's a 96-bit integer. In contrast, a `Span` is much larger since it needs
177/// to track each individual unit separately.
178///
179/// Those differences in turn motivate some approximate reasoning for when to
180/// use `Span` and when to use `SignedDuration`:
181///
182/// * If you don't care about keeping track of individual units separately or
183/// don't need the sophisticated rounding options available on a `Span`, it
184/// might be simpler and faster to use a `SignedDuration`.
185/// * If you specifically need performance on arithmetic operations involving
186/// datetimes and durations, even if it's not as convenient or correct, then it
187/// might make sense to use a `SignedDuration`.
188/// * If you need to perform arithmetic using a `std::time::Duration` and
189/// otherwise don't need the functionality of a `Span`, it might make sense
190/// to first convert the `std::time::Duration` to a `SignedDuration`, and then
191/// use one of the corresponding operations defined for `SignedDuration` on
192/// the datetime types. (They all support it.)
193///
194/// In general, a `Span` provides more functionality and is overall more
195/// flexible. A `Span` can also deserialize all forms of ISO 8601 durations
196/// (as long as they're within Jiff's limits), including durations with units
197/// of years, months, weeks and days. A `SignedDuration`, by contrast, only
198/// supports units up to and including hours.
199///
200/// # Integration with datetime types
201///
202/// All datetime types that support arithmetic using [`Span`](crate::Span) also
203/// support arithmetic using `SignedDuration` (and [`std::time::Duration`]).
204/// For example, here's how to add an absolute duration to a [`Timestamp`]:
205///
206/// ```
207/// use jiff::{SignedDuration, Timestamp};
208///
209/// let ts1 = Timestamp::from_second(1_123_456_789)?;
210/// assert_eq!(ts1.to_string(), "2005-08-07T23:19:49Z");
211///
212/// let duration = SignedDuration::new(59, 999_999_999);
213/// // Timestamp::checked_add is polymorphic! It can accept a
214/// // span or a duration.
215/// let ts2 = ts1.checked_add(duration)?;
216/// assert_eq!(ts2.to_string(), "2005-08-07T23:20:48.999999999Z");
217///
218/// # Ok::<(), Box<dyn std::error::Error>>(())
219/// ```
220///
221/// The same API pattern works with [`Zoned`], [`DateTime`], [`Date`] and
222/// [`Time`].
223///
224/// # Interaction with daylight saving time and time zone transitions
225///
226/// A `SignedDuration` always corresponds to a specific number of nanoseconds.
227/// Since a [`Zoned`] is always a precise instant in time, adding a `SignedDuration`
228/// to a `Zoned` always behaves by adding the nanoseconds from the duration to
229/// the timestamp inside of `Zoned`. Consider `2024-03-10` in `US/Eastern`.
230/// At `02:00:00`, daylight saving time came into effect, switching the UTC
231/// offset for the region from `-05` to `-04`. This has the effect of skipping
232/// an hour on the clocks:
233///
234/// ```
235/// use jiff::{civil::date, SignedDuration};
236///
237/// let zdt = date(2024, 3, 10).at(1, 59, 0, 0).in_tz("US/Eastern")?;
238/// assert_eq!(
239///     zdt.checked_add(SignedDuration::from_hours(1))?,
240///     // Time on the clock skipped an hour, but in this time
241///     // zone, 03:59 is actually precisely 1 hour later than
242///     // 01:59.
243///     date(2024, 3, 10).at(3, 59, 0, 0).in_tz("US/Eastern")?,
244/// );
245/// // The same would apply if you used a `Span`:
246/// assert_eq!(
247///     zdt.checked_add(jiff::Span::new().hours(1))?,
248///     // Time on the clock skipped an hour, but in this time
249///     // zone, 03:59 is actually precisely 1 hour later than
250///     // 01:59.
251///     date(2024, 3, 10).at(3, 59, 0, 0).in_tz("US/Eastern")?,
252/// );
253///
254/// # Ok::<(), Box<dyn std::error::Error>>(())
255/// ```
256///
257/// Where time zones might have a more interesting effect is in the definition
258/// of the "day" itself. If, for example, you encode the notion that a day is
259/// always 24 hours into your arithmetic, you might get unexpected results.
260/// For example, let's say you want to find the datetime precisely one week
261/// after `2024-03-08T17:00` in the `US/Eastern` time zone. You might be
262/// tempted to just ask for the time that is `7 * 24` hours later:
263///
264/// ```
265/// use jiff::{civil::date, SignedDuration};
266///
267/// let zdt = date(2024, 3, 8).at(17, 0, 0, 0).in_tz("US/Eastern")?;
268/// assert_eq!(
269///     zdt.checked_add(SignedDuration::from_hours(7 * 24))?,
270///     date(2024, 3, 15).at(18, 0, 0, 0).in_tz("US/Eastern")?,
271/// );
272///
273/// # Ok::<(), Box<dyn std::error::Error>>(())
274/// ```
275///
276/// Notice that you get `18:00` and not `17:00`! That's because, as shown
277/// in the previous example, `2024-03-10` was only 23 hours long. That in turn
278/// implies that the week starting from `2024-03-08` is only `7 * 24 - 1` hours
279/// long. This can be tricky to get correct with absolute durations like
280/// `SignedDuration`, but a `Span` will handle this for you automatically:
281///
282/// ```
283/// use jiff::{civil::date, ToSpan};
284///
285/// let zdt = date(2024, 3, 8).at(17, 0, 0, 0).in_tz("US/Eastern")?;
286/// assert_eq!(
287///     zdt.checked_add(1.week())?,
288///     // The expected time!
289///     date(2024, 3, 15).at(17, 0, 0, 0).in_tz("US/Eastern")?,
290/// );
291///
292/// # Ok::<(), Box<dyn std::error::Error>>(())
293/// ```
294///
295/// A `Span` achieves this by keeping track of individual units. Unlike a
296/// `SignedDuration`, it is not just a simple count of nanoseconds. It is a
297/// "bag" of individual units, and the arithmetic operations defined on a
298/// `Span` for `Zoned` know how to interpret "day" in a particular time zone
299/// at a particular instant in time.
300///
301/// With that said, the above does not mean that using a `SignedDuration` is
302/// always wrong. For example, if you're dealing with units of hours or lower,
303/// then all such units are uniform and so you'll always get the same results
304/// as with a `Span`. And using a `SignedDuration` can sometimes be simpler
305/// or faster.
306#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
307pub struct SignedDuration {
308    secs: i64,
309    nanos: i32,
310}
311
312const NANOS_PER_SEC: i32 = 1_000_000_000;
313const NANOS_PER_MILLI: i32 = 1_000_000;
314const NANOS_PER_MICRO: i32 = 1_000;
315const MILLIS_PER_SEC: i64 = 1_000;
316const MICROS_PER_SEC: i64 = 1_000_000;
317const SECS_PER_MINUTE: i64 = 60;
318const MINS_PER_HOUR: i64 = 60;
319
320impl SignedDuration {
321    /// A duration of zero time.
322    ///
323    /// # Example
324    ///
325    /// ```
326    /// use jiff::SignedDuration;
327    ///
328    /// let duration = SignedDuration::ZERO;
329    /// assert!(duration.is_zero());
330    /// assert_eq!(duration.as_secs(), 0);
331    /// assert_eq!(duration.subsec_nanos(), 0);
332    /// ```
333    pub const ZERO: SignedDuration = SignedDuration { secs: 0, nanos: 0 };
334
335    /// The minimum possible duration. Or the "most negative" duration.
336    ///
337    /// # Example
338    ///
339    /// ```
340    /// use jiff::SignedDuration;
341    ///
342    /// let duration = SignedDuration::MIN;
343    /// assert_eq!(duration.as_secs(), i64::MIN);
344    /// assert_eq!(duration.subsec_nanos(), -999_999_999);
345    /// ```
346    pub const MIN: SignedDuration =
347        SignedDuration { secs: i64::MIN, nanos: -(NANOS_PER_SEC - 1) };
348
349    /// The maximum possible duration.
350    ///
351    /// # Example
352    ///
353    /// ```
354    /// use jiff::SignedDuration;
355    ///
356    /// let duration = SignedDuration::MAX;
357    /// assert_eq!(duration.as_secs(), i64::MAX);
358    /// assert_eq!(duration.subsec_nanos(), 999_999_999);
359    /// ```
360    pub const MAX: SignedDuration =
361        SignedDuration { secs: i64::MAX, nanos: NANOS_PER_SEC - 1 };
362
363    /// Creates a new `SignedDuration` from the given number of whole seconds
364    /// and additional nanoseconds.
365    ///
366    /// If the absolute value of the nanoseconds is greater than or equal to
367    /// 1 second, then the excess balances into the number of whole seconds.
368    ///
369    /// # Panics
370    ///
371    /// When the absolute value of the nanoseconds is greater than or equal
372    /// to 1 second and the excess that carries over to the number of whole
373    /// seconds overflows `i64`.
374    ///
375    /// This never panics when `nanos` is less than `1_000_000_000`.
376    ///
377    /// # Example
378    ///
379    /// ```
380    /// use jiff::SignedDuration;
381    ///
382    /// let duration = SignedDuration::new(12, 0);
383    /// assert_eq!(duration.as_secs(), 12);
384    /// assert_eq!(duration.subsec_nanos(), 0);
385    ///
386    /// let duration = SignedDuration::new(12, -1);
387    /// assert_eq!(duration.as_secs(), 11);
388    /// assert_eq!(duration.subsec_nanos(), 999_999_999);
389    ///
390    /// let duration = SignedDuration::new(12, 1_000_000_000);
391    /// assert_eq!(duration.as_secs(), 13);
392    /// assert_eq!(duration.subsec_nanos(), 0);
393    /// ```
394    #[inline]
395    pub const fn new(mut secs: i64, mut nanos: i32) -> SignedDuration {
396        // When |nanos| exceeds 1 second, we balance the excess up to seconds.
397        if !(-NANOS_PER_SEC < nanos && nanos < NANOS_PER_SEC) {
398            // Never wraps or panics because NANOS_PER_SEC!={0,-1}.
399            let addsecs = nanos / NANOS_PER_SEC;
400            secs = match secs.checked_add(addsecs as i64) {
401                Some(secs) => secs,
402                None => panic!(
403                    "nanoseconds overflowed seconds in SignedDuration::new"
404                ),
405            };
406            // Never wraps or panics because NANOS_PER_SEC!={0,-1}.
407            nanos = nanos % NANOS_PER_SEC;
408        }
409        // At this point, we're done if either unit is zero or if they have the
410        // same sign.
411        if nanos == 0 || secs == 0 || secs.signum() == (nanos.signum() as i64)
412        {
413            return SignedDuration::new_unchecked(secs, nanos);
414        }
415        // Otherwise, the only work we have to do is to balance negative nanos
416        // into positive seconds, or positive nanos into negative seconds.
417        if secs < 0 {
418            debug_assert!(nanos > 0);
419            // Never wraps because adding +1 to a negative i64 never overflows.
420            //
421            // MSRV(1.79): Consider using `unchecked_add` here.
422            secs += 1;
423            // Never wraps because subtracting +1_000_000_000 from a positive
424            // i32 never overflows.
425            //
426            // MSRV(1.79): Consider using `unchecked_sub` here.
427            nanos -= NANOS_PER_SEC;
428        } else {
429            debug_assert!(secs > 0);
430            debug_assert!(nanos < 0);
431            // Never wraps because subtracting +1 from a positive i64 never
432            // overflows.
433            //
434            // MSRV(1.79): Consider using `unchecked_add` here.
435            secs -= 1;
436            // Never wraps because adding +1_000_000_000 to a negative i32
437            // never overflows.
438            //
439            // MSRV(1.79): Consider using `unchecked_add` here.
440            nanos += NANOS_PER_SEC;
441        }
442        SignedDuration::new_unchecked(secs, nanos)
443    }
444
445    /// Creates a new signed duration without handling nanosecond overflow.
446    ///
447    /// This might produce tighter code in some cases.
448    ///
449    /// # Panics
450    ///
451    /// When `|nanos|` is greater than or equal to 1 second.
452    #[inline]
453    pub(crate) const fn new_without_nano_overflow(
454        secs: i64,
455        nanos: i32,
456    ) -> SignedDuration {
457        assert!(nanos <= 999_999_999);
458        assert!(nanos >= -999_999_999);
459        SignedDuration::new_unchecked(secs, nanos)
460    }
461
462    /// Creates a new signed duration without handling nanosecond overflow.
463    ///
464    /// This might produce tighter code in some cases.
465    ///
466    /// In debug mode only, when `|nanos|` is greater than or equal to 1
467    /// second.
468    ///
469    /// This is not exported so that code outside this module can rely on
470    /// `|nanos|` being less than a second for purposes of memory safety.
471    #[inline]
472    const fn new_unchecked(secs: i64, nanos: i32) -> SignedDuration {
473        debug_assert!(nanos <= 999_999_999);
474        debug_assert!(nanos >= -999_999_999);
475        SignedDuration { secs, nanos }
476    }
477
478    /// Creates a new `SignedDuration` from the given number of whole seconds.
479    ///
480    /// # Example
481    ///
482    /// ```
483    /// use jiff::SignedDuration;
484    ///
485    /// let duration = SignedDuration::from_secs(12);
486    /// assert_eq!(duration.as_secs(), 12);
487    /// assert_eq!(duration.subsec_nanos(), 0);
488    /// ```
489    #[inline]
490    pub const fn from_secs(secs: i64) -> SignedDuration {
491        SignedDuration::new_unchecked(secs, 0)
492    }
493
494    /// Creates a new `SignedDuration` from the given number of whole
495    /// milliseconds.
496    ///
497    /// Note that since this accepts an `i64`, this method cannot be used
498    /// to construct the full range of possible signed duration values. In
499    /// particular, [`SignedDuration::as_millis`] returns an `i128`, and this
500    /// may be a value that would otherwise overflow an `i64`.
501    ///
502    /// # Example
503    ///
504    /// ```
505    /// use jiff::SignedDuration;
506    ///
507    /// let duration = SignedDuration::from_millis(12_456);
508    /// assert_eq!(duration.as_secs(), 12);
509    /// assert_eq!(duration.subsec_nanos(), 456_000_000);
510    ///
511    /// let duration = SignedDuration::from_millis(-12_456);
512    /// assert_eq!(duration.as_secs(), -12);
513    /// assert_eq!(duration.subsec_nanos(), -456_000_000);
514    /// ```
515    #[inline]
516    pub const fn from_millis(millis: i64) -> SignedDuration {
517        // OK because MILLIS_PER_SEC!={-1,0}.
518        let secs = millis / MILLIS_PER_SEC;
519        // OK because MILLIS_PER_SEC!={-1,0} and because
520        // millis % MILLIS_PER_SEC can be at most 999, and 999 * 1_000_000
521        // never overflows i32.
522        let nanos = (millis % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI;
523        SignedDuration::new_unchecked(secs, nanos)
524    }
525
526    /// Creates a new `SignedDuration` from the given number of whole
527    /// microseconds.
528    ///
529    /// Note that since this accepts an `i64`, this method cannot be used
530    /// to construct the full range of possible signed duration values. In
531    /// particular, [`SignedDuration::as_micros`] returns an `i128`, and this
532    /// may be a value that would otherwise overflow an `i64`.
533    ///
534    /// # Example
535    ///
536    /// ```
537    /// use jiff::SignedDuration;
538    ///
539    /// let duration = SignedDuration::from_micros(12_000_456);
540    /// assert_eq!(duration.as_secs(), 12);
541    /// assert_eq!(duration.subsec_nanos(), 456_000);
542    ///
543    /// let duration = SignedDuration::from_micros(-12_000_456);
544    /// assert_eq!(duration.as_secs(), -12);
545    /// assert_eq!(duration.subsec_nanos(), -456_000);
546    /// ```
547    #[inline]
548    pub const fn from_micros(micros: i64) -> SignedDuration {
549        // OK because MICROS_PER_SEC!={-1,0}.
550        let secs = micros / MICROS_PER_SEC;
551        // OK because MICROS_PER_SEC!={-1,0} and because
552        // millis % MICROS_PER_SEC can be at most 999, and 999 * 1_000_000
553        // never overflows i32.
554        let nanos = (micros % MICROS_PER_SEC) as i32 * NANOS_PER_MICRO;
555        SignedDuration::new_unchecked(secs, nanos)
556    }
557
558    /// Creates a new `SignedDuration` from the given number of whole
559    /// nanoseconds.
560    ///
561    /// Note that since this accepts an `i64`, this method cannot be used
562    /// to construct the full range of possible signed duration values. In
563    /// particular, [`SignedDuration::as_nanos`] returns an `i128`, which may
564    /// be a value that would otherwise overflow an `i64`.
565    ///
566    /// # Example
567    ///
568    /// ```
569    /// use jiff::SignedDuration;
570    ///
571    /// let duration = SignedDuration::from_nanos(12_000_000_456);
572    /// assert_eq!(duration.as_secs(), 12);
573    /// assert_eq!(duration.subsec_nanos(), 456);
574    ///
575    /// let duration = SignedDuration::from_nanos(-12_000_000_456);
576    /// assert_eq!(duration.as_secs(), -12);
577    /// assert_eq!(duration.subsec_nanos(), -456);
578    /// ```
579    #[inline]
580    pub const fn from_nanos(nanos: i64) -> SignedDuration {
581        // OK because NANOS_PER_SEC!={-1,0}.
582        let secs = nanos / (NANOS_PER_SEC as i64);
583        // OK because NANOS_PER_SEC!={-1,0}.
584        let nanos = (nanos % (NANOS_PER_SEC as i64)) as i32;
585        SignedDuration::new_unchecked(secs, nanos)
586    }
587
588    /// Creates a new `SignedDuration` from the given number of hours. Every
589    /// hour is exactly `3,600` seconds.
590    ///
591    /// # Panics
592    ///
593    /// Panics if the number of hours, after being converted to nanoseconds,
594    /// overflows the minimum or maximum `SignedDuration` values.
595    ///
596    /// # Example
597    ///
598    /// ```
599    /// use jiff::SignedDuration;
600    ///
601    /// let duration = SignedDuration::from_hours(24);
602    /// assert_eq!(duration.as_secs(), 86_400);
603    /// assert_eq!(duration.subsec_nanos(), 0);
604    ///
605    /// let duration = SignedDuration::from_hours(-24);
606    /// assert_eq!(duration.as_secs(), -86_400);
607    /// assert_eq!(duration.subsec_nanos(), 0);
608    /// ```
609    #[inline]
610    pub const fn from_hours(hours: i64) -> SignedDuration {
611        // OK because (SECS_PER_MINUTE*MINS_PER_HOUR)!={-1,0}.
612        const MIN_HOUR: i64 = i64::MIN / (SECS_PER_MINUTE * MINS_PER_HOUR);
613        // OK because (SECS_PER_MINUTE*MINS_PER_HOUR)!={-1,0}.
614        const MAX_HOUR: i64 = i64::MAX / (SECS_PER_MINUTE * MINS_PER_HOUR);
615        // OK because (SECS_PER_MINUTE*MINS_PER_HOUR)!={-1,0}.
616        if hours < MIN_HOUR {
617            panic!("hours overflowed minimum number of SignedDuration seconds")
618        }
619        // OK because (SECS_PER_MINUTE*MINS_PER_HOUR)!={-1,0}.
620        if hours > MAX_HOUR {
621            panic!("hours overflowed maximum number of SignedDuration seconds")
622        }
623        SignedDuration::from_secs(hours * MINS_PER_HOUR * SECS_PER_MINUTE)
624    }
625
626    /// Creates a new `SignedDuration` from the given number of minutes. Every
627    /// minute is exactly `60` seconds.
628    ///
629    /// # Panics
630    ///
631    /// Panics if the number of minutes, after being converted to nanoseconds,
632    /// overflows the minimum or maximum `SignedDuration` values.
633    ///
634    /// # Example
635    ///
636    /// ```
637    /// use jiff::SignedDuration;
638    ///
639    /// let duration = SignedDuration::from_mins(1_440);
640    /// assert_eq!(duration.as_secs(), 86_400);
641    /// assert_eq!(duration.subsec_nanos(), 0);
642    ///
643    /// let duration = SignedDuration::from_mins(-1_440);
644    /// assert_eq!(duration.as_secs(), -86_400);
645    /// assert_eq!(duration.subsec_nanos(), 0);
646    /// ```
647    #[inline]
648    pub const fn from_mins(minutes: i64) -> SignedDuration {
649        // OK because SECS_PER_MINUTE!={-1,0}.
650        const MIN_MINUTE: i64 = i64::MIN / SECS_PER_MINUTE;
651        // OK because SECS_PER_MINUTE!={-1,0}.
652        const MAX_MINUTE: i64 = i64::MAX / SECS_PER_MINUTE;
653        // OK because SECS_PER_MINUTE!={-1,0}.
654        if minutes < MIN_MINUTE {
655            panic!(
656                "minutes overflowed minimum number of SignedDuration seconds"
657            )
658        }
659        // OK because SECS_PER_MINUTE!={-1,0}.
660        if minutes > MAX_MINUTE {
661            panic!(
662                "minutes overflowed maximum number of SignedDuration seconds"
663            )
664        }
665        SignedDuration::from_secs(minutes * SECS_PER_MINUTE)
666    }
667
668    /// Converts the given timestamp into a signed duration.
669    ///
670    /// This isn't exported because it's not clear that it makes semantic
671    /// sense, since it somewhat encodes the assumption that the "desired"
672    /// duration is relative to the Unix epoch. Which is... probably fine?
673    /// But I'm not sure.
674    ///
675    /// But the point of this is to make the conversion a little cheaper.
676    /// Namely, since a `Timestamp` internally uses same representation as a
677    /// `SignedDuration` with the same guarantees (except with smaller limits),
678    /// we can avoid a fair bit of case analysis done in `SignedDuration::new`.
679    pub(crate) fn from_timestamp(timestamp: Timestamp) -> SignedDuration {
680        SignedDuration::new_unchecked(
681            timestamp.as_second(),
682            timestamp.subsec_nanosecond(),
683        )
684    }
685
686    /// Returns true if this duration spans no time.
687    ///
688    /// # Example
689    ///
690    /// ```
691    /// use jiff::SignedDuration;
692    ///
693    /// assert!(SignedDuration::ZERO.is_zero());
694    /// assert!(!SignedDuration::MIN.is_zero());
695    /// assert!(!SignedDuration::MAX.is_zero());
696    /// ```
697    #[inline]
698    pub const fn is_zero(&self) -> bool {
699        self.secs == 0 && self.nanos == 0
700    }
701
702    /// Returns the number of whole seconds in this duration.
703    ///
704    /// The value returned is negative when the duration is negative.
705    ///
706    /// This does not include any fractional component corresponding to units
707    /// less than a second. To access those, use one of the `subsec` methods
708    /// such as [`SignedDuration::subsec_nanos`].
709    ///
710    /// # Example
711    ///
712    /// ```
713    /// use jiff::SignedDuration;
714    ///
715    /// let duration = SignedDuration::new(12, 999_999_999);
716    /// assert_eq!(duration.as_secs(), 12);
717    ///
718    /// let duration = SignedDuration::new(-12, -999_999_999);
719    /// assert_eq!(duration.as_secs(), -12);
720    /// ```
721    #[inline]
722    pub const fn as_secs(&self) -> i64 {
723        self.secs
724    }
725
726    /// Returns the fractional part of this duration in whole milliseconds.
727    ///
728    /// The value returned is negative when the duration is negative. It is
729    /// guaranteed that the range of the value returned is in the inclusive
730    /// range `-999..=999`.
731    ///
732    /// To get the length of the total duration represented in milliseconds,
733    /// use [`SignedDuration::as_millis`].
734    ///
735    /// # Example
736    ///
737    /// ```
738    /// use jiff::SignedDuration;
739    ///
740    /// let duration = SignedDuration::new(12, 123_456_789);
741    /// assert_eq!(duration.subsec_millis(), 123);
742    ///
743    /// let duration = SignedDuration::new(-12, -123_456_789);
744    /// assert_eq!(duration.subsec_millis(), -123);
745    /// ```
746    #[inline]
747    pub const fn subsec_millis(&self) -> i32 {
748        // OK because NANOS_PER_MILLI!={-1,0}.
749        self.nanos / NANOS_PER_MILLI
750    }
751
752    /// Returns the fractional part of this duration in whole microseconds.
753    ///
754    /// The value returned is negative when the duration is negative. It is
755    /// guaranteed that the range of the value returned is in the inclusive
756    /// range `-999_999..=999_999`.
757    ///
758    /// To get the length of the total duration represented in microseconds,
759    /// use [`SignedDuration::as_micros`].
760    ///
761    /// # Example
762    ///
763    /// ```
764    /// use jiff::SignedDuration;
765    ///
766    /// let duration = SignedDuration::new(12, 123_456_789);
767    /// assert_eq!(duration.subsec_micros(), 123_456);
768    ///
769    /// let duration = SignedDuration::new(-12, -123_456_789);
770    /// assert_eq!(duration.subsec_micros(), -123_456);
771    /// ```
772    #[inline]
773    pub const fn subsec_micros(&self) -> i32 {
774        // OK because NANOS_PER_MICRO!={-1,0}.
775        self.nanos / NANOS_PER_MICRO
776    }
777
778    /// Returns the fractional part of this duration in whole nanoseconds.
779    ///
780    /// The value returned is negative when the duration is negative. It is
781    /// guaranteed that the range of the value returned is in the inclusive
782    /// range `-999_999_999..=999_999_999`.
783    ///
784    /// To get the length of the total duration represented in nanoseconds,
785    /// use [`SignedDuration::as_nanos`].
786    ///
787    /// # Example
788    ///
789    /// ```
790    /// use jiff::SignedDuration;
791    ///
792    /// let duration = SignedDuration::new(12, 123_456_789);
793    /// assert_eq!(duration.subsec_nanos(), 123_456_789);
794    ///
795    /// let duration = SignedDuration::new(-12, -123_456_789);
796    /// assert_eq!(duration.subsec_nanos(), -123_456_789);
797    /// ```
798    #[inline]
799    pub const fn subsec_nanos(&self) -> i32 {
800        self.nanos
801    }
802
803    /// Returns the total duration in units of whole milliseconds.
804    ///
805    /// The value returned is negative when the duration is negative.
806    ///
807    /// To get only the fractional component of this duration in units of
808    /// whole milliseconds, use [`SignedDuration::subsec_millis`].
809    ///
810    /// # Example
811    ///
812    /// ```
813    /// use jiff::SignedDuration;
814    ///
815    /// let duration = SignedDuration::new(12, 123_456_789);
816    /// assert_eq!(duration.as_millis(), 12_123);
817    ///
818    /// let duration = SignedDuration::new(-12, -123_456_789);
819    /// assert_eq!(duration.as_millis(), -12_123);
820    /// ```
821    #[inline]
822    pub const fn as_millis(&self) -> i128 {
823        // OK because 1_000 times any i64 will never overflow i128.
824        let millis = (self.secs as i128) * (MILLIS_PER_SEC as i128);
825        // OK because NANOS_PER_MILLI!={-1,0}.
826        let subsec_millis = (self.nanos / NANOS_PER_MILLI) as i128;
827        // OK because subsec_millis maxes out at 999, and adding that to
828        // i64::MAX*1_000 will never overflow a i128.
829        millis + subsec_millis
830    }
831
832    /// Returns the total duration in units of whole microseconds.
833    ///
834    /// The value returned is negative when the duration is negative.
835    ///
836    /// To get only the fractional component of this duration in units of
837    /// whole microseconds, use [`SignedDuration::subsec_micros`].
838    ///
839    /// # Example
840    ///
841    /// ```
842    /// use jiff::SignedDuration;
843    ///
844    /// let duration = SignedDuration::new(12, 123_456_789);
845    /// assert_eq!(duration.as_micros(), 12_123_456);
846    ///
847    /// let duration = SignedDuration::new(-12, -123_456_789);
848    /// assert_eq!(duration.as_micros(), -12_123_456);
849    /// ```
850    #[inline]
851    pub const fn as_micros(&self) -> i128 {
852        // OK because 1_000_000 times any i64 will never overflow i128.
853        let micros = (self.secs as i128) * (MICROS_PER_SEC as i128);
854        // OK because NANOS_PER_MICRO!={-1,0}.
855        let subsec_micros = (self.nanos / NANOS_PER_MICRO) as i128;
856        // OK because subsec_micros maxes out at 999_999, and adding that to
857        // i64::MAX*1_000_000 will never overflow a i128.
858        micros + subsec_micros
859    }
860
861    /// Returns the total duration in units of whole nanoseconds.
862    ///
863    /// The value returned is negative when the duration is negative.
864    ///
865    /// To get only the fractional component of this duration in units of
866    /// whole nanoseconds, use [`SignedDuration::subsec_nanos`].
867    ///
868    /// # Example
869    ///
870    /// ```
871    /// use jiff::SignedDuration;
872    ///
873    /// let duration = SignedDuration::new(12, 123_456_789);
874    /// assert_eq!(duration.as_nanos(), 12_123_456_789);
875    ///
876    /// let duration = SignedDuration::new(-12, -123_456_789);
877    /// assert_eq!(duration.as_nanos(), -12_123_456_789);
878    /// ```
879    #[inline]
880    pub const fn as_nanos(&self) -> i128 {
881        // OK because 1_000_000_000 times any i64 will never overflow i128.
882        let nanos = (self.secs as i128) * (NANOS_PER_SEC as i128);
883        // OK because subsec_nanos maxes out at 999_999_999, and adding that to
884        // i64::MAX*1_000_000_000 will never overflow a i128.
885        nanos + (self.nanos as i128)
886    }
887
888    // NOTE: We don't provide `abs_diff` here because we can't represent the
889    // difference between all possible durations. For example,
890    // `abs_diff(SignedDuration::MAX, SignedDuration::MIN)`. It therefore seems
891    // like we should actually return a `std::time::Duration` here, but I'm
892    // trying to be conservative when divering from std.
893
894    /// Add two signed durations together. If overflow occurs, then `None` is
895    /// returned.
896    ///
897    /// # Example
898    ///
899    /// ```
900    /// use jiff::SignedDuration;
901    ///
902    /// let duration1 = SignedDuration::new(12, 500_000_000);
903    /// let duration2 = SignedDuration::new(0, 500_000_000);
904    /// assert_eq!(
905    ///     duration1.checked_add(duration2),
906    ///     Some(SignedDuration::new(13, 0)),
907    /// );
908    ///
909    /// let duration1 = SignedDuration::MAX;
910    /// let duration2 = SignedDuration::new(0, 1);
911    /// assert_eq!(duration1.checked_add(duration2), None);
912    /// ```
913    #[inline]
914    pub const fn checked_add(
915        self,
916        rhs: SignedDuration,
917    ) -> Option<SignedDuration> {
918        let Some(mut secs) = self.secs.checked_add(rhs.secs) else {
919            return None;
920        };
921        // OK because `-999_999_999 <= nanos <= 999_999_999`, and so adding
922        // them together will never overflow an i32.
923        let mut nanos = self.nanos + rhs.nanos;
924        // The below is effectively SignedDuration::new, but with checked
925        // arithmetic. My suspicion is that there is probably a better way
926        // to do this. The main complexity here is that 1) `|nanos|` might
927        // now exceed 1 second and 2) the signs of `secs` and `nanos` might
928        // not be the same. The other difference from SignedDuration::new is
929        // that we know that `-1_999_999_998 <= nanos <= 1_999_999_998` since
930        // `|SignedDuration::nanos|` is guaranteed to be less than 1 second. So
931        // we can skip the div and modulus operations.
932
933        // When |nanos| exceeds 1 second, we balance the excess up to seconds.
934        if nanos != 0 {
935            if nanos >= NANOS_PER_SEC {
936                nanos -= NANOS_PER_SEC;
937                secs = match secs.checked_add(1) {
938                    None => return None,
939                    Some(secs) => secs,
940                };
941            } else if nanos <= -NANOS_PER_SEC {
942                nanos += NANOS_PER_SEC;
943                secs = match secs.checked_sub(1) {
944                    None => return None,
945                    Some(secs) => secs,
946                };
947            }
948            if secs != 0
949                && nanos != 0
950                && secs.signum() != (nanos.signum() as i64)
951            {
952                if secs < 0 {
953                    debug_assert!(nanos > 0);
954                    // OK because secs<0.
955                    secs += 1;
956                    // OK because nanos>0.
957                    nanos -= NANOS_PER_SEC;
958                } else {
959                    debug_assert!(secs > 0);
960                    debug_assert!(nanos < 0);
961                    // OK because secs>0.
962                    secs -= 1;
963                    // OK because nanos<0.
964                    nanos += NANOS_PER_SEC;
965                }
966            }
967        }
968        Some(SignedDuration::new_unchecked(secs, nanos))
969    }
970
971    /// Add two signed durations together. If overflow occurs, then arithmetic
972    /// saturates.
973    ///
974    /// # Example
975    ///
976    /// ```
977    /// use jiff::SignedDuration;
978    ///
979    /// let duration1 = SignedDuration::MAX;
980    /// let duration2 = SignedDuration::new(0, 1);
981    /// assert_eq!(duration1.saturating_add(duration2), SignedDuration::MAX);
982    ///
983    /// let duration1 = SignedDuration::MIN;
984    /// let duration2 = SignedDuration::new(0, -1);
985    /// assert_eq!(duration1.saturating_add(duration2), SignedDuration::MIN);
986    /// ```
987    #[inline]
988    pub const fn saturating_add(self, rhs: SignedDuration) -> SignedDuration {
989        let Some(sum) = self.checked_add(rhs) else {
990            return if rhs.is_negative() {
991                SignedDuration::MIN
992            } else {
993                SignedDuration::MAX
994            };
995        };
996        sum
997    }
998
999    /// Subtract one signed duration from another. If overflow occurs, then
1000    /// `None` is returned.
1001    ///
1002    /// # Example
1003    ///
1004    /// ```
1005    /// use jiff::SignedDuration;
1006    ///
1007    /// let duration1 = SignedDuration::new(12, 500_000_000);
1008    /// let duration2 = SignedDuration::new(0, 500_000_000);
1009    /// assert_eq!(
1010    ///     duration1.checked_sub(duration2),
1011    ///     Some(SignedDuration::new(12, 0)),
1012    /// );
1013    ///
1014    /// let duration1 = SignedDuration::MIN;
1015    /// let duration2 = SignedDuration::new(0, 1);
1016    /// assert_eq!(duration1.checked_sub(duration2), None);
1017    /// ```
1018    #[inline]
1019    pub const fn checked_sub(
1020        self,
1021        rhs: SignedDuration,
1022    ) -> Option<SignedDuration> {
1023        let Some(rhs) = rhs.checked_neg() else { return None };
1024        self.checked_add(rhs)
1025    }
1026
1027    /// Add two signed durations together. If overflow occurs, then arithmetic
1028    /// saturates.
1029    ///
1030    /// # Example
1031    ///
1032    /// ```
1033    /// use jiff::SignedDuration;
1034    ///
1035    /// let duration1 = SignedDuration::MAX;
1036    /// let duration2 = SignedDuration::new(0, -1);
1037    /// assert_eq!(duration1.saturating_sub(duration2), SignedDuration::MAX);
1038    ///
1039    /// let duration1 = SignedDuration::MIN;
1040    /// let duration2 = SignedDuration::new(0, 1);
1041    /// assert_eq!(duration1.saturating_sub(duration2), SignedDuration::MIN);
1042    /// ```
1043    #[inline]
1044    pub const fn saturating_sub(self, rhs: SignedDuration) -> SignedDuration {
1045        let Some(diff) = self.checked_sub(rhs) else {
1046            return if rhs.is_positive() {
1047                SignedDuration::MIN
1048            } else {
1049                SignedDuration::MAX
1050            };
1051        };
1052        diff
1053    }
1054
1055    /// Multiply this signed duration by an integer. If the multiplication
1056    /// overflows, then `None` is returned.
1057    ///
1058    /// # Example
1059    ///
1060    /// ```
1061    /// use jiff::SignedDuration;
1062    ///
1063    /// let duration = SignedDuration::new(12, 500_000_000);
1064    /// assert_eq!(
1065    ///     duration.checked_mul(2),
1066    ///     Some(SignedDuration::new(25, 0)),
1067    /// );
1068    /// ```
1069    #[inline]
1070    pub const fn checked_mul(self, rhs: i32) -> Option<SignedDuration> {
1071        let rhs = rhs as i64;
1072        // Multiplying any two i32 values never overflows an i64.
1073        let nanos = (self.nanos as i64) * rhs;
1074        // OK since NANOS_PER_SEC!={-1,0}.
1075        let addsecs = nanos / (NANOS_PER_SEC as i64);
1076        // OK since NANOS_PER_SEC!={-1,0}.
1077        let nanos = (nanos % (NANOS_PER_SEC as i64)) as i32;
1078        let Some(secs) = self.secs.checked_mul(rhs) else { return None };
1079        let Some(secs) = secs.checked_add(addsecs) else { return None };
1080        Some(SignedDuration::new_unchecked(secs, nanos))
1081    }
1082
1083    /// Multiply this signed duration by an integer. If the multiplication
1084    /// overflows, then the result saturates to either the minimum or maximum
1085    /// duration depending on the sign of the product.
1086    ///
1087    /// # Example
1088    ///
1089    /// ```
1090    /// use jiff::SignedDuration;
1091    ///
1092    /// let duration = SignedDuration::new(i64::MAX, 0);
1093    /// assert_eq!(duration.saturating_mul(2), SignedDuration::MAX);
1094    /// assert_eq!(duration.saturating_mul(-2), SignedDuration::MIN);
1095    ///
1096    /// let duration = SignedDuration::new(i64::MIN, 0);
1097    /// assert_eq!(duration.saturating_mul(2), SignedDuration::MIN);
1098    /// assert_eq!(duration.saturating_mul(-2), SignedDuration::MAX);
1099    /// ```
1100    #[inline]
1101    pub const fn saturating_mul(self, rhs: i32) -> SignedDuration {
1102        let Some(product) = self.checked_mul(rhs) else {
1103            let sign = (self.signum() as i64) * (rhs as i64).signum();
1104            return if sign.is_negative() {
1105                SignedDuration::MIN
1106            } else {
1107                SignedDuration::MAX
1108            };
1109        };
1110        product
1111    }
1112
1113    /// Divide this duration by an integer. If the division overflows, then
1114    /// `None` is returned.
1115    ///
1116    /// # Example
1117    ///
1118    /// ```
1119    /// use jiff::SignedDuration;
1120    ///
1121    /// let duration = SignedDuration::new(12, 500_000_000);
1122    /// assert_eq!(
1123    ///     duration.checked_div(2),
1124    ///     Some(SignedDuration::new(6, 250_000_000)),
1125    /// );
1126    /// assert_eq!(
1127    ///     duration.checked_div(-2),
1128    ///     Some(SignedDuration::new(-6, -250_000_000)),
1129    /// );
1130    ///
1131    /// let duration = SignedDuration::new(-12, -500_000_000);
1132    /// assert_eq!(
1133    ///     duration.checked_div(2),
1134    ///     Some(SignedDuration::new(-6, -250_000_000)),
1135    /// );
1136    /// assert_eq!(
1137    ///     duration.checked_div(-2),
1138    ///     Some(SignedDuration::new(6, 250_000_000)),
1139    /// );
1140    /// ```
1141    #[inline]
1142    pub const fn checked_div(self, rhs: i32) -> Option<SignedDuration> {
1143        if rhs == 0 || (self.secs == i64::MIN && rhs == -1) {
1144            return None;
1145        }
1146        // OK since rhs!={-1,0}.
1147        let secs = self.secs / (rhs as i64);
1148        // OK since rhs!={-1,0}.
1149        let addsecs = self.secs % (rhs as i64);
1150        // OK since rhs!=0 and self.nanos>i32::MIN.
1151        let mut nanos = self.nanos / rhs;
1152        // OK since rhs!=0 and self.nanos>i32::MIN.
1153        let addnanos = self.nanos % rhs;
1154        let leftover_nanos =
1155            (addsecs * (NANOS_PER_SEC as i64)) + (addnanos as i64);
1156        nanos += (leftover_nanos / (rhs as i64)) as i32;
1157        debug_assert!(nanos < NANOS_PER_SEC);
1158        Some(SignedDuration::new_unchecked(secs, nanos))
1159    }
1160
1161    /// Returns the number of seconds, with a possible fractional nanosecond
1162    /// component, represented by this signed duration as a 64-bit float.
1163    ///
1164    /// # Example
1165    ///
1166    /// ```
1167    /// use jiff::SignedDuration;
1168    ///
1169    /// let duration = SignedDuration::new(12, 123_456_789);
1170    /// assert_eq!(duration.as_secs_f64(), 12.123456789);
1171    ///
1172    /// let duration = SignedDuration::new(-12, -123_456_789);
1173    /// assert_eq!(duration.as_secs_f64(), -12.123456789);
1174    /// ```
1175    #[inline]
1176    pub fn as_secs_f64(&self) -> f64 {
1177        (self.secs as f64) + ((self.nanos as f64) / (NANOS_PER_SEC as f64))
1178    }
1179
1180    /// Returns the number of seconds, with a possible fractional nanosecond
1181    /// component, represented by this signed duration as a 32-bit float.
1182    ///
1183    /// # Example
1184    ///
1185    /// ```
1186    /// use jiff::SignedDuration;
1187    ///
1188    /// let duration = SignedDuration::new(12, 123_456_789);
1189    /// assert_eq!(duration.as_secs_f32(), 12.123456789);
1190    ///
1191    /// let duration = SignedDuration::new(-12, -123_456_789);
1192    /// assert_eq!(duration.as_secs_f32(), -12.123456789);
1193    /// ```
1194    #[inline]
1195    pub fn as_secs_f32(&self) -> f32 {
1196        (self.secs as f32) + ((self.nanos as f32) / (NANOS_PER_SEC as f32))
1197    }
1198
1199    /// Returns the number of milliseconds, with a possible fractional
1200    /// nanosecond component, represented by this signed duration as a 64-bit
1201    /// float.
1202    ///
1203    /// # Example
1204    ///
1205    /// ```
1206    /// use jiff::SignedDuration;
1207    ///
1208    /// let duration = SignedDuration::new(12, 123_456_789);
1209    /// assert_eq!(duration.as_millis_f64(), 12123.456789);
1210    ///
1211    /// let duration = SignedDuration::new(-12, -123_456_789);
1212    /// assert_eq!(duration.as_millis_f64(), -12123.456789);
1213    /// ```
1214    #[inline]
1215    pub fn as_millis_f64(&self) -> f64 {
1216        ((self.secs as f64) * (MILLIS_PER_SEC as f64))
1217            + ((self.nanos as f64) / (NANOS_PER_MILLI as f64))
1218    }
1219
1220    /// Returns the number of milliseconds, with a possible fractional
1221    /// nanosecond component, represented by this signed duration as a 32-bit
1222    /// float.
1223    ///
1224    /// # Example
1225    ///
1226    /// ```
1227    /// use jiff::SignedDuration;
1228    ///
1229    /// let duration = SignedDuration::new(12, 123_456_789);
1230    /// assert_eq!(duration.as_millis_f32(), 12123.456789);
1231    ///
1232    /// let duration = SignedDuration::new(-12, -123_456_789);
1233    /// assert_eq!(duration.as_millis_f32(), -12123.456789);
1234    /// ```
1235    #[inline]
1236    pub fn as_millis_f32(&self) -> f32 {
1237        ((self.secs as f32) * (MILLIS_PER_SEC as f32))
1238            + ((self.nanos as f32) / (NANOS_PER_MILLI as f32))
1239    }
1240
1241    /// Returns a signed duration corresponding to the number of seconds
1242    /// represented as a 64-bit float. The number given may have a fractional
1243    /// nanosecond component.
1244    ///
1245    /// # Panics
1246    ///
1247    /// If the given float overflows the minimum or maximum signed duration
1248    /// values, then this panics.
1249    ///
1250    /// # Example
1251    ///
1252    /// ```
1253    /// use jiff::SignedDuration;
1254    ///
1255    /// let duration = SignedDuration::from_secs_f64(12.123456789);
1256    /// assert_eq!(duration.as_secs(), 12);
1257    /// assert_eq!(duration.subsec_nanos(), 123_456_789);
1258    ///
1259    /// let duration = SignedDuration::from_secs_f64(-12.123456789);
1260    /// assert_eq!(duration.as_secs(), -12);
1261    /// assert_eq!(duration.subsec_nanos(), -123_456_789);
1262    ///
1263    /// # Ok::<(), Box<dyn std::error::Error>>(())
1264    /// ```
1265    #[inline]
1266    pub fn from_secs_f64(secs: f64) -> SignedDuration {
1267        SignedDuration::try_from_secs_f64(secs)
1268            .expect("finite and in-bounds f64")
1269    }
1270
1271    /// Returns a signed duration corresponding to the number of seconds
1272    /// represented as a 32-bit float. The number given may have a fractional
1273    /// nanosecond component.
1274    ///
1275    /// # Panics
1276    ///
1277    /// If the given float overflows the minimum or maximum signed duration
1278    /// values, then this panics.
1279    ///
1280    /// # Example
1281    ///
1282    /// ```
1283    /// use jiff::SignedDuration;
1284    ///
1285    /// let duration = SignedDuration::from_secs_f32(12.123456789);
1286    /// assert_eq!(duration.as_secs(), 12);
1287    /// // loss of precision!
1288    /// assert_eq!(duration.subsec_nanos(), 123_456_952);
1289    ///
1290    /// let duration = SignedDuration::from_secs_f32(-12.123456789);
1291    /// assert_eq!(duration.as_secs(), -12);
1292    /// // loss of precision!
1293    /// assert_eq!(duration.subsec_nanos(), -123_456_952);
1294    ///
1295    /// # Ok::<(), Box<dyn std::error::Error>>(())
1296    /// ```
1297    #[inline]
1298    pub fn from_secs_f32(secs: f32) -> SignedDuration {
1299        SignedDuration::try_from_secs_f32(secs)
1300            .expect("finite and in-bounds f32")
1301    }
1302
1303    /// Returns a signed duration corresponding to the number of seconds
1304    /// represented as a 64-bit float. The number given may have a fractional
1305    /// nanosecond component.
1306    ///
1307    /// If the given float overflows the minimum or maximum signed duration
1308    /// values, then an error is returned.
1309    ///
1310    /// # Example
1311    ///
1312    /// ```
1313    /// use jiff::SignedDuration;
1314    ///
1315    /// let duration = SignedDuration::try_from_secs_f64(12.123456789)?;
1316    /// assert_eq!(duration.as_secs(), 12);
1317    /// assert_eq!(duration.subsec_nanos(), 123_456_789);
1318    ///
1319    /// let duration = SignedDuration::try_from_secs_f64(-12.123456789)?;
1320    /// assert_eq!(duration.as_secs(), -12);
1321    /// assert_eq!(duration.subsec_nanos(), -123_456_789);
1322    ///
1323    /// assert!(SignedDuration::try_from_secs_f64(f64::NAN).is_err());
1324    /// assert!(SignedDuration::try_from_secs_f64(f64::INFINITY).is_err());
1325    /// assert!(SignedDuration::try_from_secs_f64(f64::NEG_INFINITY).is_err());
1326    /// assert!(SignedDuration::try_from_secs_f64(f64::MIN).is_err());
1327    /// assert!(SignedDuration::try_from_secs_f64(f64::MAX).is_err());
1328    ///
1329    /// # Ok::<(), Box<dyn std::error::Error>>(())
1330    /// ```
1331    #[inline]
1332    pub fn try_from_secs_f64(secs: f64) -> Result<SignedDuration, Error> {
1333        if !secs.is_finite() {
1334            return Err(err!(
1335                "could not convert non-finite seconds \
1336                 {secs} to signed duration",
1337            ));
1338        }
1339        if secs < (i64::MIN as f64) {
1340            return Err(err!(
1341                "floating point seconds {secs} overflows signed duration \
1342                 minimum value of {:?}",
1343                SignedDuration::MIN,
1344            ));
1345        }
1346        if secs > (i64::MAX as f64) {
1347            return Err(err!(
1348                "floating point seconds {secs} overflows signed duration \
1349                 maximum value of {:?}",
1350                SignedDuration::MAX,
1351            ));
1352        }
1353        let nanos = (secs.fract() * (NANOS_PER_SEC as f64)).round() as i32;
1354        let secs = secs.trunc() as i64;
1355        Ok(SignedDuration::new_unchecked(secs, nanos))
1356    }
1357
1358    /// Returns a signed duration corresponding to the number of seconds
1359    /// represented as a 32-bit float. The number given may have a fractional
1360    /// nanosecond component.
1361    ///
1362    /// If the given float overflows the minimum or maximum signed duration
1363    /// values, then an error is returned.
1364    ///
1365    /// # Example
1366    ///
1367    /// ```
1368    /// use jiff::SignedDuration;
1369    ///
1370    /// let duration = SignedDuration::try_from_secs_f32(12.123456789)?;
1371    /// assert_eq!(duration.as_secs(), 12);
1372    /// // loss of precision!
1373    /// assert_eq!(duration.subsec_nanos(), 123_456_952);
1374    ///
1375    /// let duration = SignedDuration::try_from_secs_f32(-12.123456789)?;
1376    /// assert_eq!(duration.as_secs(), -12);
1377    /// // loss of precision!
1378    /// assert_eq!(duration.subsec_nanos(), -123_456_952);
1379    ///
1380    /// assert!(SignedDuration::try_from_secs_f32(f32::NAN).is_err());
1381    /// assert!(SignedDuration::try_from_secs_f32(f32::INFINITY).is_err());
1382    /// assert!(SignedDuration::try_from_secs_f32(f32::NEG_INFINITY).is_err());
1383    /// assert!(SignedDuration::try_from_secs_f32(f32::MIN).is_err());
1384    /// assert!(SignedDuration::try_from_secs_f32(f32::MAX).is_err());
1385    ///
1386    /// # Ok::<(), Box<dyn std::error::Error>>(())
1387    /// ```
1388    #[inline]
1389    pub fn try_from_secs_f32(secs: f32) -> Result<SignedDuration, Error> {
1390        if !secs.is_finite() {
1391            return Err(err!(
1392                "could not convert non-finite seconds \
1393                 {secs} to signed duration",
1394            ));
1395        }
1396        if secs < (i64::MIN as f32) {
1397            return Err(err!(
1398                "floating point seconds {secs} overflows signed duration \
1399                 minimum value of {:?}",
1400                SignedDuration::MIN,
1401            ));
1402        }
1403        if secs > (i64::MAX as f32) {
1404            return Err(err!(
1405                "floating point seconds {secs} overflows signed duration \
1406                 maximum value of {:?}",
1407                SignedDuration::MAX,
1408            ));
1409        }
1410        let nanos = (secs.fract() * (NANOS_PER_SEC as f32)).round() as i32;
1411        let secs = secs.trunc() as i64;
1412        Ok(SignedDuration::new_unchecked(secs, nanos))
1413    }
1414
1415    /// Returns the result of multiplying this duration by the given 64-bit
1416    /// float.
1417    ///
1418    /// # Panics
1419    ///
1420    /// This panics if the result is not finite or overflows a
1421    /// `SignedDuration`.
1422    ///
1423    /// # Example
1424    ///
1425    /// ```
1426    /// use jiff::SignedDuration;
1427    ///
1428    /// let duration = SignedDuration::new(12, 300_000_000);
1429    /// assert_eq!(
1430    ///     duration.mul_f64(2.0),
1431    ///     SignedDuration::new(24, 600_000_000),
1432    /// );
1433    /// assert_eq!(
1434    ///     duration.mul_f64(-2.0),
1435    ///     SignedDuration::new(-24, -600_000_000),
1436    /// );
1437    /// ```
1438    #[inline]
1439    pub fn mul_f64(self, rhs: f64) -> SignedDuration {
1440        SignedDuration::from_secs_f64(rhs * self.as_secs_f64())
1441    }
1442
1443    /// Returns the result of multiplying this duration by the given 32-bit
1444    /// float.
1445    ///
1446    /// # Panics
1447    ///
1448    /// This panics if the result is not finite or overflows a
1449    /// `SignedDuration`.
1450    ///
1451    /// # Example
1452    ///
1453    /// ```
1454    /// use jiff::SignedDuration;
1455    ///
1456    /// let duration = SignedDuration::new(12, 300_000_000);
1457    /// assert_eq!(
1458    ///     duration.mul_f32(2.0),
1459    ///     // loss of precision!
1460    ///     SignedDuration::new(24, 600_000_384),
1461    /// );
1462    /// assert_eq!(
1463    ///     duration.mul_f32(-2.0),
1464    ///     // loss of precision!
1465    ///     SignedDuration::new(-24, -600_000_384),
1466    /// );
1467    /// ```
1468    #[inline]
1469    pub fn mul_f32(self, rhs: f32) -> SignedDuration {
1470        SignedDuration::from_secs_f32(rhs * self.as_secs_f32())
1471    }
1472
1473    /// Returns the result of dividing this duration by the given 64-bit
1474    /// float.
1475    ///
1476    /// # Panics
1477    ///
1478    /// This panics if the result is not finite or overflows a
1479    /// `SignedDuration`.
1480    ///
1481    /// # Example
1482    ///
1483    /// ```
1484    /// use jiff::SignedDuration;
1485    ///
1486    /// let duration = SignedDuration::new(12, 300_000_000);
1487    /// assert_eq!(
1488    ///     duration.div_f64(2.0),
1489    ///     SignedDuration::new(6, 150_000_000),
1490    /// );
1491    /// assert_eq!(
1492    ///     duration.div_f64(-2.0),
1493    ///     SignedDuration::new(-6, -150_000_000),
1494    /// );
1495    /// ```
1496    #[inline]
1497    pub fn div_f64(self, rhs: f64) -> SignedDuration {
1498        SignedDuration::from_secs_f64(self.as_secs_f64() / rhs)
1499    }
1500
1501    /// Returns the result of dividing this duration by the given 32-bit
1502    /// float.
1503    ///
1504    /// # Panics
1505    ///
1506    /// This panics if the result is not finite or overflows a
1507    /// `SignedDuration`.
1508    ///
1509    /// # Example
1510    ///
1511    /// ```
1512    /// use jiff::SignedDuration;
1513    ///
1514    /// let duration = SignedDuration::new(12, 300_000_000);
1515    /// assert_eq!(
1516    ///     duration.div_f32(2.0),
1517    ///     // loss of precision!
1518    ///     SignedDuration::new(6, 150_000_096),
1519    /// );
1520    /// assert_eq!(
1521    ///     duration.div_f32(-2.0),
1522    ///     // loss of precision!
1523    ///     SignedDuration::new(-6, -150_000_096),
1524    /// );
1525    /// ```
1526    #[inline]
1527    pub fn div_f32(self, rhs: f32) -> SignedDuration {
1528        SignedDuration::from_secs_f32(self.as_secs_f32() / rhs)
1529    }
1530
1531    /// Divides this signed duration by another signed duration and returns the
1532    /// corresponding 64-bit float result.
1533    ///
1534    /// # Example
1535    ///
1536    /// ```
1537    /// use jiff::SignedDuration;
1538    ///
1539    /// let duration1 = SignedDuration::new(12, 600_000_000);
1540    /// let duration2 = SignedDuration::new(6, 300_000_000);
1541    /// assert_eq!(duration1.div_duration_f64(duration2), 2.0);
1542    ///
1543    /// let duration1 = SignedDuration::new(-12, -600_000_000);
1544    /// let duration2 = SignedDuration::new(6, 300_000_000);
1545    /// assert_eq!(duration1.div_duration_f64(duration2), -2.0);
1546    ///
1547    /// let duration1 = SignedDuration::new(-12, -600_000_000);
1548    /// let duration2 = SignedDuration::new(-6, -300_000_000);
1549    /// assert_eq!(duration1.div_duration_f64(duration2), 2.0);
1550    /// ```
1551    #[inline]
1552    pub fn div_duration_f64(self, rhs: SignedDuration) -> f64 {
1553        let lhs_nanos =
1554            (self.secs as f64) * (NANOS_PER_SEC as f64) + (self.nanos as f64);
1555        let rhs_nanos =
1556            (rhs.secs as f64) * (NANOS_PER_SEC as f64) + (rhs.nanos as f64);
1557        lhs_nanos / rhs_nanos
1558    }
1559
1560    /// Divides this signed duration by another signed duration and returns the
1561    /// corresponding 32-bit float result.
1562    ///
1563    /// # Example
1564    ///
1565    /// ```
1566    /// use jiff::SignedDuration;
1567    ///
1568    /// let duration1 = SignedDuration::new(12, 600_000_000);
1569    /// let duration2 = SignedDuration::new(6, 300_000_000);
1570    /// assert_eq!(duration1.div_duration_f32(duration2), 2.0);
1571    ///
1572    /// let duration1 = SignedDuration::new(-12, -600_000_000);
1573    /// let duration2 = SignedDuration::new(6, 300_000_000);
1574    /// assert_eq!(duration1.div_duration_f32(duration2), -2.0);
1575    ///
1576    /// let duration1 = SignedDuration::new(-12, -600_000_000);
1577    /// let duration2 = SignedDuration::new(-6, -300_000_000);
1578    /// assert_eq!(duration1.div_duration_f32(duration2), 2.0);
1579    /// ```
1580    #[inline]
1581    pub fn div_duration_f32(self, rhs: SignedDuration) -> f32 {
1582        let lhs_nanos =
1583            (self.secs as f32) * (NANOS_PER_SEC as f32) + (self.nanos as f32);
1584        let rhs_nanos =
1585            (rhs.secs as f32) * (NANOS_PER_SEC as f32) + (rhs.nanos as f32);
1586        lhs_nanos / rhs_nanos
1587    }
1588}
1589
1590/// Additional APIs not found in the standard library.
1591///
1592/// In most cases, these APIs exist as a result of the fact that this duration
1593/// is signed.
1594impl SignedDuration {
1595    /// Returns the number of whole hours in this duration.
1596    ///
1597    /// The value returned is negative when the duration is negative.
1598    ///
1599    /// This does not include any fractional component corresponding to units
1600    /// less than an hour.
1601    ///
1602    /// # Example
1603    ///
1604    /// ```
1605    /// use jiff::SignedDuration;
1606    ///
1607    /// let duration = SignedDuration::new(86_400, 999_999_999);
1608    /// assert_eq!(duration.as_hours(), 24);
1609    ///
1610    /// let duration = SignedDuration::new(-86_400, -999_999_999);
1611    /// assert_eq!(duration.as_hours(), -24);
1612    /// ```
1613    #[inline]
1614    pub const fn as_hours(&self) -> i64 {
1615        self.as_secs() / (MINS_PER_HOUR * SECS_PER_MINUTE)
1616    }
1617
1618    /// Returns the number of whole minutes in this duration.
1619    ///
1620    /// The value returned is negative when the duration is negative.
1621    ///
1622    /// This does not include any fractional component corresponding to units
1623    /// less than a minute.
1624    ///
1625    /// # Example
1626    ///
1627    /// ```
1628    /// use jiff::SignedDuration;
1629    ///
1630    /// let duration = SignedDuration::new(3_600, 999_999_999);
1631    /// assert_eq!(duration.as_mins(), 60);
1632    ///
1633    /// let duration = SignedDuration::new(-3_600, -999_999_999);
1634    /// assert_eq!(duration.as_mins(), -60);
1635    /// ```
1636    #[inline]
1637    pub const fn as_mins(&self) -> i64 {
1638        self.as_secs() / SECS_PER_MINUTE
1639    }
1640
1641    /// Returns the absolute value of this signed duration.
1642    ///
1643    /// If this duration isn't negative, then this returns the original
1644    /// duration unchanged.
1645    ///
1646    /// # Panics
1647    ///
1648    /// This panics when the seconds component of this signed duration is
1649    /// equal to `i64::MIN`.
1650    ///
1651    /// # Example
1652    ///
1653    /// ```
1654    /// use jiff::SignedDuration;
1655    ///
1656    /// let duration = SignedDuration::new(1, -1_999_999_999);
1657    /// assert_eq!(duration.abs(), SignedDuration::new(0, 999_999_999));
1658    /// ```
1659    #[inline]
1660    pub const fn abs(self) -> SignedDuration {
1661        SignedDuration::new_unchecked(self.secs.abs(), self.nanos.abs())
1662    }
1663
1664    /// Returns the absolute value of this signed duration as a
1665    /// [`std::time::Duration`]. More specifically, this routine cannot
1666    /// panic because the absolute value of `SignedDuration::MIN` is
1667    /// representable in a `std::time::Duration`.
1668    ///
1669    /// # Example
1670    ///
1671    /// ```
1672    /// use std::time::Duration;
1673    ///
1674    /// use jiff::SignedDuration;
1675    ///
1676    /// let duration = SignedDuration::MIN;
1677    /// assert_eq!(
1678    ///     duration.unsigned_abs(),
1679    ///     Duration::new(i64::MIN.unsigned_abs(), 999_999_999),
1680    /// );
1681    /// ```
1682    #[inline]
1683    pub const fn unsigned_abs(self) -> Duration {
1684        Duration::new(self.secs.unsigned_abs(), self.nanos.unsigned_abs())
1685    }
1686
1687    /// Returns this duration with its sign flipped.
1688    ///
1689    /// If this duration is zero, then this returns the duration unchanged.
1690    ///
1691    /// This returns none if the negation does not exist. This occurs in
1692    /// precisely the cases when [`SignedDuration::as_secs`] is equal to
1693    /// `i64::MIN`.
1694    ///
1695    /// # Example
1696    ///
1697    /// ```
1698    /// use jiff::SignedDuration;
1699    ///
1700    /// let duration = SignedDuration::new(12, 123_456_789);
1701    /// assert_eq!(
1702    ///     duration.checked_neg(),
1703    ///     Some(SignedDuration::new(-12, -123_456_789)),
1704    /// );
1705    ///
1706    /// let duration = SignedDuration::new(-12, -123_456_789);
1707    /// assert_eq!(
1708    ///     duration.checked_neg(),
1709    ///     Some(SignedDuration::new(12, 123_456_789)),
1710    /// );
1711    ///
1712    /// // Negating the minimum seconds isn't possible.
1713    /// assert_eq!(SignedDuration::MIN.checked_neg(), None);
1714    /// ```
1715    #[inline]
1716    pub const fn checked_neg(self) -> Option<SignedDuration> {
1717        let Some(secs) = self.secs.checked_neg() else { return None };
1718        Some(SignedDuration::new_unchecked(
1719            secs,
1720            // Always OK because `-999_999_999 <= self.nanos <= 999_999_999`.
1721            -self.nanos,
1722        ))
1723    }
1724
1725    /// Returns a number that represents the sign of this duration.
1726    ///
1727    /// * When [`SignedDuration::is_zero`] is true, this returns `0`.
1728    /// * When [`SignedDuration::is_positive`] is true, this returns `1`.
1729    /// * When [`SignedDuration::is_negative`] is true, this returns `-1`.
1730    ///
1731    /// The above cases are mutually exclusive.
1732    ///
1733    /// # Example
1734    ///
1735    /// ```
1736    /// use jiff::SignedDuration;
1737    ///
1738    /// assert_eq!(0, SignedDuration::ZERO.signum());
1739    /// ```
1740    #[inline]
1741    pub const fn signum(self) -> i8 {
1742        if self.is_zero() {
1743            0
1744        } else if self.is_positive() {
1745            1
1746        } else {
1747            debug_assert!(self.is_negative());
1748            -1
1749        }
1750    }
1751
1752    /// Returns true when this duration is positive. That is, greater than
1753    /// [`SignedDuration::ZERO`].
1754    ///
1755    /// # Example
1756    ///
1757    /// ```
1758    /// use jiff::SignedDuration;
1759    ///
1760    /// let duration = SignedDuration::new(0, 1);
1761    /// assert!(duration.is_positive());
1762    /// ```
1763    #[inline]
1764    pub const fn is_positive(&self) -> bool {
1765        self.secs.is_positive() || self.nanos.is_positive()
1766    }
1767
1768    /// Returns true when this duration is negative. That is, less than
1769    /// [`SignedDuration::ZERO`].
1770    ///
1771    /// # Example
1772    ///
1773    /// ```
1774    /// use jiff::SignedDuration;
1775    ///
1776    /// let duration = SignedDuration::new(0, -1);
1777    /// assert!(duration.is_negative());
1778    /// ```
1779    #[inline]
1780    pub const fn is_negative(&self) -> bool {
1781        self.secs.is_negative() || self.nanos.is_negative()
1782    }
1783}
1784
1785/// Additional APIs for computing the duration between date and time values.
1786impl SignedDuration {
1787    pub(crate) fn zoned_until(
1788        zoned1: &Zoned,
1789        zoned2: &Zoned,
1790    ) -> SignedDuration {
1791        SignedDuration::timestamp_until(zoned1.timestamp(), zoned2.timestamp())
1792    }
1793
1794    pub(crate) fn timestamp_until(
1795        timestamp1: Timestamp,
1796        timestamp2: Timestamp,
1797    ) -> SignedDuration {
1798        // OK because all the difference between any two timestamp values can
1799        // fit into a signed duration.
1800        timestamp2.as_duration() - timestamp1.as_duration()
1801    }
1802
1803    pub(crate) fn datetime_until(
1804        datetime1: DateTime,
1805        datetime2: DateTime,
1806    ) -> SignedDuration {
1807        let date_until =
1808            SignedDuration::date_until(datetime1.date(), datetime2.date());
1809        let time_until =
1810            SignedDuration::time_until(datetime1.time(), datetime2.time());
1811        // OK because the difference between any two datetimes can bit into a
1812        // 96-bit integer of nanoseconds.
1813        date_until + time_until
1814    }
1815
1816    pub(crate) fn date_until(date1: Date, date2: Date) -> SignedDuration {
1817        let days = date1.until_days_ranged(date2);
1818        // OK because difference in days fits in an i32, and multiplying an
1819        // i32 by 24 will never overflow an i64.
1820        let hours = 24 * i64::from(days.get());
1821        SignedDuration::from_hours(hours)
1822    }
1823
1824    pub(crate) fn time_until(time1: Time, time2: Time) -> SignedDuration {
1825        let nanos = time1.until_nanoseconds(time2);
1826        SignedDuration::from_nanos(nanos.get())
1827    }
1828
1829    pub(crate) fn offset_until(
1830        offset1: Offset,
1831        offset2: Offset,
1832    ) -> SignedDuration {
1833        let secs1 = i64::from(offset1.seconds());
1834        let secs2 = i64::from(offset2.seconds());
1835        // OK because subtracting any two i32 values will
1836        // never overflow an i64.
1837        let diff = secs2 - secs1;
1838        SignedDuration::from_secs(diff)
1839    }
1840
1841    /// Returns the duration from `time1` until `time2` where the times are
1842    /// [`std::time::SystemTime`] values from the standard library.
1843    ///
1844    /// # Errors
1845    ///
1846    /// This returns an error if the difference between the two time values
1847    /// overflows the signed duration limits.
1848    ///
1849    /// # Example
1850    ///
1851    /// ```
1852    /// use std::time::{Duration, SystemTime};
1853    /// use jiff::SignedDuration;
1854    ///
1855    /// let time1 = SystemTime::UNIX_EPOCH;
1856    /// let time2 = time1.checked_add(Duration::from_secs(86_400)).unwrap();
1857    /// assert_eq!(
1858    ///     SignedDuration::system_until(time1, time2)?,
1859    ///     SignedDuration::from_hours(24),
1860    /// );
1861    ///
1862    /// # Ok::<(), Box<dyn std::error::Error>>(())
1863    /// ```
1864    #[cfg(feature = "std")]
1865    #[inline]
1866    pub fn system_until(
1867        time1: std::time::SystemTime,
1868        time2: std::time::SystemTime,
1869    ) -> Result<SignedDuration, Error> {
1870        match time2.duration_since(time1) {
1871            Ok(dur) => SignedDuration::try_from(dur).with_context(|| {
1872                err!(
1873                    "unsigned duration {dur:?} for system time since \
1874                     Unix epoch overflowed signed duration"
1875                )
1876            }),
1877            Err(err) => {
1878                let dur = err.duration();
1879                let dur =
1880                    SignedDuration::try_from(dur).with_context(|| {
1881                        err!(
1882                        "unsigned duration {dur:?} for system time before \
1883                         Unix epoch overflowed signed duration"
1884                    )
1885                    })?;
1886                dur.checked_neg().ok_or_else(|| {
1887                    err!("negating duration {dur:?} from before the Unix epoch \
1888                     overflowed signed duration")
1889                })
1890            }
1891        }
1892    }
1893}
1894
1895/// Jiff specific APIs.
1896impl SignedDuration {
1897    /// Returns a new signed duration that is rounded according to the given
1898    /// configuration.
1899    ///
1900    /// Rounding a duration has a number of parameters, all of which are
1901    /// optional. When no parameters are given, then no rounding is done, and
1902    /// the duration as given is returned. That is, it's a no-op.
1903    ///
1904    /// As is consistent with `SignedDuration` itself, rounding only supports
1905    /// time units, i.e., units of hours or smaller. If a calendar `Unit` is
1906    /// provided, then an error is returned. In order to round a duration with
1907    /// calendar units, you must use [`Span::round`](crate::Span::round) and
1908    /// provide a relative datetime.
1909    ///
1910    /// The parameters are, in brief:
1911    ///
1912    /// * [`SignedDurationRound::smallest`] sets the smallest [`Unit`] that
1913    /// is allowed to be non-zero in the duration returned. By default, it
1914    /// is set to [`Unit::Nanosecond`], i.e., no rounding occurs. When the
1915    /// smallest unit is set to something bigger than nanoseconds, then the
1916    /// non-zero units in the duration smaller than the smallest unit are used
1917    /// to determine how the duration should be rounded. For example, rounding
1918    /// `1 hour 59 minutes` to the nearest hour using the default rounding mode
1919    /// would produce `2 hours`.
1920    /// * [`SignedDurationRound::mode`] determines how to handle the remainder
1921    /// when rounding. The default is [`RoundMode::HalfExpand`], which
1922    /// corresponds to how you were likely taught to round in school.
1923    /// Alternative modes, like [`RoundMode::Trunc`], exist too. For example,
1924    /// a truncating rounding of `1 hour 59 minutes` to the nearest hour would
1925    /// produce `1 hour`.
1926    /// * [`SignedDurationRound::increment`] sets the rounding granularity to
1927    /// use for the configured smallest unit. For example, if the smallest unit
1928    /// is minutes and the increment is 5, then the duration returned will
1929    /// always have its minute units set to a multiple of `5`.
1930    ///
1931    /// # Errors
1932    ///
1933    /// In general, there are two main ways for rounding to fail: an improper
1934    /// configuration like trying to round a duration to the nearest calendar
1935    /// unit, or when overflow occurs. Overflow can occur when the duration
1936    /// would exceed the minimum or maximum `SignedDuration` values. Typically,
1937    /// this can only realistically happen if the duration before rounding is
1938    /// already close to its minimum or maximum value.
1939    ///
1940    /// # Example: round to the nearest second
1941    ///
1942    /// This shows how to round a duration to the nearest second. This might
1943    /// be useful when you want to chop off any sub-second component in a way
1944    /// that depends on how close it is (or not) to the next second.
1945    ///
1946    /// ```
1947    /// use jiff::{SignedDuration, Unit};
1948    ///
1949    /// // rounds up
1950    /// let dur = SignedDuration::new(4 * 60 * 60 + 50 * 60 + 32, 500_000_000);
1951    /// assert_eq!(
1952    ///     dur.round(Unit::Second)?,
1953    ///     SignedDuration::new(4 * 60 * 60 + 50 * 60 + 33, 0),
1954    /// );
1955    /// // rounds down
1956    /// let dur = SignedDuration::new(4 * 60 * 60 + 50 * 60 + 32, 499_999_999);
1957    /// assert_eq!(
1958    ///     dur.round(Unit::Second)?,
1959    ///     SignedDuration::new(4 * 60 * 60 + 50 * 60 + 32, 0),
1960    /// );
1961    ///
1962    /// # Ok::<(), Box<dyn std::error::Error>>(())
1963    /// ```
1964    ///
1965    /// # Example: round to the nearest half minute
1966    ///
1967    /// One can use [`SignedDurationRound::increment`] to set the rounding
1968    /// increment:
1969    ///
1970    /// ```
1971    /// use jiff::{SignedDuration, SignedDurationRound, Unit};
1972    ///
1973    /// let options = SignedDurationRound::new()
1974    ///     .smallest(Unit::Second)
1975    ///     .increment(30);
1976    ///
1977    /// // rounds up
1978    /// let dur = SignedDuration::from_secs(4 * 60 * 60 + 50 * 60 + 15);
1979    /// assert_eq!(
1980    ///     dur.round(options)?,
1981    ///     SignedDuration::from_secs(4 * 60 * 60 + 50 * 60 + 30),
1982    /// );
1983    /// // rounds down
1984    /// let dur = SignedDuration::from_secs(4 * 60 * 60 + 50 * 60 + 14);
1985    /// assert_eq!(
1986    ///     dur.round(options)?,
1987    ///     SignedDuration::from_secs(4 * 60 * 60 + 50 * 60),
1988    /// );
1989    ///
1990    /// # Ok::<(), Box<dyn std::error::Error>>(())
1991    /// ```
1992    ///
1993    /// # Example: overflow results in an error
1994    ///
1995    /// If rounding would result in a value that exceeds a `SignedDuration`'s
1996    /// minimum or maximum values, then an error occurs:
1997    ///
1998    /// ```
1999    /// use jiff::{SignedDuration, Unit};
2000    ///
2001    /// assert_eq!(
2002    ///     SignedDuration::MAX.round(Unit::Hour).unwrap_err().to_string(),
2003    ///     "rounding `2562047788015215h 30m 7s 999ms 999µs 999ns` to \
2004    ///      nearest hour in increments of 1 resulted in \
2005    ///      9223372036854777600 seconds, which does not fit into an i64 \
2006    ///      and thus overflows `SignedDuration`",
2007    /// );
2008    /// assert_eq!(
2009    ///     SignedDuration::MIN.round(Unit::Hour).unwrap_err().to_string(),
2010    ///     "rounding `2562047788015215h 30m 8s 999ms 999µs 999ns ago` to \
2011    ///      nearest hour in increments of 1 resulted in \
2012    ///      -9223372036854777600 seconds, which does not fit into an i64 \
2013    ///      and thus overflows `SignedDuration`",
2014    /// );
2015    /// ```
2016    ///
2017    /// # Example: rounding with a calendar unit results in an error
2018    ///
2019    /// ```
2020    /// use jiff::{SignedDuration, Unit};
2021    ///
2022    /// assert_eq!(
2023    ///     SignedDuration::ZERO.round(Unit::Day).unwrap_err().to_string(),
2024    ///     "rounding `SignedDuration` failed \
2025    ///      because a calendar unit of days was provided \
2026    ///      (to round by calendar units, you must use a `Span`)",
2027    /// );
2028    /// ```
2029    #[inline]
2030    pub fn round<R: Into<SignedDurationRound>>(
2031        self,
2032        options: R,
2033    ) -> Result<SignedDuration, Error> {
2034        let options: SignedDurationRound = options.into();
2035        options.round(self)
2036    }
2037}
2038
2039impl core::fmt::Display for SignedDuration {
2040    #[inline]
2041    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2042        use crate::fmt::StdFmtWrite;
2043
2044        if f.alternate() {
2045            friendly::DEFAULT_SPAN_PRINTER
2046                .print_duration(self, StdFmtWrite(f))
2047                .map_err(|_| core::fmt::Error)
2048        } else {
2049            temporal::DEFAULT_SPAN_PRINTER
2050                .print_duration(self, StdFmtWrite(f))
2051                .map_err(|_| core::fmt::Error)
2052        }
2053    }
2054}
2055
2056impl core::fmt::Debug for SignedDuration {
2057    #[inline]
2058    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2059        use crate::fmt::StdFmtWrite;
2060
2061        friendly::DEFAULT_SPAN_PRINTER
2062            .print_duration(self, StdFmtWrite(f))
2063            .map_err(|_| core::fmt::Error)
2064    }
2065}
2066
2067impl TryFrom<Duration> for SignedDuration {
2068    type Error = Error;
2069
2070    fn try_from(d: Duration) -> Result<SignedDuration, Error> {
2071        let secs = i64::try_from(d.as_secs()).map_err(|_| {
2072            err!("seconds in unsigned duration {d:?} overflowed i64")
2073        })?;
2074        // Guaranteed to succeed since 0<=nanos<=999,999,999.
2075        let nanos = i32::try_from(d.subsec_nanos()).unwrap();
2076        Ok(SignedDuration::new_unchecked(secs, nanos))
2077    }
2078}
2079
2080impl TryFrom<SignedDuration> for Duration {
2081    type Error = Error;
2082
2083    fn try_from(sd: SignedDuration) -> Result<Duration, Error> {
2084        // This isn't needed, but improves error messages.
2085        if sd.is_negative() {
2086            return Err(err!(
2087                "cannot convert negative duration `{sd:?}` to \
2088                 unsigned `std::time::Duration`",
2089            ));
2090        }
2091        let secs = u64::try_from(sd.as_secs()).map_err(|_| {
2092            err!("seconds in signed duration {sd:?} overflowed u64")
2093        })?;
2094        // Guaranteed to succeed because the above only succeeds
2095        // when `sd` is non-negative. And when `sd` is non-negative,
2096        // we are guaranteed that 0<=nanos<=999,999,999.
2097        let nanos = u32::try_from(sd.subsec_nanos()).unwrap();
2098        Ok(Duration::new(secs, nanos))
2099    }
2100}
2101
2102impl From<Offset> for SignedDuration {
2103    fn from(offset: Offset) -> SignedDuration {
2104        SignedDuration::from_secs(i64::from(offset.seconds()))
2105    }
2106}
2107
2108impl core::str::FromStr for SignedDuration {
2109    type Err = Error;
2110
2111    #[inline]
2112    fn from_str(string: &str) -> Result<SignedDuration, Error> {
2113        parse_iso_or_friendly(string.as_bytes())
2114    }
2115}
2116
2117impl core::ops::Neg for SignedDuration {
2118    type Output = SignedDuration;
2119
2120    #[inline]
2121    fn neg(self) -> SignedDuration {
2122        self.checked_neg().expect("overflow when negating signed duration")
2123    }
2124}
2125
2126impl core::ops::Add for SignedDuration {
2127    type Output = SignedDuration;
2128
2129    #[inline]
2130    fn add(self, rhs: SignedDuration) -> SignedDuration {
2131        self.checked_add(rhs).expect("overflow when adding signed durations")
2132    }
2133}
2134
2135impl core::ops::AddAssign for SignedDuration {
2136    #[inline]
2137    fn add_assign(&mut self, rhs: SignedDuration) {
2138        *self = *self + rhs;
2139    }
2140}
2141
2142impl core::ops::Sub for SignedDuration {
2143    type Output = SignedDuration;
2144
2145    #[inline]
2146    fn sub(self, rhs: SignedDuration) -> SignedDuration {
2147        self.checked_sub(rhs)
2148            .expect("overflow when subtracting signed durations")
2149    }
2150}
2151
2152impl core::ops::SubAssign for SignedDuration {
2153    #[inline]
2154    fn sub_assign(&mut self, rhs: SignedDuration) {
2155        *self = *self - rhs;
2156    }
2157}
2158
2159impl core::ops::Mul<i32> for SignedDuration {
2160    type Output = SignedDuration;
2161
2162    #[inline]
2163    fn mul(self, rhs: i32) -> SignedDuration {
2164        self.checked_mul(rhs)
2165            .expect("overflow when multiplying signed duration by scalar")
2166    }
2167}
2168
2169impl core::ops::Mul<SignedDuration> for i32 {
2170    type Output = SignedDuration;
2171
2172    #[inline]
2173    fn mul(self, rhs: SignedDuration) -> SignedDuration {
2174        rhs * self
2175    }
2176}
2177
2178impl core::ops::MulAssign<i32> for SignedDuration {
2179    #[inline]
2180    fn mul_assign(&mut self, rhs: i32) {
2181        *self = *self * rhs;
2182    }
2183}
2184
2185impl core::ops::Div<i32> for SignedDuration {
2186    type Output = SignedDuration;
2187
2188    #[inline]
2189    fn div(self, rhs: i32) -> SignedDuration {
2190        self.checked_div(rhs)
2191            .expect("overflow when dividing signed duration by scalar")
2192    }
2193}
2194
2195impl core::ops::DivAssign<i32> for SignedDuration {
2196    #[inline]
2197    fn div_assign(&mut self, rhs: i32) {
2198        *self = *self / rhs;
2199    }
2200}
2201
2202#[cfg(feature = "serde")]
2203impl serde::Serialize for SignedDuration {
2204    #[inline]
2205    fn serialize<S: serde::Serializer>(
2206        &self,
2207        serializer: S,
2208    ) -> Result<S::Ok, S::Error> {
2209        serializer.collect_str(self)
2210    }
2211}
2212
2213#[cfg(feature = "serde")]
2214impl<'de> serde::Deserialize<'de> for SignedDuration {
2215    #[inline]
2216    fn deserialize<D: serde::Deserializer<'de>>(
2217        deserializer: D,
2218    ) -> Result<SignedDuration, D::Error> {
2219        use serde::de;
2220
2221        struct SignedDurationVisitor;
2222
2223        impl<'de> de::Visitor<'de> for SignedDurationVisitor {
2224            type Value = SignedDuration;
2225
2226            fn expecting(
2227                &self,
2228                f: &mut core::fmt::Formatter,
2229            ) -> core::fmt::Result {
2230                f.write_str("a signed duration string")
2231            }
2232
2233            #[inline]
2234            fn visit_bytes<E: de::Error>(
2235                self,
2236                value: &[u8],
2237            ) -> Result<SignedDuration, E> {
2238                parse_iso_or_friendly(value).map_err(de::Error::custom)
2239            }
2240
2241            #[inline]
2242            fn visit_str<E: de::Error>(
2243                self,
2244                value: &str,
2245            ) -> Result<SignedDuration, E> {
2246                self.visit_bytes(value.as_bytes())
2247            }
2248        }
2249
2250        deserializer.deserialize_str(SignedDurationVisitor)
2251    }
2252}
2253
2254/// Options for [`SignedDuration::round`].
2255///
2256/// This type provides a way to configure the rounding of a duration. This
2257/// includes setting the smallest unit (i.e., the unit to round), the rounding
2258/// increment and the rounding mode (e.g., "ceil" or "truncate").
2259///
2260/// `SignedDuration::round` accepts anything that implements
2261/// `Into<SignedDurationRound>`. There are a few key trait implementations that
2262/// make this convenient:
2263///
2264/// * `From<Unit> for SignedDurationRound` will construct a rounding
2265/// configuration where the smallest unit is set to the one given.
2266/// * `From<(Unit, i64)> for SignedDurationRound` will construct a rounding
2267/// configuration where the smallest unit and the rounding increment are set to
2268/// the ones given.
2269///
2270/// In order to set other options (like the rounding mode), one must explicitly
2271/// create a `SignedDurationRound` and pass it to `SignedDuration::round`.
2272///
2273/// # Example
2274///
2275/// This example shows how to always round up to the nearest half-minute:
2276///
2277/// ```
2278/// use jiff::{RoundMode, SignedDuration, SignedDurationRound, Unit};
2279///
2280/// let dur = SignedDuration::new(4 * 60 * 60 + 17 * 60 + 1, 123_456_789);
2281/// let rounded = dur.round(
2282///     SignedDurationRound::new()
2283///         .smallest(Unit::Second)
2284///         .increment(30)
2285///         .mode(RoundMode::Expand),
2286/// )?;
2287/// assert_eq!(rounded, SignedDuration::from_secs(4 * 60 * 60 + 17 * 60 + 30));
2288///
2289/// # Ok::<(), Box<dyn std::error::Error>>(())
2290/// ```
2291#[derive(Clone, Copy, Debug)]
2292pub struct SignedDurationRound {
2293    smallest: Unit,
2294    mode: RoundMode,
2295    increment: i64,
2296}
2297
2298impl SignedDurationRound {
2299    /// Create a new default configuration for rounding a signed duration via
2300    /// [`SignedDuration::round`].
2301    ///
2302    /// The default configuration does no rounding.
2303    #[inline]
2304    pub fn new() -> SignedDurationRound {
2305        SignedDurationRound {
2306            smallest: Unit::Nanosecond,
2307            mode: RoundMode::HalfExpand,
2308            increment: 1,
2309        }
2310    }
2311
2312    /// Set the smallest units allowed in the duration returned. These are the
2313    /// units that the duration is rounded to.
2314    ///
2315    /// # Errors
2316    ///
2317    /// The unit must be [`Unit::Hour`] or smaller.
2318    ///
2319    /// # Example
2320    ///
2321    /// A basic example that rounds to the nearest minute:
2322    ///
2323    /// ```
2324    /// use jiff::{SignedDuration, Unit};
2325    ///
2326    /// let duration = SignedDuration::new(15 * 60 + 46, 0);
2327    /// assert_eq!(duration.round(Unit::Minute)?, SignedDuration::from_mins(16));
2328    ///
2329    /// # Ok::<(), Box<dyn std::error::Error>>(())
2330    /// ```
2331    #[inline]
2332    pub fn smallest(self, unit: Unit) -> SignedDurationRound {
2333        SignedDurationRound { smallest: unit, ..self }
2334    }
2335
2336    /// Set the rounding mode.
2337    ///
2338    /// This defaults to [`RoundMode::HalfExpand`], which makes rounding work
2339    /// like how you were taught in school.
2340    ///
2341    /// # Example
2342    ///
2343    /// A basic example that rounds to the nearest minute, but changing its
2344    /// rounding mode to truncation:
2345    ///
2346    /// ```
2347    /// use jiff::{RoundMode, SignedDuration, SignedDurationRound, Unit};
2348    ///
2349    /// let duration = SignedDuration::new(15 * 60 + 46, 0);
2350    /// assert_eq!(
2351    ///     duration.round(SignedDurationRound::new()
2352    ///         .smallest(Unit::Minute)
2353    ///         .mode(RoundMode::Trunc),
2354    ///     )?,
2355    ///     // The default round mode does rounding like
2356    ///     // how you probably learned in school, and would
2357    ///     // result in rounding up to 16 minutes. But we
2358    ///     // change it to truncation here, which makes it
2359    ///     // round down.
2360    ///     SignedDuration::from_mins(15),
2361    /// );
2362    ///
2363    /// # Ok::<(), Box<dyn std::error::Error>>(())
2364    /// ```
2365    #[inline]
2366    pub fn mode(self, mode: RoundMode) -> SignedDurationRound {
2367        SignedDurationRound { mode, ..self }
2368    }
2369
2370    /// Set the rounding increment for the smallest unit.
2371    ///
2372    /// The default value is `1`. Other values permit rounding the smallest
2373    /// unit to the nearest integer increment specified. For example, if the
2374    /// smallest unit is set to [`Unit::Minute`], then a rounding increment of
2375    /// `30` would result in rounding in increments of a half hour. That is,
2376    /// the only minute value that could result would be `0` or `30`.
2377    ///
2378    /// # Errors
2379    ///
2380    /// The rounding increment must divide evenly into the next highest unit
2381    /// after the smallest unit configured (and must not be equivalent to it).
2382    /// For example, if the smallest unit is [`Unit::Nanosecond`], then *some*
2383    /// of the valid values for the rounding increment are `1`, `2`, `4`, `5`,
2384    /// `100` and `500`. Namely, any integer that divides evenly into `1,000`
2385    /// nanoseconds since there are `1,000` nanoseconds in the next highest
2386    /// unit (microseconds).
2387    ///
2388    /// # Example
2389    ///
2390    /// This shows how to round a duration to the nearest 5 minute increment:
2391    ///
2392    /// ```
2393    /// use jiff::{SignedDuration, Unit};
2394    ///
2395    /// let duration = SignedDuration::new(4 * 60 * 60 + 2 * 60 + 30, 0);
2396    /// assert_eq!(
2397    ///     duration.round((Unit::Minute, 5))?,
2398    ///     SignedDuration::new(4 * 60 * 60 + 5 * 60, 0),
2399    /// );
2400    ///
2401    /// # Ok::<(), Box<dyn std::error::Error>>(())
2402    /// ```
2403    #[inline]
2404    pub fn increment(self, increment: i64) -> SignedDurationRound {
2405        SignedDurationRound { increment, ..self }
2406    }
2407
2408    /// Returns the `smallest` unit configuration.
2409    pub(crate) fn get_smallest(&self) -> Unit {
2410        self.smallest
2411    }
2412
2413    /// Does the actual duration rounding.
2414    fn round(&self, dur: SignedDuration) -> Result<SignedDuration, Error> {
2415        if self.smallest > Unit::Hour {
2416            return Err(err!(
2417                "rounding `SignedDuration` failed because \
2418                 a calendar unit of {plural} was provided \
2419                 (to round by calendar units, you must use a `Span`)",
2420                plural = self.smallest.plural(),
2421            ));
2422        }
2423        let nanos = t::NoUnits128::new_unchecked(dur.as_nanos());
2424        let increment = t::NoUnits::new_unchecked(self.increment);
2425        let rounded = self.mode.round_by_unit_in_nanoseconds(
2426            nanos,
2427            self.smallest,
2428            increment,
2429        );
2430
2431        let seconds = rounded / t::NANOS_PER_SECOND;
2432        let seconds =
2433            t::NoUnits::try_rfrom("seconds", seconds).map_err(|_| {
2434                err!(
2435                    "rounding `{dur:#}` to nearest {singular} in increments \
2436                     of {increment} resulted in {seconds} seconds, which does \
2437                     not fit into an i64 and thus overflows `SignedDuration`",
2438                    singular = self.smallest.singular(),
2439                )
2440            })?;
2441        let subsec_nanos = rounded % t::NANOS_PER_SECOND;
2442        // OK because % 1_000_000_000 above guarantees that the result fits
2443        // in a i32.
2444        let subsec_nanos = i32::try_from(subsec_nanos).unwrap();
2445        Ok(SignedDuration::new(seconds.get(), subsec_nanos))
2446    }
2447}
2448
2449impl Default for SignedDurationRound {
2450    fn default() -> SignedDurationRound {
2451        SignedDurationRound::new()
2452    }
2453}
2454
2455impl From<Unit> for SignedDurationRound {
2456    fn from(unit: Unit) -> SignedDurationRound {
2457        SignedDurationRound::default().smallest(unit)
2458    }
2459}
2460
2461impl From<(Unit, i64)> for SignedDurationRound {
2462    fn from((unit, increment): (Unit, i64)) -> SignedDurationRound {
2463        SignedDurationRound::default().smallest(unit).increment(increment)
2464    }
2465}
2466
2467/// A common parsing function that works in bytes.
2468///
2469/// Specifically, this parses either an ISO 8601 duration into a
2470/// `SignedDuration` or a "friendly" duration into a `SignedDuration`. It also
2471/// tries to give decent error messages.
2472///
2473/// This works because the friendly and ISO 8601 formats have non-overlapping
2474/// prefixes. Both can start with a `+` or `-`, but aside from that, an ISO
2475/// 8601 duration _always_ has to start with a `P` or `p`. We can utilize this
2476/// property to very quickly determine how to parse the input. We just need to
2477/// handle the possibly ambiguous case with a leading sign a little carefully
2478/// in order to ensure good error messages.
2479///
2480/// (We do the same thing for `Span`.)
2481#[inline(always)]
2482fn parse_iso_or_friendly(bytes: &[u8]) -> Result<SignedDuration, Error> {
2483    if bytes.is_empty() {
2484        return Err(err!(
2485            "an empty string is not a valid `SignedDuration`, \
2486             expected either a ISO 8601 or Jiff's 'friendly' \
2487             format",
2488        ));
2489    }
2490    let mut first = bytes[0];
2491    if first == b'+' || first == b'-' {
2492        if bytes.len() == 1 {
2493            return Err(err!(
2494                "found nothing after sign `{sign}`, \
2495                 which is not a valid `SignedDuration`, \
2496                 expected either a ISO 8601 or Jiff's 'friendly' \
2497                 format",
2498                sign = escape::Byte(first),
2499            ));
2500        }
2501        first = bytes[1];
2502    }
2503    if first == b'P' || first == b'p' {
2504        temporal::DEFAULT_SPAN_PARSER.parse_duration(bytes)
2505    } else {
2506        friendly::DEFAULT_SPAN_PARSER.parse_duration(bytes)
2507    }
2508}
2509
2510#[cfg(test)]
2511mod tests {
2512    use std::io::Cursor;
2513
2514    use alloc::string::ToString;
2515
2516    use super::*;
2517
2518    #[test]
2519    fn new() {
2520        let d = SignedDuration::new(12, i32::MAX);
2521        assert_eq!(d.as_secs(), 14);
2522        assert_eq!(d.subsec_nanos(), 147_483_647);
2523
2524        let d = SignedDuration::new(-12, i32::MIN);
2525        assert_eq!(d.as_secs(), -14);
2526        assert_eq!(d.subsec_nanos(), -147_483_648);
2527
2528        let d = SignedDuration::new(i64::MAX, i32::MIN);
2529        assert_eq!(d.as_secs(), i64::MAX - 3);
2530        assert_eq!(d.subsec_nanos(), 852_516_352);
2531
2532        let d = SignedDuration::new(i64::MIN, i32::MAX);
2533        assert_eq!(d.as_secs(), i64::MIN + 3);
2534        assert_eq!(d.subsec_nanos(), -852_516_353);
2535    }
2536
2537    #[test]
2538    #[should_panic]
2539    fn new_fail_positive() {
2540        SignedDuration::new(i64::MAX, 1_000_000_000);
2541    }
2542
2543    #[test]
2544    #[should_panic]
2545    fn new_fail_negative() {
2546        SignedDuration::new(i64::MIN, -1_000_000_000);
2547    }
2548
2549    #[test]
2550    fn from_hours_limits() {
2551        let d = SignedDuration::from_hours(2_562_047_788_015_215);
2552        assert_eq!(d.as_secs(), 9223372036854774000);
2553
2554        let d = SignedDuration::from_hours(-2_562_047_788_015_215);
2555        assert_eq!(d.as_secs(), -9223372036854774000);
2556    }
2557
2558    #[test]
2559    #[should_panic]
2560    fn from_hours_fail_positive() {
2561        SignedDuration::from_hours(2_562_047_788_015_216);
2562    }
2563
2564    #[test]
2565    #[should_panic]
2566    fn from_hours_fail_negative() {
2567        SignedDuration::from_hours(-2_562_047_788_015_216);
2568    }
2569
2570    #[test]
2571    fn from_minutes_limits() {
2572        let d = SignedDuration::from_mins(153_722_867_280_912_930);
2573        assert_eq!(d.as_secs(), 9223372036854775800);
2574
2575        let d = SignedDuration::from_mins(-153_722_867_280_912_930);
2576        assert_eq!(d.as_secs(), -9223372036854775800);
2577    }
2578
2579    #[test]
2580    #[should_panic]
2581    fn from_minutes_fail_positive() {
2582        SignedDuration::from_mins(153_722_867_280_912_931);
2583    }
2584
2585    #[test]
2586    #[should_panic]
2587    fn from_minutes_fail_negative() {
2588        SignedDuration::from_mins(-153_722_867_280_912_931);
2589    }
2590
2591    #[test]
2592    fn add() {
2593        let add = |(secs1, nanos1): (i64, i32),
2594                   (secs2, nanos2): (i64, i32)|
2595         -> (i64, i32) {
2596            let d1 = SignedDuration::new(secs1, nanos1);
2597            let d2 = SignedDuration::new(secs2, nanos2);
2598            let sum = d1.checked_add(d2).unwrap();
2599            (sum.as_secs(), sum.subsec_nanos())
2600        };
2601
2602        assert_eq!(add((1, 1), (1, 1)), (2, 2));
2603        assert_eq!(add((1, 1), (-1, -1)), (0, 0));
2604        assert_eq!(add((-1, -1), (1, 1)), (0, 0));
2605        assert_eq!(add((-1, -1), (-1, -1)), (-2, -2));
2606
2607        assert_eq!(add((1, 500_000_000), (1, 500_000_000)), (3, 0));
2608        assert_eq!(add((-1, -500_000_000), (-1, -500_000_000)), (-3, 0));
2609        assert_eq!(
2610            add((5, 200_000_000), (-1, -500_000_000)),
2611            (3, 700_000_000)
2612        );
2613        assert_eq!(
2614            add((-5, -200_000_000), (1, 500_000_000)),
2615            (-3, -700_000_000)
2616        );
2617    }
2618
2619    #[test]
2620    fn add_overflow() {
2621        let add = |(secs1, nanos1): (i64, i32),
2622                   (secs2, nanos2): (i64, i32)|
2623         -> Option<(i64, i32)> {
2624            let d1 = SignedDuration::new(secs1, nanos1);
2625            let d2 = SignedDuration::new(secs2, nanos2);
2626            d1.checked_add(d2).map(|d| (d.as_secs(), d.subsec_nanos()))
2627        };
2628        assert_eq!(None, add((i64::MAX, 0), (1, 0)));
2629        assert_eq!(None, add((i64::MIN, 0), (-1, 0)));
2630        assert_eq!(None, add((i64::MAX, 1), (0, 999_999_999)));
2631        assert_eq!(None, add((i64::MIN, -1), (0, -999_999_999)));
2632    }
2633
2634    /// # `serde` deserializer compatibility test
2635    ///
2636    /// Serde YAML used to be unable to deserialize `jiff` types,
2637    /// as deserializing from bytes is not supported by the deserializer.
2638    ///
2639    /// - <https://github.com/BurntSushi/jiff/issues/138>
2640    /// - <https://github.com/BurntSushi/jiff/discussions/148>
2641    #[test]
2642    fn signed_duration_deserialize_yaml() {
2643        let expected = SignedDuration::from_secs(123456789);
2644
2645        let deserialized: SignedDuration =
2646            serde_yaml::from_str("PT34293h33m9s").unwrap();
2647
2648        assert_eq!(deserialized, expected);
2649
2650        let deserialized: SignedDuration =
2651            serde_yaml::from_slice("PT34293h33m9s".as_bytes()).unwrap();
2652
2653        assert_eq!(deserialized, expected);
2654
2655        let cursor = Cursor::new(b"PT34293h33m9s");
2656        let deserialized: SignedDuration =
2657            serde_yaml::from_reader(cursor).unwrap();
2658
2659        assert_eq!(deserialized, expected);
2660    }
2661
2662    #[test]
2663    fn from_str() {
2664        let p = |s: &str| -> Result<SignedDuration, Error> { s.parse() };
2665
2666        insta::assert_snapshot!(
2667            p("1 hour").unwrap(),
2668            @"PT1H",
2669        );
2670        insta::assert_snapshot!(
2671            p("+1 hour").unwrap(),
2672            @"PT1H",
2673        );
2674        insta::assert_snapshot!(
2675            p("-1 hour").unwrap(),
2676            @"-PT1H",
2677        );
2678        insta::assert_snapshot!(
2679            p("PT1h").unwrap(),
2680            @"PT1H",
2681        );
2682        insta::assert_snapshot!(
2683            p("+PT1h").unwrap(),
2684            @"PT1H",
2685        );
2686        insta::assert_snapshot!(
2687            p("-PT1h").unwrap(),
2688            @"-PT1H",
2689        );
2690
2691        insta::assert_snapshot!(
2692            p("").unwrap_err(),
2693            @"an empty string is not a valid `SignedDuration`, expected either a ISO 8601 or Jiff's 'friendly' format",
2694        );
2695        insta::assert_snapshot!(
2696            p("+").unwrap_err(),
2697            @"found nothing after sign `+`, which is not a valid `SignedDuration`, expected either a ISO 8601 or Jiff's 'friendly' format",
2698        );
2699        insta::assert_snapshot!(
2700            p("-").unwrap_err(),
2701            @"found nothing after sign `-`, which is not a valid `SignedDuration`, expected either a ISO 8601 or Jiff's 'friendly' format",
2702        );
2703    }
2704
2705    #[test]
2706    fn serde_deserialize() {
2707        let p = |s: &str| -> Result<SignedDuration, serde_json::Error> {
2708            serde_json::from_str(&alloc::format!("\"{s}\""))
2709        };
2710
2711        insta::assert_snapshot!(
2712            p("1 hour").unwrap(),
2713            @"PT1H",
2714        );
2715        insta::assert_snapshot!(
2716            p("+1 hour").unwrap(),
2717            @"PT1H",
2718        );
2719        insta::assert_snapshot!(
2720            p("-1 hour").unwrap(),
2721            @"-PT1H",
2722        );
2723        insta::assert_snapshot!(
2724            p("PT1h").unwrap(),
2725            @"PT1H",
2726        );
2727        insta::assert_snapshot!(
2728            p("+PT1h").unwrap(),
2729            @"PT1H",
2730        );
2731        insta::assert_snapshot!(
2732            p("-PT1h").unwrap(),
2733            @"-PT1H",
2734        );
2735
2736        insta::assert_snapshot!(
2737            p("").unwrap_err(),
2738            @"an empty string is not a valid `SignedDuration`, expected either a ISO 8601 or Jiff's 'friendly' format at line 1 column 2",
2739        );
2740        insta::assert_snapshot!(
2741            p("+").unwrap_err(),
2742            @"found nothing after sign `+`, which is not a valid `SignedDuration`, expected either a ISO 8601 or Jiff's 'friendly' format at line 1 column 3",
2743        );
2744        insta::assert_snapshot!(
2745            p("-").unwrap_err(),
2746            @"found nothing after sign `-`, which is not a valid `SignedDuration`, expected either a ISO 8601 or Jiff's 'friendly' format at line 1 column 3",
2747        );
2748    }
2749
2750    /// This test ensures that we can parse `humantime` formatted durations.
2751    #[test]
2752    fn humantime_compatibility_parse() {
2753        let dur = std::time::Duration::new(26_784, 123_456_789);
2754        let formatted = humantime::format_duration(dur).to_string();
2755        assert_eq!(formatted, "7h 26m 24s 123ms 456us 789ns");
2756
2757        let expected = SignedDuration::try_from(dur).unwrap();
2758        assert_eq!(formatted.parse::<SignedDuration>().unwrap(), expected);
2759    }
2760
2761    /// This test ensures that we can print a `SignedDuration` that `humantime`
2762    /// can parse.
2763    ///
2764    /// Note that this isn't the default since `humantime`'s parser is
2765    /// pretty limited. e.g., It doesn't support things like `nsecs`
2766    /// despite supporting `secs`. And other reasons. See the docs on
2767    /// `Designator::HumanTime` for why we sadly provide a custom variant for
2768    /// it.
2769    #[test]
2770    fn humantime_compatibility_print() {
2771        static PRINTER: friendly::SpanPrinter = friendly::SpanPrinter::new()
2772            .designator(friendly::Designator::HumanTime);
2773
2774        let sdur = SignedDuration::new(26_784, 123_456_789);
2775        let formatted = PRINTER.duration_to_string(&sdur);
2776        assert_eq!(formatted, "7h 26m 24s 123ms 456us 789ns");
2777
2778        let dur = humantime::parse_duration(&formatted).unwrap();
2779        let expected = std::time::Duration::try_from(sdur).unwrap();
2780        assert_eq!(dur, expected);
2781    }
2782}