1use core::cmp::Ordering;
8
9const MATTER_EPOCH_UNIX_OFFSET: u64 = 946_684_800;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub struct MatterTime(pub u32);
20
21impl MatterTime {
22 pub const NO_EXPIRY: Self = Self(0);
24
25 #[must_use]
28 pub fn from_unix_secs(unix: u64) -> Self {
29 let matter = unix.saturating_sub(MATTER_EPOCH_UNIX_OFFSET);
30 let clamped = u32::try_from(matter).unwrap_or(u32::MAX);
31 Self(clamped)
32 }
33
34 #[must_use]
36 pub fn to_unix_secs(self) -> u64 {
37 u64::from(self.0) + MATTER_EPOCH_UNIX_OFFSET
38 }
39}
40
41impl PartialOrd for MatterTime {
42 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
43 Some(self.cmp(other))
44 }
45}
46
47impl Ord for MatterTime {
48 fn cmp(&self, other: &Self) -> Ordering {
49 self.0.cmp(&other.0)
50 }
51}
52
53#[cfg(test)]
54#[allow(clippy::unwrap_used)] mod tests {
56 use super::*;
57
58 #[test]
59 fn unix_to_matter_to_unix_round_trip() {
60 let unix = 1_763_337_600u64;
61 let matter = MatterTime::from_unix_secs(unix);
62 assert_eq!(matter.to_unix_secs(), unix);
63 }
64
65 #[test]
66 fn matter_epoch_zero_maps_to_2000_01_01() {
67 assert_eq!(MatterTime(0).to_unix_secs(), MATTER_EPOCH_UNIX_OFFSET);
68 }
69
70 #[test]
71 fn no_expiry_constant_is_zero() {
72 assert_eq!(MatterTime::NO_EXPIRY, MatterTime(0));
73 }
74
75 #[test]
76 fn pre_matter_epoch_unix_saturates_to_zero() {
77 let unix = 946_684_799u64;
78 assert_eq!(MatterTime::from_unix_secs(unix), MatterTime(0));
79 }
80
81 #[test]
82 fn unix_at_matter_u32_max_boundary_is_exact() {
83 let unix = MATTER_EPOCH_UNIX_OFFSET + u64::from(u32::MAX);
87 assert_eq!(MatterTime::from_unix_secs(unix), MatterTime(u32::MAX));
88 }
89
90 #[test]
91 fn unix_just_above_matter_u32_max_saturates() {
92 let unix = MATTER_EPOCH_UNIX_OFFSET + u64::from(u32::MAX) + 1;
96 assert_eq!(MatterTime::from_unix_secs(unix), MatterTime(u32::MAX));
97 }
98
99 #[test]
100 fn unix_u64_max_saturates_to_u32_max() {
101 assert_eq!(MatterTime::from_unix_secs(u64::MAX), MatterTime(u32::MAX));
103 }
104
105 #[test]
106 fn ordering_uses_native_u32() {
107 assert!(MatterTime(100) < MatterTime(200));
108 assert!(MatterTime(u32::MAX) > MatterTime(0));
109 }
110}