about summary refs log tree commit diff
path: root/src/libstd
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
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')
-rw-r--r--src/libstd/sync/condvar.rs82
-rw-r--r--src/libstd/sys/unix/condvar.rs22
-rw-r--r--src/libstd/sys/unix/thread.rs9
-rw-r--r--src/libstd/sys/unix/time.rs30
-rw-r--r--src/libstd/sys/windows/condvar.rs2
-rw-r--r--src/libstd/sys/windows/mod.rs22
-rw-r--r--src/libstd/sys/windows/thread.rs10
-rw-r--r--src/libstd/sys/windows/time.rs20
-rw-r--r--src/libstd/thread/mod.rs44
-rw-r--r--src/libstd/time/duration.rs664
-rw-r--r--src/libstd/time/mod.rs13
11 files changed, 329 insertions, 589 deletions
diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index c2964b7a4f1..8da917916e5 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -69,12 +69,12 @@ pub struct Condvar { inner: Box<StaticCondvar> }
 /// # Examples
 ///
 /// ```
-/// # #![feature(std_misc)]
+/// # #![feature(static_condvar)]
 /// use std::sync::{StaticCondvar, CONDVAR_INIT};
 ///
 /// static CVAR: StaticCondvar = CONDVAR_INIT;
 /// ```
-#[unstable(feature = "std_misc",
+#[unstable(feature = "static_condvar",
            reason = "may be merged with Condvar in the future")]
 pub struct StaticCondvar {
     inner: sys::Condvar,
@@ -82,7 +82,7 @@ pub struct StaticCondvar {
 }
 
 /// Constant initializer for a statically allocated condition variable.
-#[unstable(feature = "std_misc",
+#[unstable(feature = "static_condvar",
            reason = "may be merged with Condvar in the future")]
 pub const CONDVAR_INIT: StaticCondvar = StaticCondvar {
     inner: sys::CONDVAR_INIT,
@@ -164,6 +164,30 @@ impl Condvar {
     /// Waits on this condition variable for a notification, timing out after a
     /// specified duration.
     ///
+    /// The semantics of this function are equivalent to `wait()` except that
+    /// the thread will be blocked for roughly no longer than `dur`. This
+    /// method should not be used for precise timing due to anomalies such as
+    /// preemption or platform differences that may not cause the maximum
+    /// amount of time waited to be precisely `dur`.
+    ///
+    /// The returned boolean is `false` only if the timeout is known
+    /// to have elapsed.
+    ///
+    /// Like `wait`, the lock specified will be re-acquired when this function
+    /// returns, regardless of whether the timeout elapsed or not.
+    #[unstable(feature = "wait_timeout", reason = "waiting for Duration")]
+    pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
+                               dur: Duration)
+                               -> LockResult<(MutexGuard<'a, T>, bool)> {
+        unsafe {
+            let me: &'static Condvar = &*(self as *const _);
+            me.inner.wait_timeout(guard, dur)
+        }
+    }
+
+    /// Waits on this condition variable for a notification, timing out after a
+    /// specified duration.
+    ///
     /// The semantics of this function are equivalent to `wait_timeout` except
     /// that the implementation will repeatedly wait while the duration has not
     /// passed and the provided function returns `false`.
@@ -214,7 +238,7 @@ impl StaticCondvar {
     /// notification.
     ///
     /// See `Condvar::wait`.
-    #[unstable(feature = "std_misc",
+    #[unstable(feature = "static_condvar",
                reason = "may be merged with Condvar in the future")]
     pub fn wait<'a, T>(&'static self, guard: MutexGuard<'a, T>)
                        -> LockResult<MutexGuard<'a, T>> {
@@ -235,14 +259,27 @@ impl StaticCondvar {
     /// specified duration.
     ///
     /// See `Condvar::wait_timeout`.
-    #[unstable(feature = "std_misc",
+    #[unstable(feature = "static_condvar",
                reason = "may be merged with Condvar in the future")]
     pub fn wait_timeout_ms<'a, T>(&'static self, guard: MutexGuard<'a, T>, ms: u32)
                                   -> LockResult<(MutexGuard<'a, T>, bool)> {
+        self.wait_timeout(guard, Duration::from_millis(ms as u64))
+    }
+
+    /// Waits on this condition variable for a notification, timing out after a
+    /// specified duration.
+    ///
+    /// See `Condvar::wait_timeout`.
+    #[unstable(feature = "static_condvar",
+               reason = "may be merged with Condvar in the future")]
+    pub fn wait_timeout<'a, T>(&'static self,
+                               guard: MutexGuard<'a, T>,
+                               timeout: Duration)
+                               -> LockResult<(MutexGuard<'a, T>, bool)> {
         let (poisoned, success) = unsafe {
             let lock = mutex::guard_lock(&guard);
             self.verify(lock);
-            let success = self.inner.wait_timeout(lock, Duration::milliseconds(ms as i64));
+            let success = self.inner.wait_timeout(lock, timeout);
             (mutex::guard_poison(&guard).get(), success)
         };
         if poisoned {
@@ -259,7 +296,7 @@ impl StaticCondvar {
     /// passed and the function returns `false`.
     ///
     /// See `Condvar::wait_timeout_with`.
-    #[unstable(feature = "std_misc",
+    #[unstable(feature = "static_condvar",
                reason = "may be merged with Condvar in the future")]
     pub fn wait_timeout_with<'a, T, F>(&'static self,
                                        guard: MutexGuard<'a, T>,
@@ -267,7 +304,8 @@ impl StaticCondvar {
                                        mut f: F)
                                        -> LockResult<(MutexGuard<'a, T>, bool)>
             where F: FnMut(LockResult<&mut T>) -> bool {
-        // This could be made more efficient by pushing the implementation into sys::condvar
+        // This could be made more efficient by pushing the implementation into
+        // sys::condvar
         let start = SteadyTime::now();
         let mut guard_result: LockResult<MutexGuard<'a, T>> = Ok(guard);
         while !f(guard_result
@@ -277,12 +315,15 @@ impl StaticCondvar {
             let now = SteadyTime::now();
             let consumed = &now - &start;
             let guard = guard_result.unwrap_or_else(|e| e.into_inner());
-            let res = self.wait_timeout_ms(guard, (dur - consumed).num_milliseconds() as u32);
-            let (new_guard_result, no_timeout) = match res {
-                Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout),
-                Err(err) => {
-                    let (new_guard, no_timeout) = err.into_inner();
-                    (Err(PoisonError::new(new_guard)), no_timeout)
+            let (new_guard_result, no_timeout) = if consumed > dur {
+                (Ok(guard), false)
+            } else {
+                match self.wait_timeout(guard, dur - consumed) {
+                    Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout),
+                    Err(err) => {
+                        let (new_guard, no_timeout) = err.into_inner();
+                        (Err(PoisonError::new(new_guard)), no_timeout)
+                    }
                 }
             };
             guard_result = new_guard_result;
@@ -301,14 +342,14 @@ impl StaticCondvar {
     /// Wakes up one blocked thread on this condvar.
     ///
     /// See `Condvar::notify_one`.
-    #[unstable(feature = "std_misc",
+    #[unstable(feature = "static_condvar",
                reason = "may be merged with Condvar in the future")]
     pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } }
 
     /// Wakes up all blocked threads on this condvar.
     ///
     /// See `Condvar::notify_all`.
-    #[unstable(feature = "std_misc",
+    #[unstable(feature = "static_condvar",
                reason = "may be merged with Condvar in the future")]
     pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } }
 
@@ -318,7 +359,7 @@ impl StaticCondvar {
     /// active users of the condvar, and this also doesn't prevent any future
     /// users of the condvar. This method is required to be called to not leak
     /// memory on all platforms.
-    #[unstable(feature = "std_misc",
+    #[unstable(feature = "static_condvar",
                reason = "may be merged with Condvar in the future")]
     pub unsafe fn destroy(&'static self) {
         self.inner.destroy()
@@ -447,7 +488,9 @@ mod tests {
         static S: AtomicUsize = ATOMIC_USIZE_INIT;
 
         let g = M.lock().unwrap();
-        let (g, success) = C.wait_timeout_with(g, Duration::nanoseconds(1000), |_| false).unwrap();
+        let (g, success) = C.wait_timeout_with(g, Duration::new(0, 1000), |_| {
+            false
+        }).unwrap();
         assert!(!success);
 
         let (tx, rx) = channel();
@@ -471,7 +514,8 @@ mod tests {
         });
 
         let mut state = 0;
-        let (_g, success) = C.wait_timeout_with(g, Duration::days(1), |_| {
+        let day = 24 * 60 * 60;
+        let (_g, success) = C.wait_timeout_with(g, Duration::new(day, 0), |_| {
             assert_eq!(state, S.load(Ordering::SeqCst));
             tx.send(()).unwrap();
             state += 1;
diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs
index ed6382e000a..29a13cc6be7 100644
--- a/src/libstd/sys/unix/condvar.rs
+++ b/src/libstd/sys/unix/condvar.rs
@@ -57,25 +57,20 @@ impl Condvar {
     // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
     // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        if dur <= Duration::zero() {
-            return false;
-        }
-
-        // First, figure out what time it currently is, in both system and stable time.
-        // pthread_cond_timedwait uses system time, but we want to report timeout based on stable
-        // time.
+        // First, figure out what time it currently is, in both system and
+        // stable time.  pthread_cond_timedwait uses system time, but we want to
+        // report timeout based on stable time.
         let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
         let stable_now = time::SteadyTime::now();
         let r = ffi::gettimeofday(&mut sys_now, ptr::null_mut());
         debug_assert_eq!(r, 0);
 
-        let seconds = dur.num_seconds() as libc::time_t;
+        let seconds = dur.secs() as libc::time_t;
         let timeout = match sys_now.tv_sec.checked_add(seconds) {
             Some(sec) => {
                 libc::timespec {
                     tv_sec: sec,
-                    tv_nsec: (dur - Duration::seconds(dur.num_seconds()))
-                        .num_nanoseconds().unwrap() as libc::c_long,
+                    tv_nsec: dur.extra_nanos() as libc::c_long,
                 }
             }
             None => {
@@ -87,11 +82,12 @@ impl Condvar {
         };
 
         // And wait!
-        let r = ffi::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), &timeout);
+        let r = ffi::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
+                                            &timeout);
         debug_assert!(r == libc::ETIMEDOUT || r == 0);
 
-        // ETIMEDOUT is not a totally reliable method of determining timeout due to clock shifts,
-        // so do the check ourselves
+        // ETIMEDOUT is not a totally reliable method of determining timeout due
+        // to clock shifts, so do the check ourselves
         &time::SteadyTime::now() - &stable_now < dur
     }
 
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index cfab9d1c51a..0cb5a06e6b6 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -129,14 +129,9 @@ impl Thread {
     }
 
     pub fn sleep(dur: Duration) {
-        if dur < Duration::zero() {
-            return Thread::yield_now()
-        }
-        let seconds = dur.num_seconds();
-        let ns = dur - Duration::seconds(seconds);
         let mut ts = libc::timespec {
-            tv_sec: seconds as libc::time_t,
-            tv_nsec: ns.num_nanoseconds().unwrap() as libc::c_long,
+            tv_sec: dur.secs() as libc::time_t,
+            tv_nsec: dur.extra_nanos() as libc::c_long,
         };
 
         // If we're awoken with a signal then the return value will be -1 and
diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs
index f59eb2c0301..16dfd3eebd0 100644
--- a/src/libstd/sys/unix/time.rs
+++ b/src/libstd/sys/unix/time.rs
@@ -10,12 +10,15 @@
 
 pub use self::inner::SteadyTime;
 
+const NSEC_PER_SEC: u64 = 1_000_000_000;
+
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 mod inner {
     use libc;
     use time::Duration;
     use ops::Sub;
     use sync::{Once, ONCE_INIT};
+    use super::NSEC_PER_SEC;
 
     pub struct SteadyTime {
         t: u64
@@ -32,11 +35,6 @@ mod inner {
                 t: unsafe { mach_absolute_time() },
             }
         }
-
-        pub fn ns(&self) -> u64 {
-            let info = info();
-            self.t * info.numer as u64 / info.denom as u64
-        }
     }
 
     fn info() -> &'static libc::mach_timebase_info {
@@ -59,8 +57,9 @@ mod inner {
 
         fn sub(self, other: &SteadyTime) -> Duration {
             let info = info();
-            let diff = self.t as i64 - other.t as i64;
-            Duration::nanoseconds(diff * info.numer as i64 / info.denom as i64)
+            let diff = self.t as u64 - other.t as u64;
+            let nanos = diff * info.numer as u64 / info.denom as u64;
+            Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)
         }
     }
 }
@@ -70,8 +69,7 @@ mod inner {
     use libc;
     use time::Duration;
     use ops::Sub;
-
-    const NSEC_PER_SEC: i64 = 1_000_000_000;
+    use super::NSEC_PER_SEC;
 
     pub struct SteadyTime {
         t: libc::timespec,
@@ -104,10 +102,6 @@ mod inner {
             }
             t
         }
-
-        pub fn ns(&self) -> u64 {
-            self.t.tv_sec as u64 * NSEC_PER_SEC as u64 + self.t.tv_nsec as u64
-        }
     }
 
     impl<'a> Sub for &'a SteadyTime {
@@ -115,12 +109,12 @@ mod inner {
 
         fn sub(self, other: &SteadyTime) -> Duration {
             if self.t.tv_nsec >= other.t.tv_nsec {
-                Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) +
-                    Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64)
+                Duration::new(self.t.tv_sec as u64 - other.t.tv_sec as u64,
+                              self.t.tv_nsec as u32 - other.t.tv_nsec as u32)
             } else {
-                Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) +
-                    Duration::nanoseconds(self.t.tv_nsec as i64 + NSEC_PER_SEC -
-                                          other.t.tv_nsec as i64)
+                Duration::new(self.t.tv_sec as u64 - 1 - other.t.tv_sec as u64,
+                              self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
+                                          other.t.tv_nsec as u32)
             }
         }
     }
diff --git a/src/libstd/sys/windows/condvar.rs b/src/libstd/sys/windows/condvar.rs
index 67552255fdb..8bb2326e4d6 100644
--- a/src/libstd/sys/windows/condvar.rs
+++ b/src/libstd/sys/windows/condvar.rs
@@ -42,7 +42,7 @@ impl Condvar {
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         let r = ffi::SleepConditionVariableSRW(self.inner.get(),
                                                mutex::raw(mutex),
-                                               dur.num_milliseconds() as DWORD,
+                                               super::dur2timeout(dur),
                                                0);
         if r == 0 {
             const ERROR_TIMEOUT: DWORD = 0x5B4;
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 5ae5f6f201b..d7a3a03de6d 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -20,6 +20,7 @@ use libc;
 use num::Zero;
 use os::windows::ffi::{OsStrExt, OsStringExt};
 use path::PathBuf;
+use time::Duration;
 
 pub mod backtrace;
 pub mod c;
@@ -151,6 +152,27 @@ fn cvt<I: PartialEq + Zero>(i: I) -> io::Result<I> {
     }
 }
 
+fn dur2timeout(dur: Duration) -> libc::DWORD {
+    // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
+    // timeouts in windows APIs are typically u32 milliseconds. To translate, we
+    // have two pieces to take care of:
+    //
+    // * Nanosecond precision is rounded up
+    // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
+    //   (never time out).
+    dur.secs().checked_mul(1000).and_then(|ms| {
+        ms.checked_add((dur.extra_nanos() as u64) / 1_000_000)
+    }).and_then(|ms| {
+        ms.checked_add(if dur.extra_nanos() % 1_000_000 > 0 {1} else {0})
+    }).map(|ms| {
+        if ms > <libc::DWORD>::max_value() as u64 {
+            libc::INFINITE
+        } else {
+            ms as libc::DWORD
+        }
+    }).unwrap_or(libc::INFINITE)
+}
+
 fn ms_to_filetime(ms: u64) -> libc::FILETIME {
     // A FILETIME is a count of 100 nanosecond intervals, so we multiply by
     // 10000 b/c there are 10000 intervals in 1 ms
diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs
index 797f45f8702..50dfee4ab10 100644
--- a/src/libstd/sys/windows/thread.rs
+++ b/src/libstd/sys/windows/thread.rs
@@ -80,15 +80,7 @@ impl Thread {
 
     pub fn sleep(dur: Duration) {
         unsafe {
-            if dur < Duration::zero() {
-                return Thread::yield_now()
-            }
-            let ms = dur.num_milliseconds();
-            // if we have a fractional number of milliseconds then add an extra
-            // millisecond to sleep for
-            let extra = dur - Duration::milliseconds(ms);
-            let ms = ms + if extra.is_zero() {0} else {1};
-            c::Sleep(ms as DWORD);
+            c::Sleep(super::dur2timeout(dur))
         }
     }
 }
diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs
index 209460df10b..e64df54a0fa 100644
--- a/src/libstd/sys/windows/time.rs
+++ b/src/libstd/sys/windows/time.rs
@@ -12,7 +12,7 @@ use ops::Sub;
 use time::Duration;
 use sync::{Once, ONCE_INIT};
 
-const NANOS_PER_SEC: i64 = 1_000_000_000;
+const NANOS_PER_SEC: u64 = 1_000_000_000;
 
 pub struct SteadyTime {
     t: libc::LARGE_INTEGER,
@@ -24,10 +24,6 @@ impl SteadyTime {
         unsafe { libc::QueryPerformanceCounter(&mut t.t); }
         t
     }
-
-    pub fn ns(&self) -> u64 {
-        mul_div_i64(self.t as i64, NANOS_PER_SEC, frequency() as i64) as u64
-    }
 }
 
 fn frequency() -> libc::LARGE_INTEGER {
@@ -46,15 +42,16 @@ impl<'a> Sub for &'a SteadyTime {
     type Output = Duration;
 
     fn sub(self, other: &SteadyTime) -> Duration {
-        let diff = self.t as i64 - other.t as i64;
-        Duration::nanoseconds(mul_div_i64(diff, NANOS_PER_SEC, frequency() as i64))
+        let diff = self.t as u64 - other.t as u64;
+        let nanos = mul_div_u64(diff, NANOS_PER_SEC, frequency() as u64);
+        Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32)
     }
 }
 
 // Computes (value*numer)/denom without overflow, as long as both
 // (numer*denom) and the overall result fit into i64 (which is the case
 // for our time conversions).
-fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 {
+fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
     let q = value / denom;
     let r = value % denom;
     // Decompose value as (value/denom*denom + value%denom),
@@ -65,9 +62,6 @@ fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 {
 
 #[test]
 fn test_muldiv() {
-    assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000),  1_000_000_000_001_000);
-    assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), -1_000_000_000_001_000);
-    assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000),  1_000_000_000_001_000);
-    assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), -1_000_000_000_001_000);
-    assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000),  1_000_000_000_001_000);
+    assert_eq!(mul_div_u64( 1_000_000_000_001, 1_000_000_000, 1_000_000),
+               1_000_000_000_001_000);
 }
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index bcc70c2b816..1378ea96e27 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -482,7 +482,23 @@ pub fn catch_panic<F, R>(f: F) -> Result<R>
 /// spurious wakeup.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn sleep_ms(ms: u32) {
-    imp::Thread::sleep(Duration::milliseconds(ms as i64))
+    sleep(Duration::from_millis(ms as u64))
+}
+
+/// Puts the current thread to sleep for the specified amount of time.
+///
+/// The thread may sleep longer than the duration specified due to scheduling
+/// specifics or platform-dependent functionality.
+///
+/// # Platform behavior
+///
+/// On Unix platforms this function will not return early due to a
+/// signal being received or a spurious wakeup. Platforms which do not support
+/// nanosecond precision for sleeping will have `dur` rounded up to the nearest
+/// granularity of time they can sleep for.
+#[unstable(feature = "thread_sleep", reason = "waiting on Duration")]
+pub fn sleep(dur: Duration) {
+    imp::Thread::sleep(dur)
 }
 
 /// Blocks unless or until the current thread's token is made available (may wake spuriously).
@@ -508,18 +524,38 @@ pub fn park() {
 /// the specified duration has been reached (may wake spuriously).
 ///
 /// The semantics of this function are equivalent to `park()` except that the
-/// thread will be blocked for roughly no longer than *duration*. This method
+/// thread will be blocked for roughly no longer than *ms*. This method
 /// should not be used for precise timing due to anomalies such as
 /// preemption or platform differences that may not cause the maximum
-/// amount of time waited to be precisely *duration* long.
+/// amount of time waited to be precisely *ms* long.
 ///
 /// See the module doc for more detail.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn park_timeout_ms(ms: u32) {
+    park_timeout(Duration::from_millis(ms as u64))
+}
+
+/// Blocks unless or until the current thread's token is made available or
+/// the specified duration has been reached (may wake spuriously).
+///
+/// The semantics of this function are equivalent to `park()` except that the
+/// thread will be blocked for roughly no longer than *dur*. This method
+/// should not be used for precise timing due to anomalies such as
+/// preemption or platform differences that may not cause the maximum
+/// amount of time waited to be precisely *dur* long.
+///
+/// See the module doc for more detail.
+///
+/// # Platform behavior
+///
+/// Platforms which do not support nanosecond precision for sleeping will have
+/// `dur` rounded up to the nearest granularity of time they can sleep for.
+#[unstable(feature = "park_timeout", reason = "waiting on Duration")]
+pub fn park_timeout(dur: Duration) {
     let thread = current();
     let mut guard = thread.inner.lock.lock().unwrap();
     if !*guard {
-        let (g, _) = thread.inner.cvar.wait_timeout_ms(guard, ms).unwrap();
+        let (g, _) = thread.inner.cvar.wait_timeout(guard, dur).unwrap();
         guard = g;
     }
     *guard = false;
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;