// 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
use std::{fmt, i64}; use std::error::Error; use std::ops::{Add, Sub, Mul, Div, Neg, FnOnce}; use std::time::Duration as StdDuration;
/// 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;
/// ISO 8601 time duration with nanosecond precision. /// This also allows for the negative duration; see individual methods for details. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pubstruct Duration {
secs: i64,
nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
}
/// The minimum possible `Duration`: `i64::MIN` milliseconds. pubconst 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. pubconst 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. /// Panics when the duration is out of bounds. #[inline] pubfn 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. /// Panics when the duration is out of bounds. #[inline] pubfn 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. /// Panics when the duration is out of bounds. #[inline] pubfn hours(hours: i64) -> Duration { let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours out of bounds");
Duration::seconds(secs)
}
/// Makes a new `Duration` with given number of minutes. /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. /// Panics when the duration is out of bounds. #[inline] pubfn 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. /// Panics when the duration is more than `i64::MAX` milliseconds /// or less than `i64::MIN` milliseconds. #[inline] pubfn 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] pubfn 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] pubfn 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] pubfn 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. pubfn 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] pubfn num_weeks(&self) -> i64 { self.num_days() / 7
}
/// Returns the total number of whole days in the duration. pubfn num_days(&self) -> i64 { self.num_seconds() / SECS_PER_DAY
}
/// Returns the total number of whole hours in the duration. #[inline] pubfn num_hours(&self) -> i64 { self.num_seconds() / SECS_PER_HOUR
}
/// Returns the total number of whole minutes in the duration. #[inline] pubfn num_minutes(&self) -> i64 { self.num_seconds() / SECS_PER_MINUTE
}
/// Returns the total number of whole seconds in the duration. pubfn num_seconds(&self) -> i64 { // If secs is negative, nanos should be subtracted from the duration. ifself.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 { ifself.secs < 0 && self.nanos > 0 { self.nanos - NANOS_PER_SEC
} else { self.nanos
}
}
/// Returns the total number of whole milliseconds in the duration, pubfn 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<sup>63</sup> microseconds in either direction). pubfn 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<sup>63</sup> nanoseconds in either direction). pubfn 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. pubfn checked_add(&self, rhs: &Duration) -> Option<Duration> { letmut secs = try_opt!(self.secs.checked_add(rhs.secs)); letmut 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. pubfn checked_sub(&self, rhs: &Duration) -> Option<Duration> { letmut secs = try_opt!(self.secs.checked_sub(rhs.secs)); letmut 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] pubfn min_value() -> Duration { MIN }
/// The maximum possible `Duration`: `i64::MAX` milliseconds. #[inline] pubfn max_value() -> Duration { MAX }
/// A duration where the stored seconds and nanoseconds are equal to zero. #[inline] pubfn zero() -> Duration {
Duration { secs: 0, nanos: 0 }
}
/// Creates a `time::Duration` object from `std::time::Duration` /// /// This function errors when original duration is larger than the maximum /// value supported for this type. pubfn from_std(duration: StdDuration) -> Result<Duration, OutOfRangeError> { // We need to check secs as u64 before coercing to i64 if duration.as_secs() > MAX.secs as u64 { return Err(OutOfRangeError(()));
} let d = Duration {
secs: duration.as_secs() as i64,
nanos: duration.subsec_nanos() as i32,
}; if d > MAX { return Err(OutOfRangeError(()));
}
Ok(d)
}
/// Creates a `std::time::Duration` object from `time::Duration` /// /// This function errors when duration is less than zero. As standard /// library implementation is limited to non-negative values. pubfn to_std(&self) -> Result<StdDuration, OutOfRangeError> { ifself.secs < 0 { return Err(OutOfRangeError(()));
}
Ok(StdDuration::new(self.secs as u64, self.nanos as u32))
}
/// Returns the raw value of duration. #[cfg(target_env = "sgx")] pub(crate) fn raw(&self) -> (i64, i32) {
(self.secs, self.nanos)
}
}
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 }
}
}
impl Div<i32> for Duration { type Output = Duration;
fn div(self, rhs: i32) -> Duration { letmut 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; letmut 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 }
}
}
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) = ifself.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;
/// Represents error when converting `Duration` to/from a standard library /// implementation /// /// The `std::time::Duration` supports a range from zero to `u64::MAX` /// *seconds*, while this module supports signed range of up to /// `i64::MAX` of *milliseconds*. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pubstruct OutOfRangeError(());
#[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,
}
}
// the format specifier should have no effect on `Duration`
assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)), "P1DT2.345S");
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.