Coverage Report

Created: 2025-07-23 06:05

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