1use std::time::Duration;
2
3#[cfg(not(target_family = "wasm"))]
4use std::time::{SystemTime, UNIX_EPOCH};
5#[cfg(target_family = "wasm")]
6use web_time::{SystemTime, UNIX_EPOCH};
7
8use crate::Error;
9
10#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
11pub struct Timestamp(pub(crate) Duration);
12
13const ANSI_EPOCH_DIFF_NANOS: u64 = 11_644_473_600_000_000_000;
14
15impl Timestamp {
16 pub fn now() -> Self {
20 Self(
21 SystemTime::now()
22 .duration_since(UNIX_EPOCH)
23 .expect("System time is below UNIX EPOCH"),
24 )
25 }
26 pub fn now_rounded() -> Self {
27 let t = Self::now();
28 Self(Duration::from_secs(t.0.as_secs()))
29 }
30 #[inline]
31 pub fn elapsed(self) -> Result<Duration, Error> {
32 let now = Timestamp::now();
33 if now >= self {
34 Ok(now.0 - self.0)
35 } else {
36 Err(Error::TimeWentBackward)
37 }
38 }
39 #[inline]
40 pub fn duration_since(self, earlier: Self) -> Result<Duration, Error> {
41 if self >= earlier {
42 Ok(self.0 - earlier.0)
43 } else {
44 Err(Error::TimeWentBackward)
45 }
46 }
47 pub fn try_from_ansi_to_unix(self) -> Result<Self, Error> {
62 Ok(Self(Duration::from_nanos(
63 u64::try_from(self.0.as_nanos())?
64 .checked_sub(ANSI_EPOCH_DIFF_NANOS)
65 .ok_or_else(|| Error::Convert("Failed to convert from ANSI to UNIX".to_string()))?,
66 )))
67 }
68 pub fn try_from_unix_to_ansi(self) -> Result<Self, Error> {
72 Ok(Self(Duration::from_nanos(
73 u64::try_from(self.0.as_nanos())?
74 .checked_add(ANSI_EPOCH_DIFF_NANOS)
75 .ok_or_else(|| Error::Convert("Failed to convert from UNIX to ANSI".to_string()))?,
76 )))
77 }
78}