Struct SignedDuration

struct SignedDuration { ... }

A signed duration of time represented as a 96-bit integer of nanoseconds.

Each duration is made up of a 64-bit integer of whole seconds and a 32-bit integer of fractional nanoseconds less than 1 whole second. Unlike std::time::Duration, this duration is signed. The sign applies to the entire duration. That is, either both the seconds and the fractional nanoseconds are negative or neither are. Stated differently, it is guaranteed that the signs of SignedDuration::as_secs and SignedDuration::subsec_nanos are always the same, or one component is zero. (For example, -1 seconds and 0 nanoseconds, or 0 seconds and -1 nanoseconds.)

Parsing and printing

Like the Span type, the SignedDuration type provides convenient trait implementations of std::str::FromStr and [std::fmt::Display]:

use jiff::SignedDuration;

let duration: SignedDuration = "PT2h30m".parse()?;
assert_eq!(duration.to_string(), "PT2H30M");

// Or use the "friendly" format by invoking the alternate:
assert_eq!(format!("{duration:#}"), "2h 30m");

// Parsing automatically supports both the ISO 8601 and "friendly" formats:
let duration: SignedDuration = "2h 30m".parse()?;
assert_eq!(duration, SignedDuration::new(2 * 60 * 60 + 30 * 60, 0));
let duration: SignedDuration = "2 hours, 30 minutes".parse()?;
assert_eq!(duration, SignedDuration::new(2 * 60 * 60 + 30 * 60, 0));

# Ok::<(), Box<dyn std::error::Error>>(())

Unlike the Span type, though, only uniform units are supported. This means that ISO 8601 durations with non-zero units of days or greater cannot be parsed directly into a SignedDuration:

use jiff::SignedDuration;

assert_eq!(
    "P1d".parse::<SignedDuration>().unwrap_err().to_string(),
    "failed to parse ISO 8601 duration string into `SignedDuration`: \
     parsing ISO 8601 duration into SignedDuration requires that the \
     duration contain a time component and no components of days or \
     greater",
);

# Ok::<(), Box<dyn std::error::Error>>(())

To parse such durations, one should first parse them into a Span and then convert them to a SignedDuration by providing a relative date:

use jiff::{civil::date, SignedDuration, Span};

let span: Span = "P1d".parse()?;
let relative = date(2024, 11, 3).in_tz("US/Eastern")?;
let duration = span.to_duration(&relative)?;
// This example also motivates *why* a relative date
// is required. Not all days are the same length!
assert_eq!(duration.to_string(), "PT25H");

# Ok::<(), Box<dyn std::error::Error>>(())

The format supported is a variation (nearly a subset) of the duration format specified in ISO 8601 and a Jiff-specific "friendly" format. Here are more examples:

use jiff::SignedDuration;

let durations = [
    // ISO 8601
    ("PT2H30M", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("PT2.5h", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("PT1m", SignedDuration::from_mins(1)),
    ("PT1.5m", SignedDuration::from_secs(90)),
    ("PT0.0021s", SignedDuration::new(0, 2_100_000)),
    ("PT0s", SignedDuration::ZERO),
    ("PT0.000000001s", SignedDuration::from_nanos(1)),
    // Jiff's "friendly" format
    ("2h30m", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("2 hrs 30 mins", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("2 hours 30 minutes", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("2.5h", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("1m", SignedDuration::from_mins(1)),
    ("1.5m", SignedDuration::from_secs(90)),
    ("0.0021s", SignedDuration::new(0, 2_100_000)),
    ("0s", SignedDuration::ZERO),
    ("0.000000001s", SignedDuration::from_nanos(1)),
];
for (string, duration) in durations {
    let parsed: SignedDuration = string.parse()?;
    assert_eq!(duration, parsed, "result of parsing {string:?}");
}

# Ok::<(), Box<dyn std::error::Error>>(())

For more details, see the fmt::temporal and fmt::friendly modules.

API design

A SignedDuration is, as much as is possible, a replica of the std::time::Duration API. While there are probably some quirks in the API of std::time::Duration that could have been fixed here, it is probably more important that it behave "exactly like a std::time::Duration but with a sign." That is, this type mirrors the parallels between signed and unsigned integer types.

While the goal was to match the std::time::Duration API as much as possible, there are some differences worth highlighting:

When should I use SignedDuration versus Span?

Jiff's primary duration type is Span. The key differences between it and SignedDuration are:

Those differences in turn motivate some approximate reasoning for when to use Span and when to use SignedDuration:

In general, a Span provides more functionality and is overall more flexible. A Span can also deserialize all forms of ISO 8601 durations (as long as they're within Jiff's limits), including durations with units of years, months, weeks and days. A SignedDuration, by contrast, only supports units up to and including hours.

Integration with datetime types

All datetime types that support arithmetic using Span also support arithmetic using SignedDuration (and std::time::Duration). For example, here's how to add an absolute duration to a [Timestamp]:

use jiff::{SignedDuration, Timestamp};

let ts1 = Timestamp::from_second(1_123_456_789)?;
assert_eq!(ts1.to_string(), "2005-08-07T23:19:49Z");

let duration = SignedDuration::new(59, 999_999_999);
// Timestamp::checked_add is polymorphic! It can accept a
// span or a duration.
let ts2 = ts1.checked_add(duration)?;
assert_eq!(ts2.to_string(), "2005-08-07T23:20:48.999999999Z");

# Ok::<(), Box<dyn std::error::Error>>(())

The same API pattern works with Zoned, DateTime, Date and Time.

Interaction with daylight saving time and time zone transitions

A SignedDuration always corresponds to a specific number of nanoseconds. Since a Zoned is always a precise instant in time, adding a SignedDuration to a Zoned always behaves by adding the nanoseconds from the duration to the timestamp inside of Zoned. Consider 2024-03-10 in US/Eastern. At 02:00:00, daylight saving time came into effect, switching the UTC offset for the region from -05 to -04. This has the effect of skipping an hour on the clocks:

use jiff::{civil::date, SignedDuration};

let zdt = date(2024, 3, 10).at(1, 59, 0, 0).in_tz("US/Eastern")?;
assert_eq!(
    zdt.checked_add(SignedDuration::from_hours(1))?,
    // Time on the clock skipped an hour, but in this time
    // zone, 03:59 is actually precisely 1 hour later than
    // 01:59.
    date(2024, 3, 10).at(3, 59, 0, 0).in_tz("US/Eastern")?,
);
// The same would apply if you used a `Span`:
assert_eq!(
    zdt.checked_add(jiff::Span::new().hours(1))?,
    // Time on the clock skipped an hour, but in this time
    // zone, 03:59 is actually precisely 1 hour later than
    // 01:59.
    date(2024, 3, 10).at(3, 59, 0, 0).in_tz("US/Eastern")?,
);

# Ok::<(), Box<dyn std::error::Error>>(())

Where time zones might have a more interesting effect is in the definition of the "day" itself. If, for example, you encode the notion that a day is always 24 hours into your arithmetic, you might get unexpected results. For example, let's say you want to find the datetime precisely one week after 2024-03-08T17:00 in the US/Eastern time zone. You might be tempted to just ask for the time that is 7 * 24 hours later:

use jiff::{civil::date, SignedDuration};

let zdt = date(2024, 3, 8).at(17, 0, 0, 0).in_tz("US/Eastern")?;
assert_eq!(
    zdt.checked_add(SignedDuration::from_hours(7 * 24))?,
    date(2024, 3, 15).at(18, 0, 0, 0).in_tz("US/Eastern")?,
);

# Ok::<(), Box<dyn std::error::Error>>(())

Notice that you get 18:00 and not 17:00! That's because, as shown in the previous example, 2024-03-10 was only 23 hours long. That in turn implies that the week starting from 2024-03-08 is only 7 * 24 - 1 hours long. This can be tricky to get correct with absolute durations like SignedDuration, but a Span will handle this for you automatically:

use jiff::{civil::date, ToSpan};

let zdt = date(2024, 3, 8).at(17, 0, 0, 0).in_tz("US/Eastern")?;
assert_eq!(
    zdt.checked_add(1.week())?,
    // The expected time!
    date(2024, 3, 15).at(17, 0, 0, 0).in_tz("US/Eastern")?,
);

# Ok::<(), Box<dyn std::error::Error>>(())

A Span achieves this by keeping track of individual units. Unlike a SignedDuration, it is not just a simple count of nanoseconds. It is a "bag" of individual units, and the arithmetic operations defined on a Span for Zoned know how to interpret "day" in a particular time zone at a particular instant in time.

With that said, the above does not mean that using a SignedDuration is always wrong. For example, if you're dealing with units of hours or lower, then all such units are uniform and so you'll always get the same results as with a Span. And using a SignedDuration can sometimes be simpler or faster.

Implementations

impl SignedDuration

const fn new(secs: i64, nanos: i32) -> SignedDuration

Creates a new SignedDuration from the given number of whole seconds and additional nanoseconds.

If the absolute value of the nanoseconds is greater than or equal to 1 second, then the excess balances into the number of whole seconds.

Panics

When the absolute value of the nanoseconds is greater than or equal to 1 second and the excess that carries over to the number of whole seconds overflows i64.

This never panics when nanos is less than 1_000_000_000.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 0);
assert_eq!(duration.as_secs(), 12);
assert_eq!(duration.subsec_nanos(), 0);

let duration = SignedDuration::new(12, -1);
assert_eq!(duration.as_secs(), 11);
assert_eq!(duration.subsec_nanos(), 999_999_999);

let duration = SignedDuration::new(12, 1_000_000_000);
assert_eq!(duration.as_secs(), 13);
assert_eq!(duration.subsec_nanos(), 0);
const fn from_secs(secs: i64) -> SignedDuration

Creates a new SignedDuration from the given number of whole seconds.

Example

use jiff::SignedDuration;

let duration = SignedDuration::from_secs(12);
assert_eq!(duration.as_secs(), 12);
assert_eq!(duration.subsec_nanos(), 0);
const fn from_millis(millis: i64) -> SignedDuration

Creates a new SignedDuration from the given number of whole milliseconds.

Note that since this accepts an i64, this method cannot be used to construct the full range of possible signed duration values. In particular, SignedDuration::as_millis returns an i128, and this may be a value that would otherwise overflow an i64.

Example

use jiff::SignedDuration;

let duration = SignedDuration::from_millis(12_456);
assert_eq!(duration.as_secs(), 12);
assert_eq!(duration.subsec_nanos(), 456_000_000);

let duration = SignedDuration::from_millis(-12_456);
assert_eq!(duration.as_secs(), -12);
assert_eq!(duration.subsec_nanos(), -456_000_000);
const fn from_micros(micros: i64) -> SignedDuration

Creates a new SignedDuration from the given number of whole microseconds.

Note that since this accepts an i64, this method cannot be used to construct the full range of possible signed duration values. In particular, SignedDuration::as_micros returns an i128, and this may be a value that would otherwise overflow an i64.

Example

use jiff::SignedDuration;

let duration = SignedDuration::from_micros(12_000_456);
assert_eq!(duration.as_secs(), 12);
assert_eq!(duration.subsec_nanos(), 456_000);

let duration = SignedDuration::from_micros(-12_000_456);
assert_eq!(duration.as_secs(), -12);
assert_eq!(duration.subsec_nanos(), -456_000);
const fn from_nanos(nanos: i64) -> SignedDuration

Creates a new SignedDuration from the given number of whole nanoseconds.

Note that since this accepts an i64, this method cannot be used to construct the full range of possible signed duration values. In particular, SignedDuration::as_nanos returns an i128, which may be a value that would otherwise overflow an i64.

Example

use jiff::SignedDuration;

let duration = SignedDuration::from_nanos(12_000_000_456);
assert_eq!(duration.as_secs(), 12);
assert_eq!(duration.subsec_nanos(), 456);

let duration = SignedDuration::from_nanos(-12_000_000_456);
assert_eq!(duration.as_secs(), -12);
assert_eq!(duration.subsec_nanos(), -456);
const fn from_hours(hours: i64) -> SignedDuration

Creates a new SignedDuration from the given number of hours. Every hour is exactly 3,600 seconds.

Panics

Panics if the number of hours, after being converted to nanoseconds, overflows the minimum or maximum SignedDuration values.

Example

use jiff::SignedDuration;

let duration = SignedDuration::from_hours(24);
assert_eq!(duration.as_secs(), 86_400);
assert_eq!(duration.subsec_nanos(), 0);

let duration = SignedDuration::from_hours(-24);
assert_eq!(duration.as_secs(), -86_400);
assert_eq!(duration.subsec_nanos(), 0);
const fn from_mins(minutes: i64) -> SignedDuration

Creates a new SignedDuration from the given number of minutes. Every minute is exactly 60 seconds.

Panics

Panics if the number of minutes, after being converted to nanoseconds, overflows the minimum or maximum SignedDuration values.

Example

use jiff::SignedDuration;

let duration = SignedDuration::from_mins(1_440);
assert_eq!(duration.as_secs(), 86_400);
assert_eq!(duration.subsec_nanos(), 0);

let duration = SignedDuration::from_mins(-1_440);
assert_eq!(duration.as_secs(), -86_400);
assert_eq!(duration.subsec_nanos(), 0);
const fn is_zero(self: &Self) -> bool

Returns true if this duration spans no time.

Example

use jiff::SignedDuration;

assert!(SignedDuration::ZERO.is_zero());
assert!(!SignedDuration::MIN.is_zero());
assert!(!SignedDuration::MAX.is_zero());
const fn as_secs(self: &Self) -> i64

Returns the number of whole seconds in this duration.

The value returned is negative when the duration is negative.

This does not include any fractional component corresponding to units less than a second. To access those, use one of the subsec methods such as SignedDuration::subsec_nanos.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 999_999_999);
assert_eq!(duration.as_secs(), 12);

let duration = SignedDuration::new(-12, -999_999_999);
assert_eq!(duration.as_secs(), -12);
const fn subsec_millis(self: &Self) -> i32

Returns the fractional part of this duration in whole milliseconds.

The value returned is negative when the duration is negative. It is guaranteed that the range of the value returned is in the inclusive range -999..=999.

To get the length of the total duration represented in milliseconds, use SignedDuration::as_millis.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(duration.subsec_millis(), 123);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(duration.subsec_millis(), -123);
const fn subsec_micros(self: &Self) -> i32

Returns the fractional part of this duration in whole microseconds.

The value returned is negative when the duration is negative. It is guaranteed that the range of the value returned is in the inclusive range -999_999..=999_999.

To get the length of the total duration represented in microseconds, use SignedDuration::as_micros.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(duration.subsec_micros(), 123_456);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(duration.subsec_micros(), -123_456);
const fn subsec_nanos(self: &Self) -> i32

Returns the fractional part of this duration in whole nanoseconds.

The value returned is negative when the duration is negative. It is guaranteed that the range of the value returned is in the inclusive range -999_999_999..=999_999_999.

To get the length of the total duration represented in nanoseconds, use SignedDuration::as_nanos.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(duration.subsec_nanos(), 123_456_789);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(duration.subsec_nanos(), -123_456_789);
const fn as_millis(self: &Self) -> i128

Returns the total duration in units of whole milliseconds.

The value returned is negative when the duration is negative.

To get only the fractional component of this duration in units of whole milliseconds, use SignedDuration::subsec_millis.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(duration.as_millis(), 12_123);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(duration.as_millis(), -12_123);
const fn as_micros(self: &Self) -> i128

Returns the total duration in units of whole microseconds.

The value returned is negative when the duration is negative.

To get only the fractional component of this duration in units of whole microseconds, use SignedDuration::subsec_micros.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(duration.as_micros(), 12_123_456);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(duration.as_micros(), -12_123_456);
const fn as_nanos(self: &Self) -> i128

Returns the total duration in units of whole nanoseconds.

The value returned is negative when the duration is negative.

To get only the fractional component of this duration in units of whole nanoseconds, use SignedDuration::subsec_nanos.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(duration.as_nanos(), 12_123_456_789);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(duration.as_nanos(), -12_123_456_789);
const fn checked_add(self: Self, rhs: SignedDuration) -> Option<SignedDuration>

Add two signed durations together. If overflow occurs, then None is returned.

Example

use jiff::SignedDuration;

let duration1 = SignedDuration::new(12, 500_000_000);
let duration2 = SignedDuration::new(0, 500_000_000);
assert_eq!(
    duration1.checked_add(duration2),
    Some(SignedDuration::new(13, 0)),
);

let duration1 = SignedDuration::MAX;
let duration2 = SignedDuration::new(0, 1);
assert_eq!(duration1.checked_add(duration2), None);
const fn saturating_add(self: Self, rhs: SignedDuration) -> SignedDuration

Add two signed durations together. If overflow occurs, then arithmetic saturates.

Example

use jiff::SignedDuration;

let duration1 = SignedDuration::MAX;
let duration2 = SignedDuration::new(0, 1);
assert_eq!(duration1.saturating_add(duration2), SignedDuration::MAX);

let duration1 = SignedDuration::MIN;
let duration2 = SignedDuration::new(0, -1);
assert_eq!(duration1.saturating_add(duration2), SignedDuration::MIN);
const fn checked_sub(self: Self, rhs: SignedDuration) -> Option<SignedDuration>

Subtract one signed duration from another. If overflow occurs, then None is returned.

Example

use jiff::SignedDuration;

let duration1 = SignedDuration::new(12, 500_000_000);
let duration2 = SignedDuration::new(0, 500_000_000);
assert_eq!(
    duration1.checked_sub(duration2),
    Some(SignedDuration::new(12, 0)),
);

let duration1 = SignedDuration::MIN;
let duration2 = SignedDuration::new(0, 1);
assert_eq!(duration1.checked_sub(duration2), None);
const fn saturating_sub(self: Self, rhs: SignedDuration) -> SignedDuration

Add two signed durations together. If overflow occurs, then arithmetic saturates.

Example

use jiff::SignedDuration;

let duration1 = SignedDuration::MAX;
let duration2 = SignedDuration::new(0, -1);
assert_eq!(duration1.saturating_sub(duration2), SignedDuration::MAX);

let duration1 = SignedDuration::MIN;
let duration2 = SignedDuration::new(0, 1);
assert_eq!(duration1.saturating_sub(duration2), SignedDuration::MIN);
const fn checked_mul(self: Self, rhs: i32) -> Option<SignedDuration>

Multiply this signed duration by an integer. If the multiplication overflows, then None is returned.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 500_000_000);
assert_eq!(
    duration.checked_mul(2),
    Some(SignedDuration::new(25, 0)),
);
const fn saturating_mul(self: Self, rhs: i32) -> SignedDuration

Multiply this signed duration by an integer. If the multiplication overflows, then the result saturates to either the minimum or maximum duration depending on the sign of the product.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(i64::MAX, 0);
assert_eq!(duration.saturating_mul(2), SignedDuration::MAX);
assert_eq!(duration.saturating_mul(-2), SignedDuration::MIN);

let duration = SignedDuration::new(i64::MIN, 0);
assert_eq!(duration.saturating_mul(2), SignedDuration::MIN);
assert_eq!(duration.saturating_mul(-2), SignedDuration::MAX);
const fn checked_div(self: Self, rhs: i32) -> Option<SignedDuration>

Divide this duration by an integer. If the division overflows, then None is returned.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 500_000_000);
assert_eq!(
    duration.checked_div(2),
    Some(SignedDuration::new(6, 250_000_000)),
);
assert_eq!(
    duration.checked_div(-2),
    Some(SignedDuration::new(-6, -250_000_000)),
);

let duration = SignedDuration::new(-12, -500_000_000);
assert_eq!(
    duration.checked_div(2),
    Some(SignedDuration::new(-6, -250_000_000)),
);
assert_eq!(
    duration.checked_div(-2),
    Some(SignedDuration::new(6, 250_000_000)),
);
fn as_secs_f64(self: &Self) -> f64

Returns the number of seconds, with a possible fractional nanosecond component, represented by this signed duration as a 64-bit float.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(duration.as_secs_f64(), 12.123456789);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(duration.as_secs_f64(), -12.123456789);
fn as_secs_f32(self: &Self) -> f32

Returns the number of seconds, with a possible fractional nanosecond component, represented by this signed duration as a 32-bit float.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(duration.as_secs_f32(), 12.123456789);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(duration.as_secs_f32(), -12.123456789);
fn as_millis_f64(self: &Self) -> f64

Returns the number of milliseconds, with a possible fractional nanosecond component, represented by this signed duration as a 64-bit float.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(duration.as_millis_f64(), 12123.456789);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(duration.as_millis_f64(), -12123.456789);
fn as_millis_f32(self: &Self) -> f32

Returns the number of milliseconds, with a possible fractional nanosecond component, represented by this signed duration as a 32-bit float.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(duration.as_millis_f32(), 12123.456789);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(duration.as_millis_f32(), -12123.456789);
fn from_secs_f64(secs: f64) -> SignedDuration

Returns a signed duration corresponding to the number of seconds represented as a 64-bit float. The number given may have a fractional nanosecond component.

Panics

If the given float overflows the minimum or maximum signed duration values, then this panics.

Example

use jiff::SignedDuration;

let duration = SignedDuration::from_secs_f64(12.123456789);
assert_eq!(duration.as_secs(), 12);
assert_eq!(duration.subsec_nanos(), 123_456_789);

let duration = SignedDuration::from_secs_f64(-12.123456789);
assert_eq!(duration.as_secs(), -12);
assert_eq!(duration.subsec_nanos(), -123_456_789);

# Ok::<(), Box<dyn std::error::Error>>(())
fn from_secs_f32(secs: f32) -> SignedDuration

Returns a signed duration corresponding to the number of seconds represented as a 32-bit float. The number given may have a fractional nanosecond component.

Panics

If the given float overflows the minimum or maximum signed duration values, then this panics.

Example

use jiff::SignedDuration;

let duration = SignedDuration::from_secs_f32(12.123456789);
assert_eq!(duration.as_secs(), 12);
// loss of precision!
assert_eq!(duration.subsec_nanos(), 123_456_952);

let duration = SignedDuration::from_secs_f32(-12.123456789);
assert_eq!(duration.as_secs(), -12);
// loss of precision!
assert_eq!(duration.subsec_nanos(), -123_456_952);

# Ok::<(), Box<dyn std::error::Error>>(())
fn try_from_secs_f64(secs: f64) -> Result<SignedDuration, Error>

Returns a signed duration corresponding to the number of seconds represented as a 64-bit float. The number given may have a fractional nanosecond component.

If the given float overflows the minimum or maximum signed duration values, then an error is returned.

Example

use jiff::SignedDuration;

let duration = SignedDuration::try_from_secs_f64(12.123456789)?;
assert_eq!(duration.as_secs(), 12);
assert_eq!(duration.subsec_nanos(), 123_456_789);

let duration = SignedDuration::try_from_secs_f64(-12.123456789)?;
assert_eq!(duration.as_secs(), -12);
assert_eq!(duration.subsec_nanos(), -123_456_789);

assert!(SignedDuration::try_from_secs_f64(f64::NAN).is_err());
assert!(SignedDuration::try_from_secs_f64(f64::INFINITY).is_err());
assert!(SignedDuration::try_from_secs_f64(f64::NEG_INFINITY).is_err());
assert!(SignedDuration::try_from_secs_f64(f64::MIN).is_err());
assert!(SignedDuration::try_from_secs_f64(f64::MAX).is_err());

# Ok::<(), Box<dyn std::error::Error>>(())
fn try_from_secs_f32(secs: f32) -> Result<SignedDuration, Error>

Returns a signed duration corresponding to the number of seconds represented as a 32-bit float. The number given may have a fractional nanosecond component.

If the given float overflows the minimum or maximum signed duration values, then an error is returned.

Example

use jiff::SignedDuration;

let duration = SignedDuration::try_from_secs_f32(12.123456789)?;
assert_eq!(duration.as_secs(), 12);
// loss of precision!
assert_eq!(duration.subsec_nanos(), 123_456_952);

let duration = SignedDuration::try_from_secs_f32(-12.123456789)?;
assert_eq!(duration.as_secs(), -12);
// loss of precision!
assert_eq!(duration.subsec_nanos(), -123_456_952);

assert!(SignedDuration::try_from_secs_f32(f32::NAN).is_err());
assert!(SignedDuration::try_from_secs_f32(f32::INFINITY).is_err());
assert!(SignedDuration::try_from_secs_f32(f32::NEG_INFINITY).is_err());
assert!(SignedDuration::try_from_secs_f32(f32::MIN).is_err());
assert!(SignedDuration::try_from_secs_f32(f32::MAX).is_err());

# Ok::<(), Box<dyn std::error::Error>>(())
fn mul_f64(self: Self, rhs: f64) -> SignedDuration

Returns the result of multiplying this duration by the given 64-bit float.

Panics

This panics if the result is not finite or overflows a SignedDuration.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 300_000_000);
assert_eq!(
    duration.mul_f64(2.0),
    SignedDuration::new(24, 600_000_000),
);
assert_eq!(
    duration.mul_f64(-2.0),
    SignedDuration::new(-24, -600_000_000),
);
fn mul_f32(self: Self, rhs: f32) -> SignedDuration

Returns the result of multiplying this duration by the given 32-bit float.

Panics

This panics if the result is not finite or overflows a SignedDuration.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 300_000_000);
assert_eq!(
    duration.mul_f32(2.0),
    // loss of precision!
    SignedDuration::new(24, 600_000_384),
);
assert_eq!(
    duration.mul_f32(-2.0),
    // loss of precision!
    SignedDuration::new(-24, -600_000_384),
);
fn div_f64(self: Self, rhs: f64) -> SignedDuration

Returns the result of dividing this duration by the given 64-bit float.

Panics

This panics if the result is not finite or overflows a SignedDuration.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 300_000_000);
assert_eq!(
    duration.div_f64(2.0),
    SignedDuration::new(6, 150_000_000),
);
assert_eq!(
    duration.div_f64(-2.0),
    SignedDuration::new(-6, -150_000_000),
);
fn div_f32(self: Self, rhs: f32) -> SignedDuration

Returns the result of dividing this duration by the given 32-bit float.

Panics

This panics if the result is not finite or overflows a SignedDuration.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 300_000_000);
assert_eq!(
    duration.div_f32(2.0),
    // loss of precision!
    SignedDuration::new(6, 150_000_096),
);
assert_eq!(
    duration.div_f32(-2.0),
    // loss of precision!
    SignedDuration::new(-6, -150_000_096),
);
fn div_duration_f64(self: Self, rhs: SignedDuration) -> f64

Divides this signed duration by another signed duration and returns the corresponding 64-bit float result.

Example

use jiff::SignedDuration;

let duration1 = SignedDuration::new(12, 600_000_000);
let duration2 = SignedDuration::new(6, 300_000_000);
assert_eq!(duration1.div_duration_f64(duration2), 2.0);

let duration1 = SignedDuration::new(-12, -600_000_000);
let duration2 = SignedDuration::new(6, 300_000_000);
assert_eq!(duration1.div_duration_f64(duration2), -2.0);

let duration1 = SignedDuration::new(-12, -600_000_000);
let duration2 = SignedDuration::new(-6, -300_000_000);
assert_eq!(duration1.div_duration_f64(duration2), 2.0);
fn div_duration_f32(self: Self, rhs: SignedDuration) -> f32

Divides this signed duration by another signed duration and returns the corresponding 32-bit float result.

Example

use jiff::SignedDuration;

let duration1 = SignedDuration::new(12, 600_000_000);
let duration2 = SignedDuration::new(6, 300_000_000);
assert_eq!(duration1.div_duration_f32(duration2), 2.0);

let duration1 = SignedDuration::new(-12, -600_000_000);
let duration2 = SignedDuration::new(6, 300_000_000);
assert_eq!(duration1.div_duration_f32(duration2), -2.0);

let duration1 = SignedDuration::new(-12, -600_000_000);
let duration2 = SignedDuration::new(-6, -300_000_000);
assert_eq!(duration1.div_duration_f32(duration2), 2.0);

impl SignedDuration

fn round<R: Into<SignedDurationRound>>(self: Self, options: R) -> Result<SignedDuration, Error>

Returns a new signed duration that is rounded according to the given configuration.

Rounding a duration has a number of parameters, all of which are optional. When no parameters are given, then no rounding is done, and the duration as given is returned. That is, it's a no-op.

As is consistent with SignedDuration itself, rounding only supports time units, i.e., units of hours or smaller. If a calendar Unit is provided, then an error is returned. In order to round a duration with calendar units, you must use Span::round and provide a relative datetime.

The parameters are, in brief:

  • SignedDurationRound::smallest sets the smallest Unit that is allowed to be non-zero in the duration returned. By default, it is set to Unit::Nanosecond, i.e., no rounding occurs. When the smallest unit is set to something bigger than nanoseconds, then the non-zero units in the duration smaller than the smallest unit are used to determine how the duration should be rounded. For example, rounding 1 hour 59 minutes to the nearest hour using the default rounding mode would produce 2 hours.
  • SignedDurationRound::mode determines how to handle the remainder when rounding. The default is RoundMode::HalfExpand, which corresponds to how you were likely taught to round in school. Alternative modes, like RoundMode::Trunc, exist too. For example, a truncating rounding of 1 hour 59 minutes to the nearest hour would produce 1 hour.
  • SignedDurationRound::increment sets the rounding granularity to use for the configured smallest unit. For example, if the smallest unit is minutes and the increment is 5, then the duration returned will always have its minute units set to a multiple of 5.

Errors

In general, there are two main ways for rounding to fail: an improper configuration like trying to round a duration to the nearest calendar unit, or when overflow occurs. Overflow can occur when the duration would exceed the minimum or maximum SignedDuration values. Typically, this can only realistically happen if the duration before rounding is already close to its minimum or maximum value.

Example: round to the nearest second

This shows how to round a duration to the nearest second. This might be useful when you want to chop off any sub-second component in a way that depends on how close it is (or not) to the next second.

use jiff::{SignedDuration, Unit};

// rounds up
let dur = SignedDuration::new(4 * 60 * 60 + 50 * 60 + 32, 500_000_000);
assert_eq!(
    dur.round(Unit::Second)?,
    SignedDuration::new(4 * 60 * 60 + 50 * 60 + 33, 0),
);
// rounds down
let dur = SignedDuration::new(4 * 60 * 60 + 50 * 60 + 32, 499_999_999);
assert_eq!(
    dur.round(Unit::Second)?,
    SignedDuration::new(4 * 60 * 60 + 50 * 60 + 32, 0),
);

# Ok::<(), Box<dyn std::error::Error>>(())

Example: round to the nearest half minute

One can use SignedDurationRound::increment to set the rounding increment:

use jiff::{SignedDuration, SignedDurationRound, Unit};

let options = SignedDurationRound::new()
    .smallest(Unit::Second)
    .increment(30);

// rounds up
let dur = SignedDuration::from_secs(4 * 60 * 60 + 50 * 60 + 15);
assert_eq!(
    dur.round(options)?,
    SignedDuration::from_secs(4 * 60 * 60 + 50 * 60 + 30),
);
// rounds down
let dur = SignedDuration::from_secs(4 * 60 * 60 + 50 * 60 + 14);
assert_eq!(
    dur.round(options)?,
    SignedDuration::from_secs(4 * 60 * 60 + 50 * 60),
);

# Ok::<(), Box<dyn std::error::Error>>(())

Example: overflow results in an error

If rounding would result in a value that exceeds a SignedDuration's minimum or maximum values, then an error occurs:

use jiff::{SignedDuration, Unit};

assert_eq!(
    SignedDuration::MAX.round(Unit::Hour).unwrap_err().to_string(),
    "rounding `2562047788015215h 30m 7s 999ms 999µs 999ns` to \
     nearest hour in increments of 1 resulted in \
     9223372036854777600 seconds, which does not fit into an i64 \
     and thus overflows `SignedDuration`",
);
assert_eq!(
    SignedDuration::MIN.round(Unit::Hour).unwrap_err().to_string(),
    "rounding `2562047788015215h 30m 8s 999ms 999µs 999ns ago` to \
     nearest hour in increments of 1 resulted in \
     -9223372036854777600 seconds, which does not fit into an i64 \
     and thus overflows `SignedDuration`",
);

Example: rounding with a calendar unit results in an error

use jiff::{SignedDuration, Unit};

assert_eq!(
    SignedDuration::ZERO.round(Unit::Day).unwrap_err().to_string(),
    "rounding `SignedDuration` failed \
     because a calendar unit of days was provided \
     (to round by calendar units, you must use a `Span`)",
);

impl SignedDuration

const fn as_hours(self: &Self) -> i64

Returns the number of whole hours in this duration.

The value returned is negative when the duration is negative.

This does not include any fractional component corresponding to units less than an hour.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(86_400, 999_999_999);
assert_eq!(duration.as_hours(), 24);

let duration = SignedDuration::new(-86_400, -999_999_999);
assert_eq!(duration.as_hours(), -24);
const fn as_mins(self: &Self) -> i64

Returns the number of whole minutes in this duration.

The value returned is negative when the duration is negative.

This does not include any fractional component corresponding to units less than a minute.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(3_600, 999_999_999);
assert_eq!(duration.as_mins(), 60);

let duration = SignedDuration::new(-3_600, -999_999_999);
assert_eq!(duration.as_mins(), -60);
const fn abs(self: Self) -> SignedDuration

Returns the absolute value of this signed duration.

If this duration isn't negative, then this returns the original duration unchanged.

Panics

This panics when the seconds component of this signed duration is equal to i64::MIN.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(1, -1_999_999_999);
assert_eq!(duration.abs(), SignedDuration::new(0, 999_999_999));
const fn unsigned_abs(self: Self) -> Duration

Returns the absolute value of this signed duration as a std::time::Duration. More specifically, this routine cannot panic because the absolute value of SignedDuration::MIN is representable in a std::time::Duration.

Example

use std::time::Duration;

use jiff::SignedDuration;

let duration = SignedDuration::MIN;
assert_eq!(
    duration.unsigned_abs(),
    Duration::new(i64::MIN.unsigned_abs(), 999_999_999),
);
const fn checked_neg(self: Self) -> Option<SignedDuration>

Returns this duration with its sign flipped.

If this duration is zero, then this returns the duration unchanged.

This returns none if the negation does not exist. This occurs in precisely the cases when SignedDuration::as_secs is equal to i64::MIN.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(12, 123_456_789);
assert_eq!(
    duration.checked_neg(),
    Some(SignedDuration::new(-12, -123_456_789)),
);

let duration = SignedDuration::new(-12, -123_456_789);
assert_eq!(
    duration.checked_neg(),
    Some(SignedDuration::new(12, 123_456_789)),
);

// Negating the minimum seconds isn't possible.
assert_eq!(SignedDuration::MIN.checked_neg(), None);
const fn signum(self: Self) -> i8

Returns a number that represents the sign of this duration.

The above cases are mutually exclusive.

Example

use jiff::SignedDuration;

assert_eq!(0, SignedDuration::ZERO.signum());
const fn is_positive(self: &Self) -> bool

Returns true when this duration is positive. That is, greater than SignedDuration::ZERO.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(0, 1);
assert!(duration.is_positive());
const fn is_negative(self: &Self) -> bool

Returns true when this duration is negative. That is, less than SignedDuration::ZERO.

Example

use jiff::SignedDuration;

let duration = SignedDuration::new(0, -1);
assert!(duration.is_negative());

impl SignedDuration

fn system_until(time1: SystemTime, time2: SystemTime) -> Result<SignedDuration, Error>

Returns the duration from time1 until time2 where the times are std::time::SystemTime values from the standard library.

Errors

This returns an error if the difference between the two time values overflows the signed duration limits.

Example

use std::time::{Duration, SystemTime};
use jiff::SignedDuration;

let time1 = SystemTime::UNIX_EPOCH;
let time2 = time1.checked_add(Duration::from_secs(86_400)).unwrap();
assert_eq!(
    SignedDuration::system_until(time1, time2)?,
    SignedDuration::from_hours(24),
);

# Ok::<(), Box<dyn std::error::Error>>(())

impl Add for SignedDuration

fn add(self: Self, rhs: SignedDuration) -> SignedDuration

impl AddAssign for SignedDuration

fn add_assign(self: &mut Self, rhs: SignedDuration)

impl Clone for SignedDuration

fn clone(self: &Self) -> SignedDuration

impl Copy for SignedDuration

impl Debug for SignedDuration

fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result

impl Default for SignedDuration

fn default() -> SignedDuration

impl Display for SignedDuration

fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result

impl Div for SignedDuration

fn div(self: Self, rhs: i32) -> SignedDuration

impl DivAssign for SignedDuration

fn div_assign(self: &mut Self, rhs: i32)

impl Eq for SignedDuration

impl Freeze for SignedDuration

impl From for SignedDuration

fn from(offset: Offset) -> SignedDuration

impl FromStr for SignedDuration

fn from_str(string: &str) -> Result<SignedDuration, Error>

impl Hash for SignedDuration

fn hash<__H: $crate::hash::Hasher>(self: &Self, state: &mut __H)

impl Mul for SignedDuration

fn mul(self: Self, rhs: i32) -> SignedDuration

impl MulAssign for SignedDuration

fn mul_assign(self: &mut Self, rhs: i32)

impl Neg for SignedDuration

fn neg(self: Self) -> SignedDuration

impl Ord for SignedDuration

fn cmp(self: &Self, other: &SignedDuration) -> Ordering

impl PartialEq for SignedDuration

fn eq(self: &Self, other: &SignedDuration) -> bool

impl PartialOrd for SignedDuration

fn partial_cmp(self: &Self, other: &SignedDuration) -> Option<Ordering>

impl RefUnwindSafe for SignedDuration

impl Send for SignedDuration

impl Serialize for SignedDuration

fn serialize<S: serde::Serializer>(self: &Self, serializer: S) -> Result<<S as >::Ok, <S as >::Error>

impl StructuralPartialEq for SignedDuration

impl Sub for SignedDuration

fn sub(self: Self, rhs: SignedDuration) -> SignedDuration

impl SubAssign for SignedDuration

fn sub_assign(self: &mut Self, rhs: SignedDuration)

impl Sync for SignedDuration

impl TryFrom for SignedDuration

fn try_from(d: Duration) -> Result<SignedDuration, Error>

impl TryFrom for SignedDuration

fn try_from(sp: Span) -> Result<SignedDuration, Error>

impl Unpin for SignedDuration

impl UnsafeUnpin for SignedDuration

impl UnwindSafe for SignedDuration

impl<'de> Deserialize for SignedDuration

fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<SignedDuration, <D as >::Error>

impl<T> Any for SignedDuration

fn type_id(self: &Self) -> TypeId

impl<T> Borrow for SignedDuration

fn borrow(self: &Self) -> &T

impl<T> BorrowMut for SignedDuration

fn borrow_mut(self: &mut Self) -> &mut T

impl<T> CloneToUninit for SignedDuration

unsafe fn clone_to_uninit(self: &Self, dest: *mut u8)

impl<T> DeserializeOwned for SignedDuration

impl<T> From for SignedDuration

fn from(t: T) -> T

Returns the argument unchanged.

impl<T> ToOwned for SignedDuration

fn to_owned(self: &Self) -> T
fn clone_into(self: &Self, target: &mut T)

impl<T> ToString for SignedDuration

fn to_string(self: &Self) -> String

impl<T, U> Into for SignedDuration

fn into(self: Self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

impl<T, U> TryFrom for SignedDuration

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

impl<T, U> TryInto for SignedDuration

fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>