1use serde::{Deserialize, Serialize};
6use std::fmt;
7use std::time::{Duration, SystemTime, UNIX_EPOCH};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
13#[serde(transparent)]
14pub struct TimestampSecs(pub i64);
15
16impl TimestampSecs {
17 #[must_use]
19 pub fn now() -> Self {
20 let duration = SystemTime::now()
21 .duration_since(UNIX_EPOCH)
22 .unwrap_or_default();
23 Self(duration.as_secs() as i64)
24 }
25
26 #[must_use]
28 pub const fn from_millis(ms: i64) -> Self {
29 Self(ms / 1000)
30 }
31
32 #[must_use]
34 pub const fn as_millis(&self) -> i64 {
35 self.0 * 1000
36 }
37
38 #[must_use]
40 pub fn seconds_ago(seconds: i64) -> Self {
41 Self(Self::now().0 - seconds)
42 }
43
44 #[must_use]
46 pub fn minutes_ago(minutes: i64) -> Self {
47 Self::seconds_ago(minutes * 60)
48 }
49
50 #[must_use]
52 pub fn hours_ago(hours: i64) -> Self {
53 Self::seconds_ago(hours * 3600)
54 }
55
56 #[must_use]
58 pub fn days_ago(days: i64) -> Self {
59 Self::seconds_ago(days * 86400)
60 }
61
62 #[must_use]
64 pub const fn as_secs(&self) -> i64 {
65 self.0
66 }
67}
68
69impl fmt::Display for TimestampSecs {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 write!(f, "{}", self.0)
72 }
73}
74
75impl From<i64> for TimestampSecs {
76 fn from(secs: i64) -> Self {
77 Self(secs)
78 }
79}
80
81impl From<TimestampSecs> for i64 {
82 fn from(ts: TimestampSecs) -> Self {
83 ts.0
84 }
85}
86
87impl From<Duration> for TimestampSecs {
88 fn from(duration: Duration) -> Self {
89 Self(duration.as_secs() as i64)
90 }
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
97#[serde(transparent)]
98pub struct TimestampMillis(pub i64);
99
100impl TimestampMillis {
101 #[must_use]
103 pub fn now() -> Self {
104 let duration = SystemTime::now()
105 .duration_since(UNIX_EPOCH)
106 .unwrap_or_default();
107 Self(duration.as_millis() as i64)
108 }
109
110 #[must_use]
112 pub const fn as_secs(&self) -> TimestampSecs {
113 TimestampSecs(self.0 / 1000)
114 }
115
116 #[must_use]
118 pub const fn as_millis(&self) -> i64 {
119 self.0
120 }
121}
122
123impl fmt::Display for TimestampMillis {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 write!(f, "{}", self.0)
126 }
127}
128
129impl From<i64> for TimestampMillis {
130 fn from(ms: i64) -> Self {
131 Self(ms)
132 }
133}
134
135impl From<TimestampMillis> for i64 {
136 fn from(ts: TimestampMillis) -> Self {
137 ts.0
138 }
139}
140
141impl From<TimestampSecs> for TimestampMillis {
142 fn from(ts: TimestampSecs) -> Self {
143 Self(ts.0 * 1000)
144 }
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
151#[serde(transparent)]
152pub struct TimestampNanos(pub i64);
153
154impl TimestampNanos {
155 #[must_use]
157 pub fn now() -> Self {
158 let duration = SystemTime::now()
159 .duration_since(UNIX_EPOCH)
160 .unwrap_or_default();
161 Self(duration.as_nanos() as i64)
162 }
163
164 #[must_use]
166 pub const fn as_secs(&self) -> TimestampSecs {
167 TimestampSecs(self.0 / 1_000_000_000)
168 }
169
170 #[must_use]
172 pub const fn as_millis(&self) -> TimestampMillis {
173 TimestampMillis(self.0 / 1_000_000)
174 }
175
176 #[must_use]
178 pub const fn as_nanos(&self) -> i64 {
179 self.0
180 }
181}
182
183impl fmt::Display for TimestampNanos {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 write!(f, "{}", self.0)
186 }
187}
188
189impl From<i64> for TimestampNanos {
190 fn from(ns: i64) -> Self {
191 Self(ns)
192 }
193}
194
195impl From<TimestampNanos> for i64 {
196 fn from(ts: TimestampNanos) -> Self {
197 ts.0
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn test_timestamp_secs_now() {
207 let ts = TimestampSecs::now();
208 assert!(ts.0 > 1577836800);
210 }
211
212 #[test]
213 fn test_timestamp_secs_from_millis() {
214 let ts = TimestampSecs::from_millis(1234567890123);
215 assert_eq!(ts.0, 1234567890);
216 }
217
218 #[test]
219 fn test_timestamp_secs_as_millis() {
220 let ts = TimestampSecs(1234567890);
221 assert_eq!(ts.as_millis(), 1234567890000);
222 }
223
224 #[test]
225 fn test_timestamp_secs_ago() {
226 let now = TimestampSecs::now();
227 let one_hour_ago = TimestampSecs::hours_ago(1);
228 assert_eq!(now.0 - one_hour_ago.0, 3600);
229 }
230
231 #[test]
232 fn test_timestamp_millis_to_secs() {
233 let ms = TimestampMillis(1234567890123);
234 assert_eq!(ms.as_secs().0, 1234567890);
235 }
236
237 #[test]
238 fn test_timestamp_nanos_conversions() {
239 let ns = TimestampNanos(1234567890123456789);
240 assert_eq!(ns.as_secs().0, 1234567890);
241 assert_eq!(ns.as_millis().0, 1234567890123);
242 }
243
244 #[test]
245 fn test_timestamp_secs_serialization() {
246 let ts = TimestampSecs(1234567890);
247 let json = serde_json::to_string(&ts).unwrap();
248 assert_eq!(json, "1234567890");
249
250 let deserialized: TimestampSecs = serde_json::from_str(&json).unwrap();
251 assert_eq!(ts, deserialized);
252 }
253
254 #[test]
255 fn test_timestamp_from_i64() {
256 let ts: TimestampSecs = 1234567890i64.into();
257 assert_eq!(ts.0, 1234567890);
258 }
259
260 #[test]
261 fn test_timestamp_into_i64() {
262 let ts = TimestampSecs(1234567890);
263 let value: i64 = ts.into();
264 assert_eq!(value, 1234567890);
265 }
266
267 #[test]
268 fn test_timestamp_display() {
269 let ts = TimestampSecs(1234567890);
270 assert_eq!(format!("{ts}"), "1234567890");
271 }
272
273 #[test]
274 fn test_timestamp_ordering() {
275 let earlier = TimestampSecs(1000);
276 let later = TimestampSecs(2000);
277 assert!(earlier < later);
278 }
279}