iggy_common/utils/
timestamp.rs1use chrono::{DateTime, Local, Utc};
20use core::fmt;
21use serde::{
22 Deserialize, Deserializer, Serialize, Serializer,
23 de::{self, Visitor},
24};
25use std::{
26 ops::{Add, Sub},
27 time::{Duration, SystemTime, UNIX_EPOCH},
28};
29
30use crate::IggyDuration;
31
32#[derive(Debug, Clone, Copy, Eq, PartialEq)]
46pub struct IggyTimestamp(SystemTime);
47
48pub const UTC_TIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S";
49
50impl IggyTimestamp {
51 pub fn now() -> Self {
52 IggyTimestamp::default()
53 }
54
55 pub fn zero() -> Self {
56 IggyTimestamp(UNIX_EPOCH)
57 }
58
59 pub fn to_secs(&self) -> u64 {
60 self.0.duration_since(UNIX_EPOCH).unwrap().as_secs()
61 }
62
63 pub fn as_micros(&self) -> u64 {
64 self.0.duration_since(UNIX_EPOCH).unwrap().as_micros() as u64
65 }
66
67 pub fn as_millis(&self) -> u64 {
68 self.0.duration_since(UNIX_EPOCH).unwrap().as_millis() as u64
69 }
70
71 pub fn as_nanos(&self) -> u128 {
72 self.0.duration_since(UNIX_EPOCH).unwrap().as_nanos()
73 }
74
75 pub fn to_rfc3339_string(&self) -> String {
76 DateTime::<Utc>::from(self.0).to_rfc3339()
77 }
78
79 pub fn to_utc_string(&self, format: &str) -> String {
80 DateTime::<Utc>::from(self.0).format(format).to_string()
81 }
82
83 pub fn to_local_string(&self, format: &str) -> String {
84 DateTime::<Local>::from(self.0).format(format).to_string()
85 }
86}
87
88impl From<u64> for IggyTimestamp {
89 fn from(timestamp: u64) -> Self {
90 IggyTimestamp(UNIX_EPOCH + Duration::from_micros(timestamp))
91 }
92}
93
94impl From<IggyTimestamp> for u64 {
95 fn from(timestamp: IggyTimestamp) -> u64 {
96 timestamp.as_micros()
97 }
98}
99
100impl From<SystemTime> for IggyTimestamp {
101 fn from(timestamp: SystemTime) -> Self {
102 IggyTimestamp(timestamp)
103 }
104}
105
106impl Add<SystemTime> for IggyTimestamp {
107 type Output = IggyTimestamp;
108
109 fn add(self, other: SystemTime) -> IggyTimestamp {
110 IggyTimestamp(self.0 + other.duration_since(UNIX_EPOCH).unwrap())
111 }
112}
113
114impl Sub<SystemTime> for IggyTimestamp {
115 type Output = IggyTimestamp;
116
117 fn sub(self, rhs: SystemTime) -> Self::Output {
118 IggyTimestamp(self.0 - rhs.duration_since(UNIX_EPOCH).unwrap())
119 }
120}
121
122impl Add<IggyDuration> for IggyTimestamp {
123 type Output = IggyTimestamp;
124
125 fn add(self, other: IggyDuration) -> Self::Output {
126 IggyTimestamp(self.0 + other.get_duration())
127 }
128}
129
130impl Sub for IggyTimestamp {
131 type Output = Duration;
132
133 fn sub(self, rhs: Self) -> Self::Output {
134 self.0
135 .duration_since(rhs.0)
136 .expect("Failed to subtract timestamps rhs < self")
137 }
138}
139
140impl Default for IggyTimestamp {
141 fn default() -> Self {
142 Self(SystemTime::now())
143 }
144}
145
146impl fmt::Display for IggyTimestamp {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 write!(f, "{}", self.to_utc_string(UTC_TIME_FORMAT))
149 }
150}
151
152impl Serialize for IggyTimestamp {
153 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
154 where
155 S: Serializer,
156 {
157 let timestamp = self.as_micros();
158 serializer.serialize_u64(timestamp)
159 }
160}
161
162impl<'de> Deserialize<'de> for IggyTimestamp {
163 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
164 where
165 D: Deserializer<'de>,
166 {
167 deserializer.deserialize_u64(IggyTimestampVisitor)
168 }
169}
170struct IggyTimestampVisitor;
171
172impl Visitor<'_> for IggyTimestampVisitor {
173 type Value = IggyTimestamp;
174
175 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
176 formatter.write_str("a microsecond timestamp as a u64")
177 }
178
179 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
180 where
181 E: de::Error,
182 {
183 Ok(IggyTimestamp::from(value))
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_timestamp_get() {
193 let timestamp = IggyTimestamp::now();
194 assert!(timestamp.as_micros() > 0);
195 }
196
197 #[test]
198 fn test_timestamp_to_micros() {
199 let timestamp = IggyTimestamp::from(1663472051111);
200 assert_eq!(timestamp.as_micros(), 1663472051111);
201 }
202
203 #[test]
204 fn test_timestamp_to_string() {
205 let timestamp = IggyTimestamp::from(1694968446131680);
206 assert_eq!(
207 timestamp.to_utc_string("%Y-%m-%d %H:%M:%S"),
208 "2023-09-17 16:34:06"
209 );
210 }
211
212 #[test]
213 fn test_timestamp_from_u64() {
214 let timestamp = IggyTimestamp::from(1663472051111);
215 assert_eq!(timestamp.as_micros(), 1663472051111);
216 }
217}