1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use crate::time::{Duration, SystemTimeError};
use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::{fmt, time};

/// A measurement of the system clock, useful for talking to external entities
/// like the file system or other processes.
///
/// This corresponds to [`std::time::SystemTime`].
///
/// Note that this `SystemTime` has no `now`, `elapsed` methods. To obtain the
/// current time or measure the duration to the current time, you must first
/// obtain a [`SystemClock`], and then call [`SystemClock::now`] or
/// [`SystemClock::elapsed`] instead. The `UNIX_EPOCH` constant is at
/// [`SystemClock::UNIX_EPOCH`].
///
/// Similar to the [`filetime` crate], when
/// `RUSTFLAGS=--cfg emulate_second_only_system` is set, `SystemTime` will
/// round times from the operating system down to the second. This emulates
/// the behavior of some file systems, mostly
/// [HFS], allowing debugging on other hardware.
///
/// [`SystemClock`]: crate::time::SystemClock
/// [`SystemClock::now`]: crate::time::SystemClock::now
/// [`SystemClock::elapsed`]: crate::time::SystemClock::elapsed
/// [`SystemClock::UNIX_EPOCH`]: crate::time::SystemClock::UNIX_EPOCH
/// [`filetime` crate]: https://crates.io/crates/filetime
/// [HFS]: https://en.wikipedia.org/wiki/HFS_Plus
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct SystemTime {
    pub(crate) std: time::SystemTime,
}

impl SystemTime {
    /// Constructs a new instance of `Self` from the given
    /// [`std::time::SystemTime`].
    // TODO: Make this a `const fn` once `time::Duration::checked_add` is a `const fn`.
    #[inline]
    pub fn from_std(std: time::SystemTime) -> Self {
        if cfg!(emulate_second_only_system) {
            let duration = std.duration_since(time::SystemTime::UNIX_EPOCH).unwrap();
            let secs = time::Duration::from_secs(duration.as_secs());
            Self {
                std: time::SystemTime::UNIX_EPOCH.checked_add(secs).unwrap(),
            }
        } else {
            Self { std }
        }
    }

    /// Constructs a new instance of [`std::time::SystemTime`] from the given
    /// `Self`.
    #[inline]
    pub const fn into_std(self) -> time::SystemTime {
        self.std
    }

    /// Returns the amount of time elapsed from another instant to this one.
    ///
    /// This corresponds to [`std::time::SystemTime::duration_since`].
    #[inline]
    pub fn duration_since(&self, earlier: Self) -> Result<Duration, SystemTimeError> {
        self.std.duration_since(earlier.std)
    }

    /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be
    /// represented as `SystemTime` (which means it's inside the bounds of the
    /// underlying data structure), `None` otherwise.
    ///
    /// This corresponds to [`std::time::SystemTime::checked_add`].
    #[inline]
    pub fn checked_add(&self, duration: Duration) -> Option<Self> {
        self.std.checked_add(duration).map(Self::from_std)
    }

    /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be
    /// represented as `SystemTime` (which means it's inside the bounds of the
    /// underlying data structure), `None` otherwise.
    ///
    /// This corresponds to [`std::time::SystemTime::checked_sub`].
    #[inline]
    pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
        self.std.checked_sub(duration).map(Self::from_std)
    }
}

impl Add<Duration> for SystemTime {
    type Output = Self;

    /// # Panics
    ///
    /// This function may panic if the resulting point in time cannot be
    /// represented by the underlying data structure. See
    /// [`SystemTime::checked_add`] for a version without panic.
    #[inline]
    fn add(self, dur: Duration) -> Self {
        self.checked_add(dur)
            .expect("overflow when adding duration to instant")
    }
}

impl AddAssign<Duration> for SystemTime {
    #[inline]
    fn add_assign(&mut self, other: Duration) {
        *self = *self + other;
    }
}

impl Sub<Duration> for SystemTime {
    type Output = Self;

    #[inline]
    fn sub(self, dur: Duration) -> Self {
        self.checked_sub(dur)
            .expect("overflow when subtracting duration from instant")
    }
}

impl SubAssign<Duration> for SystemTime {
    #[inline]
    fn sub_assign(&mut self, other: Duration) {
        *self = *self - other;
    }
}

impl fmt::Debug for SystemTime {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.std.fmt(f)
    }
}