diff options
Diffstat (limited to 'src/libstd/time')
| -rw-r--r-- | src/libstd/time/duration.rs | 6 | ||||
| -rw-r--r-- | src/libstd/time/mod.rs | 304 |
2 files changed, 307 insertions, 3 deletions
diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index ca04ec81a28..63d517606a0 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -9,7 +9,7 @@ // except according to those terms. use ops::{Add, Sub, Mul, Div}; -use sys::time::SteadyTime; +use time::Instant; const NANOS_PER_SEC: u32 = 1_000_000_000; const NANOS_PER_MILLI: u32 = 1_000_000; @@ -67,9 +67,9 @@ impl Duration { abstraction", issue = "27799")] pub fn span<F>(f: F) -> Duration where F: FnOnce() { - let start = SteadyTime::now(); + let start = Instant::now(); f(); - &SteadyTime::now() - &start + start.elapsed() } /// Creates a new `Duration` from the specified number of seconds. diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs index 446fbae52f6..95f68712be2 100644 --- a/src/libstd/time/mod.rs +++ b/src/libstd/time/mod.rs @@ -12,7 +12,311 @@ #![stable(feature = "time", since = "1.3.0")] +use error::Error; +use fmt; +use ops::{Add, Sub}; +use sys::time; + #[stable(feature = "time", since = "1.3.0")] pub use self::duration::Duration; mod duration; + +/// A measurement of a monotonically increasing clock which is suitable for +/// measuring the amount of time that an operation takes. +/// +/// Instants are guaranteed always be greater than any previously measured +/// instant when created, and are often useful for tasks such as measuring +/// benchmarks or timing how long an operation takes. +/// +/// Note, however, that instants are not guaranteed to be **steady**. In other +/// words each tick of the underlying clock may not be the same length (e.g. +/// some seconds may be longer than others). An instant may jump forwards or +/// experience time dilation (slow down or speed up), but it will never go +/// backwards. +/// +/// Instants are opaque types that can only be compared to one another. There is +/// no method to get "the number of seconds" from an instant but instead it only +/// allow learning the duration between two instants (or comparing two +/// instants). +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +pub struct Instant(time::Instant); + +/// A measurement of the system clock appropriate for timestamps such as those +/// on files on the filesystem. +/// +/// Distinct from the `Instant` type, this time measurement **is not +/// monotonic**. This means that you can save a file to the file system, then +/// save another file to the file system, **and the second file has a +/// `SystemTime` measurement earlier than the second**. In other words, an +/// operation that happens after another operation in real time may have an +/// earlier `SystemTime`! +/// +/// Consequently, comparing two `SystemTime` instances to learn about the +/// duration between them returns a `Result` instead of an infallible `Duration` +/// to indicate that this sort of time drift may happen and needs to be handled. +/// +/// Although a `SystemTime` cannot be directly inspected, the `UNIX_EPOCH` +/// constant is provided in this module as an anchor in time to learn +/// information about a `SystemTime`. By calculating the duration from this +/// fixed point in time a `SystemTime` can be converted to a human-readable time +/// or perhaps some other string representation. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +pub struct SystemTime(time::SystemTime); + +/// An error returned from the `duration_from_earlier` method on `SystemTime`, +/// used to learn about why how far in the opposite direction a timestamp lies. +#[derive(Clone, Debug)] +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +pub struct SystemTimeError(Duration); + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl Instant { + /// Returns an instant corresponding to "now". + pub fn now() -> Instant { + Instant(time::Instant::now()) + } + + /// Returns the amount of time elapsed from another instant to this one. + /// + /// # Panics + /// + /// This function will panic if `earlier` is later than `self`, which should + /// only be possible if `earlier` was created after `self`. Because + /// `Instant` is monotonic, the only time that this should happen should be + /// a bug. + pub fn duration_from_earlier(&self, earlier: Instant) -> Duration { + self.0.sub_instant(&earlier.0) + } + + /// Returns the amount of time elapsed since this instant was created. + /// + /// # Panics + /// + /// This function may panic if the current time is earlier than this instant + /// which can happen if an `Instant` is produced synthetically. + pub fn elapsed(&self) -> Duration { + Instant::now().duration_from_earlier(*self) + } +} + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl Add<Duration> for Instant { + type Output = Instant; + + fn add(self, other: Duration) -> Instant { + Instant(self.0.add_duration(&other)) + } +} + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl Sub<Duration> for Instant { + type Output = Instant; + + fn sub(self, other: Duration) -> Instant { + Instant(self.0.sub_duration(&other)) + } +} + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl fmt::Debug for Instant { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl SystemTime { + /// Returns the system time corresponding to "now". + pub fn now() -> SystemTime { + SystemTime(time::SystemTime::now()) + } + + /// Returns the amount of time elapsed from an earlier point in time. + /// + /// This function may fail because measurements taken earlier are not + /// guaranteed to always be before later measurements (due to anomalies such + /// as the system clock being adjusted either forwards or backwards). + /// + /// If successful, `Ok(duration)` is returned where the duration represents + /// the amount of time elapsed from the specified measurement to this one. + /// + /// Returns an `Err` if `earlier` is later than `self`, and the error + /// contains how far from `self` the time is. + pub fn duration_from_earlier(&self, earlier: SystemTime) + -> Result<Duration, SystemTimeError> { + self.0.sub_time(&earlier.0).map_err(SystemTimeError) + } + + /// Returns the amount of time elapsed since this system time was created. + /// + /// This function may fail as the underlying system clock is susceptible to + /// drift and updates (e.g. the system clock could go backwards), so this + /// function may not always succeed. If successful, `Ok(duration)` is + /// returned where the duration represents the amount of time elapsed from + /// this time measurement to the current time. + /// + /// Returns an `Err` if `self` is later than the current system time, and + /// the error contains how far from the current system time `self` is. + pub fn elapsed(&self) -> Result<Duration, SystemTimeError> { + SystemTime::now().duration_from_earlier(*self) + } +} + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl Add<Duration> for SystemTime { + type Output = SystemTime; + + fn add(self, dur: Duration) -> SystemTime { + SystemTime(self.0.add_duration(&dur)) + } +} + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl Sub<Duration> for SystemTime { + type Output = SystemTime; + + fn sub(self, dur: Duration) -> SystemTime { + SystemTime(self.0.sub_duration(&dur)) + } +} + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl fmt::Debug for SystemTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +/// An anchor in time which can be used to create new `SystemTime` instances or +/// learn about where in time a `SystemTime` lies. +/// +/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with +/// respect to the system clock. Using `duration_from_earlier` on an existing +/// `SystemTime` instance can tell how far away from this point in time a +/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a +/// `SystemTime` instance to represent another fixed point in time. +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH); + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl SystemTimeError { + /// Returns the positive duration which represents how far forward the + /// second system time was from the first. + /// + /// A `SystemTimeError` is returned from the `duration_from_earlier` + /// operation whenever the second duration, `earlier`, actually represents a + /// point later in time than the `self` of the method call. This function + /// will extract and return the amount of time later `earlier` actually is. + pub fn duration(&self) -> Duration { + self.0 + } +} + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl Error for SystemTimeError { + fn description(&self) -> &str { "other time was not earlier than self" } +} + +#[unstable(feature = "time2", reason = "recently added", issue = "29866")] +impl fmt::Display for SystemTimeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "second time provided was later than self") + } +} + +#[cfg(test)] +mod tests { + use super::{Instant, SystemTime, Duration, UNIX_EPOCH}; + + #[test] + fn instant_monotonic() { + let a = Instant::now(); + let b = Instant::now(); + assert!(b >= a); + } + + #[test] + fn instant_elapsed() { + let a = Instant::now(); + a.elapsed(); + } + + #[test] + fn instant_math() { + let a = Instant::now(); + let b = Instant::now(); + let dur = b.duration_from_earlier(a); + assert_eq!(b - dur, a); + assert_eq!(a + dur, b); + + let second = Duration::new(1, 0); + assert_eq!(a - second + second, a); + } + + #[test] + #[should_panic] + fn instant_duration_panic() { + let a = Instant::now(); + (a - Duration::new(1, 0)).duration_from_earlier(a); + } + + #[test] + fn system_time_math() { + let a = SystemTime::now(); + let b = SystemTime::now(); + match b.duration_from_earlier(a) { + Ok(dur) if dur == Duration::new(0, 0) => { + assert_eq!(a, b); + } + Ok(dur) => { + assert!(b > a); + assert_eq!(b - dur, a); + assert_eq!(a + dur, b); + } + Err(dur) => { + let dur = dur.duration(); + assert!(a > b); + assert_eq!(b + dur, a); + assert_eq!(b - dur, a); + } + } + + let second = Duration::new(1, 0); + assert_eq!(a.duration_from_earlier(a - second).unwrap(), second); + assert_eq!(a.duration_from_earlier(a + second).unwrap_err().duration(), + second); + + assert_eq!(a - second + second, a); + + let eighty_years = second * 60 * 60 * 24 * 365 * 80; + assert_eq!(a - eighty_years + eighty_years, a); + assert_eq!(a - (eighty_years * 10) + (eighty_years * 10), a); + } + + #[test] + fn system_time_elapsed() { + let a = SystemTime::now(); + drop(a.elapsed()); + } + + #[test] + fn since_epoch() { + let ts = SystemTime::now(); + let a = ts.duration_from_earlier(UNIX_EPOCH).unwrap(); + let b = ts.duration_from_earlier(UNIX_EPOCH - Duration::new(1, 0)).unwrap(); + assert!(b > a); + assert_eq!(b - a, Duration::new(1, 0)); + + // let's assume that we're all running computers later than 2000 + let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30; + assert!(a > thirty_years); + + // let's assume that we're all running computers earlier than 2090. + // Should give us ~70 years to fix this! + let hundred_twenty_years = thirty_years * 4; + assert!(a < hundred_twenty_years); + } +} |
