t2t_core/interop/
system_time.rs1use core::time::Duration;
4use std::time::{SystemTime, UNIX_EPOCH};
5
6use crate::errors::narrow;
7use crate::{OutOfRangeError, Timestamp};
8
9impl From<Timestamp> for SystemTime {
11 #[inline]
12 fn from(instant: Timestamp) -> Self {
13 let span = Duration::from_nanos(instant.0.unsigned_abs());
14 let system_time =
15 if instant.0 < 0 { UNIX_EPOCH.checked_sub(span) } else { UNIX_EPOCH.checked_add(span) };
16 system_time.unwrap_or(UNIX_EPOCH)
17 }
18}
19
20impl TryFrom<SystemTime> for Timestamp {
22 type Error = OutOfRangeError;
23
24 #[inline]
25 fn try_from(instant: SystemTime) -> Result<Self, Self::Error> {
26 let nanos = match instant.duration_since(UNIX_EPOCH) {
27 Ok(span) => narrow(span.as_nanos()),
28 Err(error) => narrow(0_i128.saturating_sub_unsigned(error.duration().as_nanos())),
29 };
30 nanos.map(Self)
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use core::time::Duration;
37 use std::time::{SystemTime, UNIX_EPOCH};
38
39 use rstest::rstest;
40
41 use crate::{OutOfRangeError, Timestamp};
42
43 #[rstest]
44 #[case::the_epoch(0)]
45 #[case::a_nanosecond_after(1)]
46 #[case::a_nanosecond_before(-1)]
47 #[case::the_earliest(i64::MIN)]
48 #[case::the_latest(i64::MAX)]
49 fn an_instant_crosses_both_ways(#[case] nanos: i64) {
50 let instant = Timestamp::from_nanos(nanos);
51 assert_eq!(Timestamp::try_from(SystemTime::from(instant)), Ok(instant), "and back");
52 }
53
54 #[test]
55 fn a_system_time_outside_the_range_is_refused() {
56 let span = Duration::from_secs(1 << 40);
57 let far_future = UNIX_EPOCH.checked_add(span).expect("a moment 35,000 years on");
58 let distant_past = UNIX_EPOCH.checked_sub(span).expect("a moment 35,000 years back");
59 assert_eq!(Timestamp::try_from(far_future), Err(OutOfRangeError), "after 2262");
60 assert_eq!(Timestamp::try_from(distant_past), Err(OutOfRangeError), "before 1677");
61 }
62}