Skip to main content

jiff/
signed_duration.rs

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