rust/src/libstd/time/duration.rs

602 lines
24 KiB
Rust
Raw Normal View History

// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Temporal quantification
#![unstable(feature = "std_misc")]
use {fmt, i64};
2014-12-07 13:15:25 -06:00
use ops::{Add, Sub, Mul, Div, Neg, FnOnce};
use option::Option;
use option::Option::{Some, None};
#[allow(deprecated)] // Int
use num::Int;
use result::Result::Ok;
/// The number of nanoseconds in a microsecond.
const NANOS_PER_MICRO: i32 = 1000;
/// The number of nanoseconds in a millisecond.
const NANOS_PER_MILLI: i32 = 1000_000;
/// The number of nanoseconds in seconds.
const NANOS_PER_SEC: i32 = 1_000_000_000;
/// The number of microseconds per second.
const MICROS_PER_SEC: i64 = 1000_000;
/// The number of milliseconds per second.
const MILLIS_PER_SEC: i64 = 1000;
/// The number of seconds in a minute.
const SECS_PER_MINUTE: i64 = 60;
/// The number of seconds in an hour.
const SECS_PER_HOUR: i64 = 3600;
/// The number of (non-leap) seconds in days.
const SECS_PER_DAY: i64 = 86400;
/// The number of (non-leap) seconds in a week.
const SECS_PER_WEEK: i64 = 604800;
macro_rules! try_opt {
($e:expr) => (match $e { Some(v) => v, None => return None })
}
/// ISO 8601 time duration with nanosecond precision.
/// This also allows for the negative duration; see individual methods for details.
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
2015-01-28 07:34:18 -06:00
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Duration {
secs: i64,
nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
}
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub const MIN: Duration = Duration {
secs: i64::MIN / MILLIS_PER_SEC - 1,
nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
};
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub const MAX: Duration = Duration {
secs: i64::MAX / MILLIS_PER_SEC,
nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
};
impl Duration {
/// Makes a new `Duration` with given number of weeks.
/// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks.
2014-11-08 09:47:51 -06:00
/// Panics when the duration is out of bounds.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn weeks(weeks: i64) -> Duration {
let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds");
Duration::seconds(secs)
}
/// Makes a new `Duration` with given number of days.
/// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
2014-11-08 09:47:51 -06:00
/// Panics when the duration is out of bounds.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn days(days: i64) -> Duration {
let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds");
Duration::seconds(secs)
}
/// Makes a new `Duration` with given number of hours.
/// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
2014-11-08 09:47:51 -06:00
/// Panics when the duration is out of bounds.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn hours(hours: i64) -> Duration {
let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds");
Duration::seconds(secs)
}
/// Makes a new `Duration` with given number of minutes.
/// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
2014-11-08 09:47:51 -06:00
/// Panics when the duration is out of bounds.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn minutes(minutes: i64) -> Duration {
let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds");
Duration::seconds(secs)
}
/// Makes a new `Duration` with given number of seconds.
2014-11-08 09:47:51 -06:00
/// Panics when the duration is more than `i64::MAX` milliseconds
/// or less than `i64::MIN` milliseconds.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn seconds(seconds: i64) -> Duration {
let d = Duration { secs: seconds, nanos: 0 };
if d < MIN || d > MAX {
panic!("Duration::seconds out of bounds");
}
d
}
/// Makes a new `Duration` with given number of milliseconds.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn milliseconds(milliseconds: i64) -> Duration {
let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
let nanos = millis as i32 * NANOS_PER_MILLI;
Duration { secs: secs, nanos: nanos }
}
/// Makes a new `Duration` with given number of microseconds.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn microseconds(microseconds: i64) -> Duration {
let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
let nanos = micros as i32 * NANOS_PER_MICRO;
Duration { secs: secs, nanos: nanos }
}
/// Makes a new `Duration` with given number of nanoseconds.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn nanoseconds(nanos: i64) -> Duration {
let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64);
Duration { secs: secs, nanos: nanos as i32 }
}
/// Runs a closure, returning the duration of time it took to run the
/// closure.
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
2014-12-07 13:15:25 -06:00
pub fn span<F>(f: F) -> Duration where F: FnOnce() {
let before = super::precise_time_ns();
f();
Duration::nanoseconds((super::precise_time_ns() - before) as i64)
}
/// Returns the total number of whole weeks in the duration.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn num_weeks(&self) -> i64 {
self.num_days() / 7
}
/// Returns the total number of whole days in the duration.
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn num_days(&self) -> i64 {
self.num_seconds() / SECS_PER_DAY
}
/// Returns the total number of whole hours in the duration.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn num_hours(&self) -> i64 {
self.num_seconds() / SECS_PER_HOUR
}
/// Returns the total number of whole minutes in the duration.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn num_minutes(&self) -> i64 {
self.num_seconds() / SECS_PER_MINUTE
}
2014-08-07 20:22:31 -05:00
/// Returns the total number of whole seconds in the duration.
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn num_seconds(&self) -> i64 {
// If secs is negative, nanos should be subtracted from the duration.
if self.secs < 0 && self.nanos > 0 {
self.secs + 1
} else {
self.secs
}
}
/// Returns the number of nanoseconds such that
/// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of
/// nanoseconds in the duration.
fn nanos_mod_sec(&self) -> i32 {
if self.secs < 0 && self.nanos > 0 {
self.nanos - NANOS_PER_SEC
} else {
self.nanos
}
}
/// Returns the total number of whole milliseconds in the duration,
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn num_milliseconds(&self) -> i64 {
// A proper Duration will not overflow, because MIN and MAX are defined
// such that the range is exactly i64 milliseconds.
let secs_part = self.num_seconds() * MILLIS_PER_SEC;
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI;
secs_part + nanos_part as i64
}
/// Returns the total number of whole microseconds in the duration,
/// or `None` on overflow (exceeding 2^63 microseconds in either direction).
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn num_microseconds(&self) -> Option<i64> {
let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO;
secs_part.checked_add(nanos_part as i64)
}
/// Returns the total number of whole nanoseconds in the duration,
/// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn num_nanoseconds(&self) -> Option<i64> {
let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
let nanos_part = self.nanos_mod_sec();
secs_part.checked_add(nanos_part as i64)
}
/// Add two durations, returning `None` if overflow occurred.
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
let mut secs = try_opt!(self.secs.checked_add(rhs.secs));
let mut nanos = self.nanos + rhs.nanos;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
secs = try_opt!(secs.checked_add(1));
}
let d = Duration { secs: secs, nanos: nanos };
// Even if d is within the bounds of i64 seconds,
// it might still overflow i64 milliseconds.
if d < MIN || d > MAX { None } else { Some(d) }
}
/// Subtract two durations, returning `None` if overflow occurred.
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
let mut secs = try_opt!(self.secs.checked_sub(rhs.secs));
let mut nanos = self.nanos - rhs.nanos;
if nanos < 0 {
nanos += NANOS_PER_SEC;
secs = try_opt!(secs.checked_sub(1));
}
let d = Duration { secs: secs, nanos: nanos };
// Even if d is within the bounds of i64 seconds,
// it might still overflow i64 milliseconds.
if d < MIN || d > MAX { None } else { Some(d) }
}
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn min_value() -> Duration { MIN }
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn max_value() -> Duration { MAX }
/// A duration where the stored seconds and nanoseconds are equal to zero.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn zero() -> Duration {
Duration { secs: 0, nanos: 0 }
}
/// Returns `true` if the duration equals `Duration::zero()`.
#[inline]
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
pub fn is_zero(&self) -> bool {
self.secs == 0 && self.nanos == 0
}
}
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
2015-01-02 21:56:24 -06:00
impl Neg for Duration {
type Output = Duration;
#[inline]
fn neg(self) -> Duration {
if self.nanos == 0 {
Duration { secs: -self.secs, nanos: 0 }
} else {
Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos }
}
}
}
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
2014-12-31 14:45:13 -06:00
impl Add for Duration {
type Output = Duration;
fn add(self, rhs: Duration) -> Duration {
let mut secs = self.secs + rhs.secs;
let mut nanos = self.nanos + rhs.nanos;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
secs += 1;
}
Duration { secs: secs, nanos: nanos }
}
}
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
2014-12-31 14:45:13 -06:00
impl Sub for Duration {
type Output = Duration;
fn sub(self, rhs: Duration) -> Duration {
let mut secs = self.secs - rhs.secs;
let mut nanos = self.nanos - rhs.nanos;
if nanos < 0 {
nanos += NANOS_PER_SEC;
secs -= 1;
}
Duration { secs: secs, nanos: nanos }
}
}
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
2014-12-31 14:45:13 -06:00
impl Mul<i32> for Duration {
type Output = Duration;
fn mul(self, rhs: i32) -> Duration {
// Multiply nanoseconds as i64, because it cannot overflow that way.
let total_nanos = self.nanos as i64 * rhs as i64;
let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
let secs = self.secs * rhs as i64 + extra_secs;
Duration { secs: secs, nanos: nanos as i32 }
}
}
2015-01-29 06:41:48 -06:00
#[unstable(feature = "std_misc")]
2014-12-31 14:45:13 -06:00
impl Div<i32> for Duration {
type Output = Duration;
fn div(self, rhs: i32) -> Duration {
let mut secs = self.secs / rhs as i64;
let carry = self.secs - secs * rhs as i64;
let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64;
let mut nanos = self.nanos / rhs + extra_nanos as i32;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
secs += 1;
}
if nanos < 0 {
nanos += NANOS_PER_SEC;
secs -= 1;
}
Duration { secs: secs, nanos: nanos }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
std: Rename Show/String to Debug/Display This commit is an implementation of [RFC 565][rfc] which is a stabilization of the `std::fmt` module and the implementations of various formatting traits. Specifically, the following changes were performed: [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0565-show-string-guidelines.md * The `Show` trait is now deprecated, it was renamed to `Debug` * The `String` trait is now deprecated, it was renamed to `Display` * Many `Debug` and `Display` implementations were audited in accordance with the RFC and audited implementations now have the `#[stable]` attribute * Integers and floats no longer print a suffix * Smart pointers no longer print details that they are a smart pointer * Paths with `Debug` are now quoted and escape characters * The `unwrap` methods on `Result` now require `Display` instead of `Debug` * The `Error` trait no longer has a `detail` method and now requires that `Display` must be implemented. With the loss of `String`, this has moved into libcore. * `impl<E: Error> FromError<E> for Box<Error>` now exists * `derive(Show)` has been renamed to `derive(Debug)`. This is not currently warned about due to warnings being emitted on stage1+ While backwards compatibility is attempted to be maintained with a blanket implementation of `Display` for the old `String` trait (and the same for `Show`/`Debug`) this is still a breaking change due to primitives no longer implementing `String` as well as modifications such as `unwrap` and the `Error` trait. Most code is fairly straightforward to update with a rename or tweaks of method calls. [breaking-change] Closes #21436
2015-01-20 17:45:07 -06:00
impl fmt::Display for Duration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// technically speaking, negative duration is not valid ISO 8601,
// but we need to print it anyway.
let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
let days = abs.secs / SECS_PER_DAY;
let secs = abs.secs - days * SECS_PER_DAY;
let hasdate = days != 0;
let hastime = (secs != 0 || abs.nanos != 0) || !hasdate;
try!(write!(f, "{}P", sign));
if hasdate {
try!(write!(f, "{}D", days));
}
if hastime {
if abs.nanos == 0 {
try!(write!(f, "T{}S", secs));
} else if abs.nanos % NANOS_PER_MILLI == 0 {
try!(write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI));
} else if abs.nanos % NANOS_PER_MICRO == 0 {
try!(write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO));
} else {
try!(write!(f, "T{}.{:09}S", secs, abs.nanos));
}
}
Ok(())
}
}
// Copied from libnum
#[inline]
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
(div_floor_64(this, other), mod_floor_64(this, other))
}
#[inline]
fn div_floor_64(this: i64, other: i64) -> i64 {
match div_rem_64(this, other) {
(d, r) if (r > 0 && other < 0)
|| (r < 0 && other > 0) => d - 1,
(d, _) => d,
}
}
#[inline]
fn mod_floor_64(this: i64, other: i64) -> i64 {
match this % other {
r if (r > 0 && other < 0)
|| (r < 0 && other > 0) => r + other,
r => r,
}
}
#[inline]
fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
(this / other, this % other)
}
#[cfg(test)]
mod tests {
use super::{Duration, MIN, MAX};
use {i32, i64};
use option::Option::{Some, None};
use string::ToString;
#[test]
fn test_duration() {
assert!(Duration::seconds(1) != Duration::zero());
assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3));
assert_eq!(Duration::seconds(86399) + Duration::seconds(4),
Duration::days(1) + Duration::seconds(3));
assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000));
assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000));
assert_eq!(Duration::days(2) + Duration::seconds(86399) +
Duration::nanoseconds(1234567890),
Duration::days(3) + Duration::nanoseconds(234567890));
assert_eq!(-Duration::days(3), Duration::days(-3));
assert_eq!(-(Duration::days(3) + Duration::seconds(70)),
Duration::days(-4) + Duration::seconds(86400-70));
}
#[test]
fn test_duration_num_days() {
assert_eq!(Duration::zero().num_days(), 0);
assert_eq!(Duration::days(1).num_days(), 1);
assert_eq!(Duration::days(-1).num_days(), -1);
assert_eq!(Duration::seconds(86399).num_days(), 0);
assert_eq!(Duration::seconds(86401).num_days(), 1);
assert_eq!(Duration::seconds(-86399).num_days(), 0);
assert_eq!(Duration::seconds(-86401).num_days(), -1);
assert_eq!(Duration::days(i32::MAX as i64).num_days(), i32::MAX as i64);
assert_eq!(Duration::days(i32::MIN as i64).num_days(), i32::MIN as i64);
}
#[test]
fn test_duration_num_seconds() {
assert_eq!(Duration::zero().num_seconds(), 0);
assert_eq!(Duration::seconds(1).num_seconds(), 1);
assert_eq!(Duration::seconds(-1).num_seconds(), -1);
assert_eq!(Duration::milliseconds(999).num_seconds(), 0);
assert_eq!(Duration::milliseconds(1001).num_seconds(), 1);
assert_eq!(Duration::milliseconds(-999).num_seconds(), 0);
assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1);
}
#[test]
fn test_duration_num_milliseconds() {
assert_eq!(Duration::zero().num_milliseconds(), 0);
assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1);
assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1);
assert_eq!(Duration::microseconds(999).num_milliseconds(), 0);
assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1);
assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0);
assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1);
assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX);
assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN);
assert_eq!(MAX.num_milliseconds(), i64::MAX);
assert_eq!(MIN.num_milliseconds(), i64::MIN);
}
#[test]
fn test_duration_num_microseconds() {
assert_eq!(Duration::zero().num_microseconds(), Some(0));
assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1));
assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1));
assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0));
assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1));
assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0));
assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1));
assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX));
assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN));
assert_eq!(MAX.num_microseconds(), None);
assert_eq!(MIN.num_microseconds(), None);
// overflow checks
const MICROS_PER_DAY: i64 = 86400_000_000;
assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(),
Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY));
assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(),
Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY));
assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None);
assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), None);
}
#[test]
fn test_duration_num_nanoseconds() {
assert_eq!(Duration::zero().num_nanoseconds(), Some(0));
assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1));
assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1));
assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX));
assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN));
assert_eq!(MAX.num_nanoseconds(), None);
assert_eq!(MIN.num_nanoseconds(), None);
// overflow checks
const NANOS_PER_DAY: i64 = 86400_000_000_000;
assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY));
assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(),
Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY));
assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None);
assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None);
}
#[test]
fn test_duration_checked_ops() {
assert_eq!(Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)),
Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999)));
assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1000))
.is_none());
assert_eq!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)),
Some(Duration::milliseconds(i64::MIN)));
assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1))
.is_none());
}
#[test]
fn test_duration_mul() {
assert_eq!(Duration::zero() * i32::MAX, Duration::zero());
assert_eq!(Duration::zero() * i32::MIN, Duration::zero());
assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero());
assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1));
assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1));
assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1));
assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1));
assert_eq!(Duration::nanoseconds(30) * 333_333_333,
Duration::seconds(10) - Duration::nanoseconds(10));
assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3,
Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3));
assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3));
assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3));
}
#[test]
fn test_duration_div() {
assert_eq!(Duration::zero() / i32::MAX, Duration::zero());
assert_eq!(Duration::zero() / i32::MIN, Duration::zero());
assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789));
assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789));
assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789));
assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789));
assert_eq!(Duration::seconds(1) / 3, Duration::nanoseconds(333_333_333));
assert_eq!(Duration::seconds(4) / 3, Duration::nanoseconds(1_333_333_333));
assert_eq!(Duration::seconds(-1) / 2, Duration::milliseconds(-500));
assert_eq!(Duration::seconds(1) / -2, Duration::milliseconds(-500));
assert_eq!(Duration::seconds(-1) / -2, Duration::milliseconds(500));
assert_eq!(Duration::seconds(-4) / 3, Duration::nanoseconds(-1_333_333_333));
assert_eq!(Duration::seconds(-4) / -3, Duration::nanoseconds(1_333_333_333));
}
#[test]
fn test_duration_fmt() {
assert_eq!(Duration::zero().to_string(), "PT0S");
assert_eq!(Duration::days(42).to_string(), "P42D");
assert_eq!(Duration::days(-42).to_string(), "-P42D");
assert_eq!(Duration::seconds(42).to_string(), "PT42S");
assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S");
assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S");
assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S");
assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(),
"P7DT6.543S");
assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S");
assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S");
// the format specifier should have no effect on `Duration`
assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)),
"P1DT2.345S");
}
}