use std::time::SystemTime; use crate::Duration; /// Sealed trait to prevent downstream implementations. mod sealed { /// A trait that cannot be implemented by downstream users. pub trait Sealed: Sized {} impl Sealed for std::time::SystemTime {} } /// An extension trait for [`std::time::SystemTime`] that adds methods for /// [`time::Duration`](Duration)s. pub trait SystemTimeExt: sealed::Sealed { /// Adds the given [`Duration`] to the [`SystemTime`], returning `None` is the result cannot be /// represented by the underlying data structure. fn checked_add_signed(&self, duration: Duration) -> Option; /// Subtracts the given [`Duration`] from the [`SystemTime`], returning `None` is the result /// cannot be represented by the underlying data structure. fn checked_sub_signed(&self, duration: Duration) -> Option; /// Returns the amount of time elapsed from another [`SystemTime`] to this one. This will be /// negative if `earlier` is later than `self.` /// /// If the duration cannot be stored by [`Duration`], the value will be saturated to /// [`Duration::MIN`] or [`Duration::MAX`] as appropriate. /// /// # Example /// /// ```rust /// # use std::time::SystemTime; /// # use time::ext::{NumericalDuration, SystemTimeExt}; /// let epoch = SystemTime::UNIX_EPOCH; /// let other = epoch + 1.seconds(); /// assert_eq!(other.signed_duration_since(epoch), 1.seconds()); /// assert_eq!(epoch.signed_duration_since(other), (-1).seconds()); /// ``` fn signed_duration_since(&self, earlier: Self) -> Duration; } impl SystemTimeExt for SystemTime { #[inline] fn checked_add_signed(&self, duration: Duration) -> Option { if duration.is_positive() { self.checked_add(duration.unsigned_abs()) } else if duration.is_negative() { self.checked_sub(duration.unsigned_abs()) } else { Some(*self) } } #[inline] fn checked_sub_signed(&self, duration: Duration) -> Option { if duration.is_positive() { self.checked_sub(duration.unsigned_abs()) } else if duration.is_negative() { self.checked_add(duration.unsigned_abs()) } else { Some(*self) } } #[inline] fn signed_duration_since(&self, earlier: Self) -> Duration { match self.duration_since(earlier) { Ok(duration) => duration.try_into().unwrap_or(Duration::MAX), Err(err) => { let seconds = match i64::try_from(err.duration().as_secs()) { Ok(seconds) => -seconds, Err(_) => return Duration::MIN, }; let nanoseconds = -err.duration().subsec_nanos().cast_signed(); // Safety: `nanoseconds` is guaranteed to be between -999_999_999 and 0 // inclusive. unsafe { Duration::new_unchecked(seconds, nanoseconds) } } } } }