diff options
| author | Brian Anderson <banderson@mozilla.com> | 2014-07-28 15:54:05 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2014-08-13 11:31:47 -0700 |
| commit | 6cb2093f7496a2539e343677b6f7f5dd2fa5f091 (patch) | |
| tree | 4f559bb3d4a02f63b4f2365543bbfd0a3203791b /src/libstd | |
| parent | 18f75a9197a5b535f9804901bfefbaffe373d689 (diff) | |
| download | rust-6cb2093f7496a2539e343677b6f7f5dd2fa5f091.tar.gz rust-6cb2093f7496a2539e343677b6f7f5dd2fa5f091.zip | |
std: Update Duration from upstream
From rust-chrono 4f34003e03e259bd5cbda0cb4d35325861307cc6
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/io/timer.rs | 34 | ||||
| -rw-r--r-- | src/libstd/time.rs | 394 |
2 files changed, 328 insertions, 100 deletions
diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index ff6ae05bb49..41a0271fff2 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -22,7 +22,6 @@ use time::Duration; use io::{IoResult, IoError}; use kinds::Send; use boxed::Box; -use num::{CheckedMul, CheckedAdd}; use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback}; /// A synchronous timer object @@ -71,31 +70,16 @@ pub struct Timer { struct TimerCallback { tx: Sender<()> } -#[allow(missing_doc)] -trait DurationExtension { - fn in_ms(&self) -> u64; -} - -impl DurationExtension for Duration { - fn in_ms(&self) -> u64 { - if self.ndays() < 0 { fail!("negative duration") } - let nanos = self.nnanoseconds() as u64; - let secs = self.nseconds() as u64; - let days = self.ndays() as u64; - let nanos_in_ms = nanos / 1000; - let secs_in_ms = secs.checked_mul(&1000).expect("overflow"); - let ms_per_day = 24 * 60 * 60 * 1000; // hours/day * min/hour * sec/min * ms/sec - let days_in_ms = days.checked_mul(&ms_per_day).expect("overflow"); - let result = nanos_in_ms; - let result = result.checked_add(&secs_in_ms).expect("overflow"); - let result = result.checked_add(&(days_in_ms as u64)).expect("overflow"); - return result; - } +fn in_ms(d: Duration) -> u64 { + // FIXME: Do we really want to fail on negative duration? + let ms = d.num_milliseconds(); + if ms < 0 { fail!("negative duration") } + return ms as u64; } /// Sleep the current task for the specified duration. pub fn sleep(duration: Duration) { - sleep_ms(duration.in_ms()) + sleep_ms(in_ms(duration)) } /// Sleep the current task for `msecs` milliseconds. @@ -121,7 +105,7 @@ impl Timer { /// Note that this function will cause any other receivers for this timer to /// be invalidated (the other end will be closed). pub fn sleep(&mut self, duration: Duration) { - self.obj.sleep(duration.in_ms()); + self.obj.sleep(in_ms(duration)); } /// Blocks the current task for `msecs` milliseconds. @@ -145,7 +129,7 @@ impl Timer { /// fail. pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> { let (tx, rx) = channel(); - self.obj.oneshot(duration.in_ms(), box TimerCallback { tx: tx }); + self.obj.oneshot(in_ms(duration), box TimerCallback { tx: tx }); return rx } @@ -204,7 +188,7 @@ impl Timer { /// fail. pub fn periodic(&mut self, duration: Duration) -> Receiver<()> { let (tx, rx) = channel(); - self.obj.period(duration.in_ms(), box TimerCallback { tx: tx }); + self.obj.period(in_ms(duration), box TimerCallback { tx: tx }); return rx } diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 6e347711c1c..e51296e5b9b 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -11,28 +11,31 @@ //! Temporal quantification #![experimental] -#![allow(missing_doc)] // FIXME -use {fmt, num, i32}; +use {fmt, i32}; +use ops::{Add, Sub, Mul, Div, Neg}; use option::{Option, Some, None}; +use num; +use num::{CheckedAdd, CheckedMul, ToPrimitive}; use result::{Result, Ok, Err}; -use ops::{Neg, Add, Sub, Mul, Div}; -use num::{CheckedAdd, ToPrimitive}; -pub static MIN_DAYS: i32 = i32::MIN; -pub static MAX_DAYS: i32 = i32::MAX; +/// `Duration`'s `days` component should have no more than this value. +static MIN_DAYS: i32 = i32::MIN; +/// `Duration`'s `days` component should have no less than this value. +static MAX_DAYS: i32 = i32::MAX; + +/// The number of nanoseconds in seconds. static NANOS_PER_SEC: i32 = 1_000_000_000; +/// The number of (non-leap) seconds in days. static SECS_PER_DAY: i32 = 86400; -macro_rules! earlyexit( +macro_rules! try_opt( ($e:expr) => (match $e { Some(v) => v, None => return None }) ) -/// The representation of a span of time. -/// -/// This type has nanosecond precision, and conforms to the ISO 8601 -/// standard for Date interchange. +/// ISO 8601 time duration with nanosecond precision. +/// This also allows for the negative duration; see individual methods for details. #[deriving(PartialEq, Eq, PartialOrd, Ord)] pub struct Duration { days: i32, @@ -40,30 +43,62 @@ pub struct Duration { nanos: u32, } +/// The minimum possible `Duration`. +pub static MIN: Duration = Duration { days: MIN_DAYS, secs: 0, nanos: 0 }; +/// The maximum possible `Duration`. +pub static MAX: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 - 1, + nanos: NANOS_PER_SEC as u32 - 1 }; + impl Duration { - /// Create a new `Duration`. - pub fn new(days: i32, secs: i32, nanos: i32) -> Option<Duration> { + /// Makes a new `Duration` with given number of days, seconds and nanoseconds. + /// + /// Fails when the duration is out of bounds. + #[inline] + pub fn new(days: i32, secs: i32, nanos: i32) -> Duration { + Duration::new_opt(days, secs, nanos).expect("Duration::new out of bounds") + } + + /// Makes a new `Duration` with given number of days, seconds and nanoseconds. + /// + /// Returns `None` when the duration is out of bounds. + pub fn new_opt(days: i32, secs: i32, nanos: i32) -> Option<Duration> { let (secs_, nanos) = div_mod_floor(nanos, NANOS_PER_SEC); - let secs = earlyexit!(secs.checked_add(&secs_)); + let secs = try_opt!(secs.checked_add(&secs_)); let (days_, secs) = div_mod_floor(secs, SECS_PER_DAY); - let days = earlyexit!(days.checked_add(&days_).and_then(|v| v.to_i32())); + let days = try_opt!(days.checked_add(&days_).and_then(|v| v.to_i32())); Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) } - /// Create a new `Duration` from an integer number of weeks. + /// Makes a new `Duration` with zero seconds. + #[inline] + pub fn zero() -> Duration { + Duration { days: 0, secs: 0, nanos: 0 } + } + + /// Makes a new `Duration` with given number of weeks. + /// Equivalent to `Duration::new(weeks * 7, 0, 0)` with overflow checks. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn weeks(weeks: i32) -> Duration { - Duration::days(weeks * 7) + let days = weeks.checked_mul(&7).expect("Duration::weeks out of bounds"); + Duration::days(days) } - /// Create a new `Duration` from an integer number of days. + /// Makes a new `Duration` with given number of days. + /// Equivalent to `Duration::new(days, 0, 0)`. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn days(days: i32) -> Duration { let days = days.to_i32().expect("Duration::days out of bounds"); Duration { days: days, secs: 0, nanos: 0 } } - /// Create a new `Duration` from an integer number of hours. + /// Makes a new `Duration` with given number of hours. + /// Equivalent to `Duration::new(0, hours * 3600, 0)` with overflow checks. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn hours(hours: i32) -> Duration { let (days, hours) = div_mod_floor(hours, (SECS_PER_DAY / 3600)); @@ -71,7 +106,10 @@ impl Duration { Duration { secs: secs as u32, ..Duration::days(days) } } - /// Create a new `Duration` from an integer number of minutes. + /// Makes a new `Duration` with given number of minutes. + /// Equivalent to `Duration::new(0, mins * 60, 0)` with overflow checks. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn minutes(mins: i32) -> Duration { let (days, mins) = div_mod_floor(mins, (SECS_PER_DAY / 60)); @@ -79,14 +117,20 @@ impl Duration { Duration { secs: secs as u32, ..Duration::days(days) } } - /// Create a new `Duration` from an integer number of seconds. + /// Makes a new `Duration` with given number of seconds. + /// Equivalent to `Duration::new(0, secs, 0)`. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn seconds(secs: i32) -> Duration { let (days, secs) = div_mod_floor(secs, SECS_PER_DAY); Duration { secs: secs as u32, ..Duration::days(days) } } - /// Create a new `Duration` from an integer number of milliseconds. + /// Makes a new `Duration` with given number of milliseconds. + /// Equivalent to `Duration::new(0, 0, millis * 1_000_000)` with overflow checks. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn milliseconds(millis: i32) -> Duration { let (secs, millis) = div_mod_floor(millis, (NANOS_PER_SEC / 1_000_000)); @@ -94,7 +138,10 @@ impl Duration { Duration { nanos: nanos as u32, ..Duration::seconds(secs) } } - /// Create a new `Duration` from an integer number of microseconds. + /// Makes a new `Duration` with given number of microseconds. + /// Equivalent to `Duration::new(0, 0, micros * 1_000)` with overflow checks. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn microseconds(micros: i32) -> Duration { let (secs, micros) = div_mod_floor(micros, (NANOS_PER_SEC / 1_000)); @@ -102,32 +149,141 @@ impl Duration { Duration { nanos: nanos as u32, ..Duration::seconds(secs) } } - /// Create a new `Duration` from an integer number of nanoseconds. + /// Makes a new `Duration` with given number of nanoseconds. + /// Equivalent to `Duration::new(0, 0, nanos)`. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn nanoseconds(nanos: i32) -> Duration { let (secs, nanos) = div_mod_floor(nanos, NANOS_PER_SEC); Duration { nanos: nanos as u32, ..Duration::seconds(secs) } } - /// Return the number of whole days in the `Duration`. + /// Returns a tuple of the number of days, (non-leap) seconds and nanoseconds in the duration. + /// Note that the number of seconds and nanoseconds are always positive, + /// so that for example `-Duration::seconds(3)` has -1 days and 86,397 seconds. #[inline] - pub fn ndays(&self) -> i32 { - self.days as i32 + pub fn to_tuple(&self) -> (i32, u32, u32) { + (self.days, self.secs, self.nanos) } - /// Return the fractional number of days in the `Duration` as seconds. + /// Same as `to_tuple` but returns a tuple compatible to `to_negated_tuple`. #[inline] - pub fn nseconds(&self) -> u32 { - self.secs as u32 + fn to_tuple_64(&self) -> (i64, u32, u32) { + (self.days as i64, self.secs, self.nanos) + } + + /// Negates the duration and returns a tuple like `to_tuple`. + /// This does not overflow and thus is internally used for several methods. + fn to_negated_tuple_64(&self) -> (i64, u32, u32) { + let mut days = -(self.days as i64); + let mut secs = -(self.secs as i32); + let mut nanos = -(self.nanos as i32); + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + if secs < 0 { + secs += SECS_PER_DAY; + days -= 1; + } + (days, secs as u32, nanos as u32) } - /// Return the fractional number of seconds in the `Duration` as nanoseconds. + /// Returns the total number of whole weeks in the duration. #[inline] - pub fn nnanoseconds(&self) -> u32 { - self.nanos as u32 + pub fn num_weeks(&self) -> i32 { + self.num_days() / 7 + } + + /// Returns the total number of whole days in the duration. + pub fn num_days(&self) -> i32 { + if self.days < 0 { + let negated = -*self; + -negated.days + } else { + self.days + } + } + + /// Returns the total number of whole hours in the duration. + #[inline] + pub fn num_hours(&self) -> i64 { + self.num_seconds() / 3600 + } + + /// Returns the total number of whole minutes in the duration. + #[inline] + pub fn num_minutes(&self) -> i64 { + self.num_seconds() / 60 + } + + /// Returns the total number of (non-leap) whole seconds in the duration. + pub fn num_seconds(&self) -> i64 { + // cannot overflow, 2^32 * 86400 < 2^64 + fn secs((days, secs, _): (i64, u32, u32)) -> i64 { + days as i64 * SECS_PER_DAY as i64 + secs as i64 + } + if self.days < 0 {-secs(self.to_negated_tuple_64())} else {secs(self.to_tuple_64())} + } + + /// Returns the total number of whole milliseconds in the duration. + pub fn num_milliseconds(&self) -> i64 { + // cannot overflow, 2^32 * 86400 * 1000 < 2^64 + fn millis((days, secs, nanos): (i64, u32, u32)) -> i64 { + static MILLIS_PER_SEC: i64 = 1_000; + static NANOS_PER_MILLI: i64 = 1_000_000; + (days as i64 * MILLIS_PER_SEC * SECS_PER_DAY as i64 + + secs as i64 * MILLIS_PER_SEC + + nanos as i64 / NANOS_PER_MILLI) + } + if self.days < 0 {-millis(self.to_negated_tuple_64())} else {millis(self.to_tuple_64())} + } + + /// Returns the total number of whole microseconds in the duration, + /// or `None` on the overflow (exceeding 2^63 microseconds in either directions). + pub fn num_microseconds(&self) -> Option<i64> { + fn micros((days, secs, nanos): (i64, u32, u32)) -> Option<i64> { + static MICROS_PER_SEC: i64 = 1_000_000; + static MICROS_PER_DAY: i64 = MICROS_PER_SEC * SECS_PER_DAY as i64; + static NANOS_PER_MICRO: i64 = 1_000; + let nmicros = try_opt!((days as i64).checked_mul(&MICROS_PER_DAY)); + let nmicros = try_opt!(nmicros.checked_add(&(secs as i64 * MICROS_PER_SEC))); + let nmicros = try_opt!(nmicros.checked_add(&(nanos as i64 / NANOS_PER_MICRO as i64))); + Some(nmicros) + } + if self.days < 0 { + // the final negation won't overflow since we start with positive numbers. + micros(self.to_negated_tuple_64()).map(|micros| -micros) + } else { + micros(self.to_tuple_64()) + } + } + + /// Returns the total number of whole nanoseconds in the duration, + /// or `None` on the overflow (exceeding 2^63 nanoseconds in either directions). + pub fn num_nanoseconds(&self) -> Option<i64> { + fn nanos((days, secs, nanos): (i64, u32, u32)) -> Option<i64> { + static NANOS_PER_DAY: i64 = NANOS_PER_SEC as i64 * SECS_PER_DAY as i64; + let nnanos = try_opt!((days as i64).checked_mul(&NANOS_PER_DAY)); + let nnanos = try_opt!(nnanos.checked_add(&(secs as i64 * NANOS_PER_SEC as i64))); + let nnanos = try_opt!(nnanos.checked_add(&(nanos as i64))); + Some(nnanos) + } + if self.days < 0 { + // the final negation won't overflow since we start with positive numbers. + nanos(self.to_negated_tuple_64()).map(|micros| -micros) + } else { + nanos(self.to_tuple_64()) + } } } +impl num::Bounded for Duration { + #[inline] fn min_value() -> Duration { MIN } + #[inline] fn max_value() -> Duration { MAX } +} + impl num::Zero for Duration { #[inline] fn zero() -> Duration { @@ -141,20 +297,10 @@ impl num::Zero for Duration { } impl Neg<Duration> for Duration { + #[inline] fn neg(&self) -> Duration { - // FIXME overflow (e.g. `-Duration::days(i32::MIN as i32)`) - let mut days = -(self.days as i32); - let mut secs = -(self.secs as i32); - let mut nanos = -(self.nanos as i32); - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs -= 1; - } - if secs < 0 { - secs += SECS_PER_DAY; - days -= 1; - } - Duration { days: days as i32, secs: secs as u32, nanos: nanos as u32 } + let (days, secs, nanos) = self.to_negated_tuple_64(); + Duration { days: days as i32, secs: secs, nanos: nanos } // FIXME can overflow } } @@ -177,7 +323,7 @@ impl Add<Duration,Duration> for Duration { impl num::CheckedAdd for Duration { fn checked_add(&self, rhs: &Duration) -> Option<Duration> { - let mut days = earlyexit!(self.days.checked_add(&rhs.days)); + let mut days = try_opt!(self.days.checked_add(&rhs.days)); let mut secs = self.secs + rhs.secs; let mut nanos = self.nanos + rhs.nanos; if nanos >= NANOS_PER_SEC as u32 { @@ -186,7 +332,7 @@ impl num::CheckedAdd for Duration { } if secs >= SECS_PER_DAY as u32 { secs -= SECS_PER_DAY as u32; - days = earlyexit!(days.checked_add(&1)); + days = try_opt!(days.checked_add(&1)); } Some(Duration { days: days, secs: secs, nanos: nanos }) } @@ -211,7 +357,7 @@ impl Sub<Duration,Duration> for Duration { impl num::CheckedSub for Duration { fn checked_sub(&self, rhs: &Duration) -> Option<Duration> { - let mut days = earlyexit!(self.days.checked_sub(&rhs.days)); + let mut days = try_opt!(self.days.checked_sub(&rhs.days)); let mut secs = self.secs as i32 - rhs.secs as i32; let mut nanos = self.nanos as i32 - rhs.nanos as i32; if nanos < 0 { @@ -220,7 +366,7 @@ impl num::CheckedSub for Duration { } if secs < 0 { secs += SECS_PER_DAY; - days = earlyexit!(days.checked_sub(&1)); + days = try_opt!(days.checked_sub(&1)); } Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) } @@ -256,8 +402,8 @@ impl Mul<i32,Duration> for Duration { impl Div<i32,Duration> for Duration { fn div(&self, rhs: &i32) -> Duration { let (rhs, days, secs, nanos) = if *rhs < 0 { - let negated = -*self; - (-*rhs as i64, negated.days as i64, negated.secs as i64, negated.nanos as i64) + let (days, secs, nanos) = self.to_negated_tuple_64(); + (-(*rhs as i64), days, secs as i64, nanos as i64) } else { (*rhs as i64, self.days as i64, self.secs as i64, self.nanos as i64) }; @@ -276,7 +422,7 @@ impl fmt::Show for Duration { let hasdate = self.days != 0; let hastime = (self.secs != 0 || self.nanos != 0) || !hasdate; - try!('P'.fmt(f)); + try!(write!(f, "P")); if hasdate { // technically speaking the negative part is not the valid ISO 8601, // but we need to print it anyway. @@ -286,11 +432,11 @@ impl fmt::Show for Duration { if self.nanos == 0 { try!(write!(f, "T{}S", self.secs)); } else if self.nanos % 1_000_000 == 0 { - try!(write!(f, "T{},{:03}S", self.secs, self.nanos / 1_000_000)); + try!(write!(f, "T{}.{:03}S", self.secs, self.nanos / 1_000_000)); } else if self.nanos % 1_000 == 0 { - try!(write!(f, "T{},{:06}S", self.secs, self.nanos / 1_000)); + try!(write!(f, "T{}.{:06}S", self.secs, self.nanos / 1_000)); } else { - try!(write!(f, "T{},{:09}S", self.secs, self.nanos)); + try!(write!(f, "T{}.{:09}S", self.secs, self.nanos)); } } Ok(()) @@ -354,20 +500,15 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) { (this / other, this % other) } - #[cfg(test)] mod tests { - use option::Some; - use super::{Duration, MIN_DAYS, MAX_DAYS}; - use i32; - use num::{CheckedAdd, CheckedSub, Zero}; - use to_string::ToString; - - fn zero() -> Duration { Zero::zero() } + use super::{Duration, MIN_DAYS, MAX_DAYS, MIN, MAX}; + use std::{i32, i64}; #[test] fn test_duration() { - assert!(zero() != Duration::seconds(1)); + assert_eq!(Duration::zero(), Duration::zero()); + assert!(Duration::zero() != Duration::seconds(1)); 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)); @@ -381,6 +522,105 @@ mod tests { } #[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::new(1, 2, 3_004_005).num_days(), 1); + assert_eq!(Duration::new(-1, -2, -3_004_005).num_days(), -1); + assert_eq!(Duration::days(i32::MAX).num_days(), i32::MAX); + assert_eq!(Duration::days(i32::MIN).num_days(), i32::MIN); + assert_eq!(MAX.num_days(), MAX_DAYS); + assert_eq!(MIN.num_days(), MIN_DAYS); + } + + #[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); + assert_eq!(Duration::new(1, 2, 3_004_005).num_seconds(), 86402); + assert_eq!(Duration::new(-1, -2, -3_004_005).num_seconds(), -86402); + assert_eq!(Duration::seconds(i32::MAX).num_seconds(), i32::MAX as i64); + assert_eq!(Duration::seconds(i32::MIN).num_seconds(), i32::MIN as i64); + assert_eq!(MAX.num_seconds(), (MAX_DAYS as i64 + 1) * 86400 - 1); + assert_eq!(MIN.num_seconds(), MIN_DAYS as i64 * 86400); + } + + #[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::new(1, 2, 3_004_005).num_milliseconds(), 86402_003); + assert_eq!(Duration::new(-1, -2, -3_004_005).num_milliseconds(), -86402_003); + assert_eq!(Duration::milliseconds(i32::MAX).num_milliseconds(), i32::MAX as i64); + assert_eq!(Duration::milliseconds(i32::MIN).num_milliseconds(), i32::MIN as i64); + assert_eq!(MAX.num_milliseconds(), (MAX_DAYS as i64 + 1) * 86400_000 - 1); + assert_eq!(MIN.num_milliseconds(), MIN_DAYS as i64 * 86400_000); + } + + #[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::new(1, 2, 3_004_005).num_microseconds(), Some(86402_003_004)); + assert_eq!(Duration::new(-1, -2, -3_004_005).num_microseconds(), Some(-86402_003_004)); + assert_eq!(Duration::microseconds(i32::MAX).num_microseconds(), Some(i32::MAX as i64)); + assert_eq!(Duration::microseconds(i32::MIN).num_microseconds(), Some(i32::MIN as i64)); + assert_eq!(MAX.num_microseconds(), None); + assert_eq!(MIN.num_microseconds(), None); + + // overflow checks + static MICROS_PER_DAY: i64 = 86400_000_000; + assert_eq!(Duration::days((i64::MAX / MICROS_PER_DAY) as i32).num_microseconds(), + Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)); + assert_eq!(Duration::days((i64::MIN / MICROS_PER_DAY) as i32).num_microseconds(), + Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY)); + assert_eq!(Duration::days((i64::MAX / MICROS_PER_DAY + 1) as i32).num_microseconds(), None); + assert_eq!(Duration::days((i64::MIN / MICROS_PER_DAY - 1) as i32).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::new(1, 2, 3_004_005).num_nanoseconds(), Some(86402_003_004_005)); + assert_eq!(Duration::new(-1, -2, -3_004_005).num_nanoseconds(), Some(-86402_003_004_005)); + assert_eq!(Duration::nanoseconds(i32::MAX).num_nanoseconds(), Some(i32::MAX as i64)); + assert_eq!(Duration::nanoseconds(i32::MIN).num_nanoseconds(), Some(i32::MIN as i64)); + assert_eq!(MAX.num_nanoseconds(), None); + assert_eq!(MIN.num_nanoseconds(), None); + + // overflow checks + static NANOS_PER_DAY: i64 = 86400_000_000_000; + assert_eq!(Duration::days((i64::MAX / NANOS_PER_DAY) as i32).num_nanoseconds(), + Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)); + assert_eq!(Duration::days((i64::MIN / NANOS_PER_DAY) as i32).num_nanoseconds(), + Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY)); + assert_eq!(Duration::days((i64::MAX / NANOS_PER_DAY + 1) as i32).num_nanoseconds(), None); + assert_eq!(Duration::days((i64::MIN / NANOS_PER_DAY - 1) as i32).num_nanoseconds(), None); + } + + #[test] fn test_duration_checked_ops() { assert_eq!(Duration::days(MAX_DAYS).checked_add(&Duration::seconds(86399)), Some(Duration::days(MAX_DAYS - 1) + Duration::seconds(86400+86399))); @@ -393,9 +633,9 @@ mod tests { #[test] fn test_duration_mul() { - assert_eq!(zero() * i32::MAX, zero()); - assert_eq!(zero() * i32::MIN, zero()); - assert_eq!(Duration::nanoseconds(1) * 0, zero()); + 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)); @@ -408,8 +648,8 @@ mod tests { #[test] fn test_duration_div() { - assert_eq!(zero() / i32::MAX, zero()); - assert_eq!(zero() / i32::MIN, zero()); + 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)); @@ -418,14 +658,18 @@ mod tests { #[test] fn test_duration_fmt() { - assert_eq!(zero().to_string(), "PT0S".to_string()); + assert_eq!(Duration::zero().to_string(), "PT0S".to_string()); assert_eq!(Duration::days(42).to_string(), "P42D".to_string()); assert_eq!(Duration::days(-42).to_string(), "P-42D".to_string()); assert_eq!(Duration::seconds(42).to_string(), "PT42S".to_string()); - assert_eq!(Duration::milliseconds(42).to_string(), "PT0,042S".to_string()); - assert_eq!(Duration::microseconds(42).to_string(), "PT0,000042S".to_string()); - assert_eq!(Duration::nanoseconds(42).to_string(), "PT0,000000042S".to_string()); + assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S".to_string()); + assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S".to_string()); + assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S".to_string()); assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(), - "P7DT6,543S".to_string()); + "P7DT6.543S".to_string()); + + // the format specifier should have no effect on `Duration` + assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)), + "P1DT2.345S".to_string()); } } |
