Skip to main content

time/interop/
systemdatetime_timestamp.rs

1use core::cmp::Ordering;
2use core::ops::Sub;
3use std::time::SystemTime;
4
5#[allow(unused_imports)] // MSRV of 1.87
6use num_conv::prelude::*;
7
8use crate::ext::SystemTimeExt;
9use crate::unit::*;
10use crate::{Duration, Timestamp};
11
12impl Sub<SystemTime> for Timestamp {
13    type Output = Duration;
14
15    #[inline]
16    fn sub(self, rhs: SystemTime) -> Self::Output {
17        let lhs_duration = self - Self::UNIX_EPOCH;
18        match rhs.duration_since(SystemTime::UNIX_EPOCH) {
19            Ok(duration) => lhs_duration - duration,
20            Err(err) => lhs_duration + err.duration(),
21        }
22    }
23}
24
25impl Sub<Timestamp> for SystemTime {
26    type Output = Duration;
27
28    #[inline]
29    fn sub(self, rhs: Timestamp) -> Self::Output {
30        let rhs_duration = rhs - Timestamp::UNIX_EPOCH;
31
32        match self.duration_since(Self::UNIX_EPOCH) {
33            Ok(lhs) => lhs - rhs_duration,
34            Err(err) => -(err.duration() + rhs_duration),
35        }
36    }
37}
38
39impl PartialEq<SystemTime> for Timestamp {
40    #[inline]
41    fn eq(&self, other: &SystemTime) -> bool {
42        *self - Self::UNIX_EPOCH == other.signed_duration_since(SystemTime::UNIX_EPOCH)
43    }
44}
45
46impl PartialEq<Timestamp> for SystemTime {
47    #[inline]
48    fn eq(&self, other: &Timestamp) -> bool {
49        other == self
50    }
51}
52
53impl PartialOrd<SystemTime> for Timestamp {
54    #[inline]
55    fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> {
56        (*self - Self::UNIX_EPOCH).partial_cmp(&other.signed_duration_since(SystemTime::UNIX_EPOCH))
57    }
58}
59
60impl PartialOrd<Timestamp> for SystemTime {
61    #[inline]
62    fn partial_cmp(&self, other: &Timestamp) -> Option<Ordering> {
63        other.partial_cmp(self).map(Ordering::reverse)
64    }
65}
66
67impl From<SystemTime> for Timestamp {
68    /// # Panics
69    ///
70    /// This may panic if an overflow occurs.
71    #[inline]
72    #[track_caller]
73    fn from(datetime: SystemTime) -> Self {
74        let duration = datetime.signed_duration_since(SystemTime::UNIX_EPOCH);
75        let mut seconds = duration.whole_seconds();
76        let mut nanoseconds = duration.subsec_nanoseconds();
77
78        if nanoseconds < 0 {
79            seconds -= 1;
80            nanoseconds += Nanosecond::per_t::<i32>(Second);
81        }
82
83        Self::new(seconds, nanoseconds.cast_unsigned())
84            .expect("SystemTime value is out of valid range")
85    }
86}
87
88impl From<Timestamp> for SystemTime {
89    /// # Panics
90    ///
91    /// This may panic if an overflow occurs.
92    #[inline]
93    #[track_caller]
94    fn from(timestamp: Timestamp) -> Self {
95        Self::UNIX_EPOCH + (timestamp - Timestamp::UNIX_EPOCH)
96    }
97}
98
99#[cfg(test)]
100mod test {
101    use super::*;
102    use crate::ext::NumericalDuration;
103
104    #[test]
105    fn systime_to_timestamp() -> crate::Result<()> {
106        let ts = Timestamp::from(SystemTime::UNIX_EPOCH + 5.seconds());
107        assert_eq!(ts, Timestamp::from_seconds(5)?);
108
109        let ts = Timestamp::from(SystemTime::UNIX_EPOCH - 5.seconds());
110        assert_eq!(ts, Timestamp::from_seconds(-5)?);
111
112        let ts = Timestamp::from(SystemTime::UNIX_EPOCH + 5.seconds() + 1.milliseconds());
113        assert_eq!(ts, Timestamp::from_milliseconds(5_001)?);
114
115        let ts = Timestamp::from(SystemTime::UNIX_EPOCH - 5.seconds() - 1.milliseconds());
116        assert_eq!(ts, Timestamp::from_milliseconds(-5_001)?);
117
118        Ok(())
119    }
120}