moloch_core/agent/
timestamp.rs1use serde::{Deserialize, Serialize};
10use std::time::Duration;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
18pub struct Timestamp(i64);
19
20impl Timestamp {
21 pub fn now() -> Self {
23 Self(chrono::Utc::now().timestamp_millis())
24 }
25
26 pub fn from_millis(ms: i64) -> Self {
28 Self(ms)
29 }
30
31 pub fn as_millis(&self) -> i64 {
33 self.0
34 }
35
36 pub fn elapsed(&self) -> Duration {
40 let now = chrono::Utc::now().timestamp_millis();
41 Duration::from_millis((now - self.0).max(0) as u64)
42 }
43
44 pub fn is_expired(&self, ttl: Duration) -> bool {
48 self.elapsed() > ttl
49 }
50}
51
52impl std::fmt::Display for Timestamp {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 write!(f, "{}ms", self.0)
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn timestamp_now_returns_milliseconds() {
64 let ts = Timestamp::now();
65 assert!(ts.as_millis() > 1_577_836_800_000);
67 }
68
69 #[test]
70 fn timestamp_ordering() {
71 let t1 = Timestamp::now();
72 std::thread::sleep(Duration::from_millis(2));
73 let t2 = Timestamp::now();
74 assert!(t2 > t1);
75 }
76
77 #[test]
78 fn timestamp_elapsed_since() {
79 let t1 = Timestamp::now();
80 std::thread::sleep(Duration::from_millis(10));
81 let elapsed = t1.elapsed();
82 assert!(elapsed.as_millis() >= 10);
83 }
84
85 #[test]
86 fn timestamp_from_millis_roundtrip() {
87 let ms = 1706500000000_i64;
88 let ts = Timestamp::from_millis(ms);
89 assert_eq!(ts.as_millis(), ms);
90 }
91
92 #[test]
93 fn timestamp_is_expired_after_duration() {
94 let ts = Timestamp::from_millis(chrono::Utc::now().timestamp_millis() - 5000);
95 let ttl = Duration::from_secs(3);
96 assert!(ts.is_expired(ttl));
97 }
98
99 #[test]
100 fn timestamp_is_not_expired_within_duration() {
101 let ts = Timestamp::now();
102 let ttl = Duration::from_secs(3600);
103 assert!(!ts.is_expired(ttl));
104 }
105}