1use core::fmt::{self, Display, Formatter};
8use core::time::Duration;
9use shared::unix_to_human_time;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
37#[repr(transparent)]
38pub struct Time {
39 seconds: u64,
40}
41
42impl Time {
43 pub const fn new(seconds: u64) -> Self {
58 Self { seconds }
59 }
60
61 pub const fn as_u64(self) -> u64 {
77 self.seconds
78 }
79}
80
81impl From<Duration> for Time {
85 fn from(duration: Duration) -> Self {
86 Self {
87 seconds: duration.as_secs(),
88 }
89 }
90}
91
92impl From<Time> for Duration {
96 fn from(time: Time) -> Self {
97 Duration::new(time.seconds, 0)
98 }
99}
100
101impl Display for Time {
102 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
103 let (year, month, day, hour, minute, second) = unix_to_human_time(self.seconds as i64);
104
105 write!(
106 f,
107 "{year:04}-{month:02}-{day:02} {hour:02}:{minute:02}:{second:02}",
108 )
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use alloc::{format, vec};
116
117 #[test]
118 fn test_time_creation() {
119 let time = Time::new(1640995200); assert_eq!(time.as_u64(), 1640995200);
121 }
122
123 #[test]
124 fn test_time_epoch() {
125 let epoch = Time::new(0);
126 assert_eq!(epoch.as_u64(), 0);
127 }
128
129 #[test]
130 fn test_time_const_operations() {
131 const TIME: Time = Time::new(1234567890);
133 const SECONDS: u64 = TIME.as_u64();
134
135 assert_eq!(SECONDS, 1234567890);
136 assert_eq!(TIME.as_u64(), 1234567890);
137 }
138
139 #[test]
140 fn test_time_comparison() {
141 let early = Time::new(1000);
142 let late = Time::new(2000);
143
144 assert!(early < late);
145 assert!(late > early);
146 assert!(early <= late);
147 assert!(late >= early);
148 assert!(early <= early);
149 assert!(late >= late);
150 assert_eq!(early, early);
151 assert_ne!(early, late);
152 }
153
154 #[test]
155 fn test_time_ordering() {
156 let mut times = [
157 Time::new(3000),
158 Time::new(1000),
159 Time::new(2000),
160 Time::new(500),
161 ];
162
163 times.sort();
164
165 assert_eq!(times[0], Time::new(500));
166 assert_eq!(times[1], Time::new(1000));
167 assert_eq!(times[2], Time::new(2000));
168 assert_eq!(times[3], Time::new(3000));
169 }
170
171 #[test]
172 fn test_time_clone_copy() {
173 let original = Time::new(999);
174 let cloned = original;
175 let copied = original;
176
177 assert_eq!(original, cloned);
178 assert_eq!(original, copied);
179 assert_eq!(cloned, copied);
180
181 assert_eq!(original.as_u64(), 999);
183 }
184
185 #[test]
186 fn test_time_debug() {
187 let time = Time::new(1640995200);
188 let debug_str = format!("{time:?}");
189 assert!(debug_str.contains("Time_type"));
190 assert!(debug_str.contains("1640995200"));
191 }
192
193 #[test]
194 fn test_time_hash() {
195 use alloc::collections::BTreeMap;
196
197 let time1 = Time::new(12345);
198 let time2 = Time::new(12345);
199 let time3 = Time::new(54321);
200
201 let mut map = BTreeMap::new();
203 map.insert(time1, "first");
204 map.insert(time2, "second"); map.insert(time3, "third");
206
207 assert_eq!(map.len(), 2); assert_eq!(map.get(&time1), Some(&"second"));
209 assert_eq!(map.get(&time3), Some(&"third"));
210 }
211
212 #[test]
213 fn test_time_from_duration() {
214 let duration = Duration::new(1640995200, 0);
215 let time: Time = duration.into();
216 assert_eq!(time.as_u64(), 1640995200);
217 }
218
219 #[test]
220 fn test_time_to_duration() {
221 let time = Time::new(1640995200);
222 let duration: Duration = time.into();
223 assert_eq!(duration.as_secs(), 1640995200);
224 }
225
226 #[test]
227 fn test_time_display_formatting() {
228 let time = Time::new(0); let display_str = format!("{time}");
231
232 assert!(display_str.contains("-"));
235 assert!(display_str.contains(":"));
236 assert!(display_str.len() > 10); }
238
239 #[test]
240 fn test_time_display_various_dates() {
241 let times = vec![
243 Time::new(0), Time::new(86400), Time::new(1640995200), ];
247
248 for time in times {
249 let display_str = format!("{time}");
250 assert!(display_str.len() >= 19); assert!(display_str.contains("-"));
253 assert!(display_str.contains(":"));
254 assert!(display_str.contains(" "));
255 }
256 }
257
258 #[test]
259 fn test_time_max_value() {
260 let max_time = Time::new(u64::MAX);
261 assert_eq!(max_time.as_u64(), u64::MAX);
262
263 let duration: Duration = max_time.into();
265 assert_eq!(duration.as_secs(), u64::MAX);
266 }
267
268 #[test]
269 fn test_time_zero_and_max_comparison() {
270 let zero = Time::new(0);
271 let max = Time::new(u64::MAX);
272
273 assert!(zero < max);
274 assert!(max > zero);
275 assert_ne!(zero, max);
276 }
277
278 #[test]
279 fn test_time_round_trip_conversions() {
280 let original_seconds = 1640995200u64;
281
282 let time = Time::new(original_seconds);
284 let duration: Duration = time.into();
285 let back_to_time: Time = duration.into();
286
287 assert_eq!(time, back_to_time);
288 assert_eq!(original_seconds, back_to_time.as_u64());
289 }
290
291 #[test]
292 fn test_time_type_size() {
293 use core::mem::{align_of, size_of};
294
295 assert_eq!(size_of::<Time>(), size_of::<u64>());
297 assert_eq!(align_of::<Time>(), align_of::<u64>());
298 }
299
300 #[test]
301 fn test_time_sequence() {
302 use alloc::vec::Vec;
304 let times: Vec<Time> = (0..10)
305 .map(|i| Time::new(i * 86400)) .collect();
307
308 for i in 1..times.len() {
310 assert!(times[i - 1] < times[i]);
311 }
312 }
313}