Coverage Report

Created: 2026-02-18 06:58

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