about summary refs log tree commit diff
path: root/src/libstd/time
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-04-28 11:40:04 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-05-13 17:50:58 -0700
commit556e76bb78cdd1d951e3966b2264ef8567371881 (patch)
tree2b024aea65f5b77452414fd82a70150b956613c3 /src/libstd/time
parent05d5fcaa5ba0c385e1dc97037c89fae437634fc3 (diff)
downloadrust-556e76bb78cdd1d951e3966b2264ef8567371881.tar.gz
rust-556e76bb78cdd1d951e3966b2264ef8567371881.zip
std: Redesign Duration, implementing RFC 1040
This commit is an implementation of [RFC 1040][rfc] which is a redesign of the
currently-unstable `Duration` type. The API of the type has been scaled back to
be more conservative and it also no longer supports negative durations.

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1040-duration-reform.md

The inner `duration` module of the `time` module has now been hidden (as
`Duration` is reexported) and the feature name for this type has changed from
`std_misc` to `duration`. All APIs accepting durations have also been audited to
take a more flavorful feature name instead of `std_misc`.

Closes #24874
Diffstat (limited to 'src/libstd/time')
-rw-r--r--src/libstd/time/duration.rs664
-rw-r--r--src/libstd/time/mod.rs13
2 files changed, 172 insertions, 505 deletions
diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs
index 636a0dd697a..8001df29d1f 100644
--- a/src/libstd/time/duration.rs
+++ b/src/libstd/time/duration.rs
@@ -10,589 +10,265 @@
 
 //! Temporal quantification
 
-#![unstable(feature = "std_misc")]
+#![unstable(feature = "duration", reason = "recently added API per RFC 1040")]
 
 use prelude::v1::*;
 
-use {fmt, i64};
-use ops::{Add, Sub, Mul, Div, Neg};
-
-/// 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.
-#[unstable(feature = "std_misc")]
+use fmt;
+use ops::{Add, Sub, Mul, Div};
+use sys::time::SteadyTime;
+
+const NANOS_PER_SEC: u32 = 1_000_000_000;
+const NANOS_PER_MILLI: u32 = 1_000_000;
+const MILLIS_PER_SEC: u64 = 1_000;
+
+/// A duration type to represent a span of time, typically used for system
+/// timeouts.
+///
+/// Each duration is composed of a number of seconds and nanosecond precision.
+/// APIs binding a system timeout will typically round up the nanosecond
+/// precision if the underlying system does not support that level of precision.
+///
+/// Durations implement many common traits, including `Add`, `Sub`, and other
+/// ops traits. Currently a duration may only be inspected for its number of
+/// seconds and its nanosecond precision.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(duration)]
+/// use std::time::Duration;
+///
+/// let five_seconds = Duration::new(5, 0);
+/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5);
+///
+/// assert_eq!(five_seconds_and_five_nanos.secs(), 5);
+/// assert_eq!(five_seconds_and_five_nanos.extra_nanos(), 5);
+///
+/// let ten_millis = Duration::from_millis(10);
+/// ```
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
 pub struct Duration {
-    secs: i64,
-    nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
+    secs: u64,
+    nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
 }
 
-/// The minimum possible `Duration`: `i64::MIN` milliseconds.
-#[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.
-#[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.
-    /// Panics when the duration is out of bounds.
-    #[inline]
-    #[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.
-    /// Panics when the duration is out of bounds.
-    #[inline]
-    #[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.
-    /// Panics when the duration is out of bounds.
-    #[inline]
-    #[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.
-    /// Panics when the duration is out of bounds.
-    #[inline]
-    #[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.
-    /// Panics when the duration is more than `i64::MAX` milliseconds
-    /// or less than `i64::MIN` milliseconds.
-    #[inline]
-    #[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]
-    #[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;
+    /// Crates a new `Duration` from the specified number of seconds and
+    /// additional nanosecond precision.
+    ///
+    /// If the nanoseconds is greater than 1 billion (the number of nanoseconds
+    /// in a second), then it will carry over into the seconds provided.
+    pub fn new(secs: u64, nanos: u32) -> Duration {
+        let secs = secs + (nanos / NANOS_PER_SEC) as u64;
+        let nanos = nanos % NANOS_PER_SEC;
         Duration { secs: secs, nanos: nanos }
     }
 
-    /// Makes a new `Duration` with given number of microseconds.
-    #[inline]
-    #[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]
-    #[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.
-    #[unstable(feature = "std_misc")]
+    #[unstable(feature = "duration_span",
+               reason = "unsure if this is the right API or whether it should \
+                         wait for a more general \"moment in time\" \
+                         abstraction")]
     pub fn span<F>(f: F) -> Duration where F: FnOnce() {
-        let before = super::precise_time_ns();
+        let start = SteadyTime::now();
         f();
-        Duration::nanoseconds((super::precise_time_ns() - before) as i64)
-    }
-
-    /// Returns the total number of whole weeks in the duration.
-    #[inline]
-    #[unstable(feature = "std_misc")]
-    pub fn num_weeks(&self) -> i64 {
-        self.num_days() / 7
-    }
-
-    /// Returns the total number of whole days in the duration.
-    #[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]
-    #[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]
-    #[unstable(feature = "std_misc")]
-    pub fn num_minutes(&self) -> i64 {
-        self.num_seconds() / SECS_PER_MINUTE
-    }
-
-    /// Returns the total number of whole seconds in the duration.
-    #[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,
-    #[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).
-    #[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)
+        &SteadyTime::now() - &start
     }
 
-    /// Returns the total number of whole nanoseconds in the duration,
-    /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
-    #[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)
+    /// Creates a new `Duration` from the specified number of seconds.
+    pub fn from_secs(secs: u64) -> Duration {
+        Duration { secs: secs, nanos: 0 }
     }
 
-    /// Add two durations, returning `None` if overflow occurred.
-    #[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.
-    #[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]
-    #[unstable(feature = "std_misc")]
-    pub fn min_value() -> Duration { MIN }
-
-    /// The maximum possible `Duration`: `i64::MAX` milliseconds.
-    #[inline]
-    #[unstable(feature = "std_misc")]
-    pub fn max_value() -> Duration { MAX }
-
-    /// A duration where the stored seconds and nanoseconds are equal to zero.
-    #[inline]
-    #[unstable(feature = "std_misc")]
-    pub fn zero() -> Duration {
-        Duration { secs: 0, nanos: 0 }
-    }
-
-    /// Returns `true` if the duration equals `Duration::zero()`.
-    #[inline]
-    #[unstable(feature = "std_misc")]
-    pub fn is_zero(&self) -> bool {
-        self.secs == 0 && self.nanos == 0
+    /// Creates a new `Duration` from the specified number of milliseconds.
+    pub fn from_millis(millis: u64) -> Duration {
+        let secs = millis / MILLIS_PER_SEC;
+        let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI;
+        Duration { secs: secs, nanos: nanos }
     }
-}
 
-#[unstable(feature = "std_misc")]
-impl Neg for Duration {
-    type Output = Duration;
+    /// Returns the number of whole seconds represented by this duration.
+    ///
+    /// The extra precision represented by this duration is ignored (e.g. extra
+    /// nanoseconds are not represented in the returned value).
+    pub fn secs(&self) -> u64 { self.secs }
 
-    #[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 }
-        }
-    }
+    /// Returns the nanosecond precision represented by this duration.
+    ///
+    /// This method does **not** return the length of the duration when
+    /// represented by nanoseconds. The returned number always represents a
+    /// fractional portion of a second (e.g. it is less than one billion).
+    pub fn extra_nanos(&self) -> u32 { self.nanos }
 }
 
-#[unstable(feature = "std_misc")]
 impl Add for Duration {
     type Output = Duration;
 
     fn add(self, rhs: Duration) -> Duration {
-        let mut secs = self.secs + rhs.secs;
+        let mut secs = self.secs.checked_add(rhs.secs)
+                           .expect("overflow when adding durations");
         let mut nanos = self.nanos + rhs.nanos;
         if nanos >= NANOS_PER_SEC {
             nanos -= NANOS_PER_SEC;
-            secs += 1;
+            secs = secs.checked_add(1).expect("overflow when adding durations");
         }
+        debug_assert!(nanos < NANOS_PER_SEC);
         Duration { secs: secs, nanos: nanos }
     }
 }
 
-#[unstable(feature = "std_misc")]
 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;
-        }
+        let mut secs = self.secs.checked_sub(rhs.secs)
+                           .expect("overflow when subtracting durations");
+        let nanos = if self.nanos >= rhs.nanos {
+            self.nanos - rhs.nanos
+        } else {
+            secs = secs.checked_sub(1)
+                       .expect("overflow when subtracting durations");
+            self.nanos + NANOS_PER_SEC - rhs.nanos
+        };
+        debug_assert!(nanos < NANOS_PER_SEC);
         Duration { secs: secs, nanos: nanos }
     }
 }
 
-#[unstable(feature = "std_misc")]
-impl Mul<i32> for Duration {
+impl Mul<u32> 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 }
+    fn mul(self, rhs: u32) -> Duration {
+        // Multiply nanoseconds as u64, because it cannot overflow that way.
+        let total_nanos = self.nanos as u64 * rhs as u64;
+        let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
+        let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
+        let secs = self.secs.checked_mul(rhs as u64)
+                       .and_then(|s| s.checked_add(extra_secs))
+                       .expect("overflow when multiplying duration");
+        debug_assert!(nanos < NANOS_PER_SEC);
+        Duration { secs: secs, nanos: nanos }
     }
 }
 
-#[unstable(feature = "std_misc")]
-impl Div<i32> for Duration {
+impl Div<u32> 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;
-        }
+    fn div(self, rhs: u32) -> Duration {
+        let secs = self.secs / (rhs as u64);
+        let carry = self.secs - secs * (rhs as u64);
+        let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
+        let nanos = self.nanos / rhs + (extra_nanos as u32);
+        debug_assert!(nanos < NANOS_PER_SEC);
         Duration { secs: secs, nanos: nanos }
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
 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));
-            }
+        match (self.secs, self.nanos) {
+            (s, 0) => write!(f, "{}s", s),
+            (0, n) if n % NANOS_PER_MILLI == 0 => write!(f, "{}ms",
+                                                         n / NANOS_PER_MILLI),
+            (0, n) if n % 1_000 == 0 => write!(f, "{}µs", n / 1_000),
+            (0, n) => write!(f, "{}ns", n),
+            (s, n) => write!(f, "{}.{}s", s,
+                             format!("{:09}", n).trim_right_matches('0'))
         }
-        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;
+    use prelude::v1::*;
+    use super::Duration;
 
     #[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));
+    fn creation() {
+        assert!(Duration::from_secs(1) != Duration::from_secs(0));
+        assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
+                   Duration::from_secs(3));
+        assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
+                   Duration::new(4, 10 * 1_000_000));
+        assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
     }
 
     #[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);
+    fn secs() {
+        assert_eq!(Duration::new(0, 0).secs(), 0);
+        assert_eq!(Duration::from_secs(1).secs(), 1);
+        assert_eq!(Duration::from_millis(999).secs(), 0);
+        assert_eq!(Duration::from_millis(1001).secs(), 1);
     }
 
     #[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);
+    fn nanos() {
+        assert_eq!(Duration::new(0, 0).extra_nanos(), 0);
+        assert_eq!(Duration::new(0, 5).extra_nanos(), 5);
+        assert_eq!(Duration::new(0, 1_000_000_001).extra_nanos(), 1);
+        assert_eq!(Duration::from_secs(1).extra_nanos(), 0);
+        assert_eq!(Duration::from_millis(999).extra_nanos(), 999 * 1_000_000);
+        assert_eq!(Duration::from_millis(1001).extra_nanos(), 1 * 1_000_000);
     }
 
     #[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);
+    fn add() {
+        assert_eq!(Duration::new(0, 0) + Duration::new(0, 1),
+                   Duration::new(0, 1));
+        assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001),
+                   Duration::new(1, 1));
     }
 
     #[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);
+    fn sub() {
+        assert_eq!(Duration::new(0, 1) - Duration::new(0, 0),
+                   Duration::new(0, 1));
+        assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000),
+                   Duration::new(0, 1));
+        assert_eq!(Duration::new(1, 0) - Duration::new(0, 1),
+                   Duration::new(0, 999_999_999));
     }
 
-    #[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] #[should_panic]
+    fn sub_bad1() {
+        Duration::new(0, 0) - Duration::new(0, 1);
     }
 
-    #[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] #[should_panic]
+    fn sub_bad2() {
+        Duration::new(0, 0) - Duration::new(1, 0);
     }
 
     #[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));
+    fn mul() {
+        assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
+        assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
+        assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
+        assert_eq!(Duration::new(0, 500_000_001) * 4000,
+                   Duration::new(2000, 4000));
     }
 
     #[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));
+    fn div() {
+        assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
+        assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
+        assert_eq!(Duration::new(99, 999_999_000) / 100,
+                   Duration::new(0, 999_999_990));
     }
 
     #[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");
+    fn display() {
+        assert_eq!(Duration::new(0, 2).to_string(), "2ns");
+        assert_eq!(Duration::new(0, 2_000_000).to_string(), "2ms");
+        assert_eq!(Duration::new(2, 0).to_string(), "2s");
+        assert_eq!(Duration::new(2, 2).to_string(), "2.000000002s");
+        assert_eq!(Duration::new(2, 2_000_000).to_string(),
+                   "2.002s");
+        assert_eq!(Duration::new(0, 2_000_002).to_string(),
+                   "2000002ns");
+        assert_eq!(Duration::new(2, 2_000_002).to_string(),
+                   "2.002000002s");
     }
 }
diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs
index 4d9bb8050d3..d535b195519 100644
--- a/src/libstd/time/mod.rs
+++ b/src/libstd/time/mod.rs
@@ -10,17 +10,8 @@
 
 //! Temporal quantification.
 
-#![unstable(feature = "std_misc")]
-
-use sys::time::SteadyTime;
+#![unstable(feature = "time")]
 
 pub use self::duration::Duration;
 
-pub mod duration;
-
-/// Returns the current value of a high-resolution performance counter
-/// in nanoseconds since an unspecified epoch.
-// NB: this is intentionally not public, this is not ready to stabilize its api.
-fn precise_time_ns() -> u64 {
-    SteadyTime::now().ns()
-}
+mod duration;