Skip to main content

jiff/
signed_duration.rs

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