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