1use core::fmt;
6
7#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[repr(transparent)]
11pub struct Timestamp(u64);
12
13impl Timestamp {
14 pub const EPOCH: Self = Self(0);
16 pub const MAX: Self = Self(u64::MAX);
18
19 #[inline]
21 pub const fn from_micros(micros: u64) -> Self {
22 Self(micros)
23 }
24
25 #[inline]
27 pub const fn from_millis(millis: u64) -> Self {
28 Self(millis.saturating_mul(1000))
29 }
30
31 #[inline]
33 pub const fn from_secs(secs: u64) -> Self {
34 Self(secs.saturating_mul(1_000_000))
35 }
36
37 #[inline]
39 pub const fn as_micros(&self) -> u64 {
40 self.0
41 }
42
43 #[inline]
45 pub const fn as_millis(&self) -> u64 {
46 self.0 / 1000
47 }
48
49 #[inline]
51 pub const fn as_secs(&self) -> u64 {
52 self.0 / 1_000_000
53 }
54
55 #[inline]
57 pub const fn is_zero(&self) -> bool {
58 self.0 == 0
59 }
60
61 #[inline]
63 pub const fn saturating_add(self, micros: u64) -> Self {
64 Self(self.0.saturating_add(micros))
65 }
66
67 #[inline]
69 pub const fn saturating_sub(self, micros: u64) -> Self {
70 Self(self.0.saturating_sub(micros))
71 }
72
73 pub const fn duration_since(self, earlier: Self) -> u64 {
75 self.0.saturating_sub(earlier.0)
76 }
77}
78
79impl fmt::Debug for Timestamp {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 write!(f, "Timestamp({}µs)", self.0)
82 }
83}
84
85impl fmt::Display for Timestamp {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 write!(f, "{}µs", self.0)
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn conversions() {
97 let ts = Timestamp::from_secs(1700000000);
98 assert_eq!(ts.as_secs(), 1700000000);
99 assert_eq!(ts.as_millis(), 1700000000000);
100 assert_eq!(ts.as_micros(), 1700000000000000);
101 }
102
103 #[test]
104 fn ordering() {
105 let a = Timestamp::from_secs(1);
106 let b = Timestamp::from_secs(2);
107 assert!(a < b);
108 }
109
110 #[test]
111 fn arithmetic() {
112 let ts = Timestamp::from_secs(10);
113 assert_eq!(ts.saturating_add(1_000_000), Timestamp::from_secs(11));
114 assert_eq!(ts.saturating_sub(5_000_000), Timestamp::from_secs(5));
115 assert_eq!(Timestamp::from_secs(0).saturating_sub(1), Timestamp::EPOCH);
116 }
117
118 #[test]
119 fn duration_since() {
120 let a = Timestamp::from_secs(10);
121 let b = Timestamp::from_secs(15);
122 assert_eq!(b.duration_since(a), 5_000_000);
123 }
124}