1use std::str::FromStr;
2use crate::date_error::{DateError, DateErrorKind};
3use core::fmt;
4use crate::constants::{SECONDS_IN_HOUR, SECONDS_IN_MINUTE, MINUTES_IN_HOUR, MICROSECONDS_IN_SECOND};
5use std::cmp::{Ordering, Ord};
6use std::time::Duration;
7
8#[derive(Copy, Clone, Eq, PartialEq)]
9pub struct Time {
10 pub hour:u64,
11 pub minute:u64,
12 pub second:u64,
13 pub microsecond:u64,
14}
15
16impl Time {
17 pub fn new(hour: u64, minute: u64, second: u64) -> Self {
18 Self::new_with_microseconds(hour, minute, second, 0)
19 }
20
21 pub fn new_with_microseconds(hour: u64, minute: u64, second: u64, microseconds: u64) -> Self {
22 Time { hour, minute, second, microsecond: microseconds }
23 }
24
25 pub fn valid(&self) -> bool {
26 self.hour < 24 && self.minute < 60 && self.second < 60 && self.microsecond < 1000000
27 }
28
29 pub fn to_hh_mm_string(&self) -> String {
30 format!("{:02}:{:02}", self.hour, self.minute)
31 }
32
33 pub fn from_ms_dos_time(mut ms_dos_time:u16) -> Self {
34 let second = (ms_dos_time & 0x1f) << 1;
35 ms_dos_time >>= 5;
36 let minute = ms_dos_time & 0x3f;
37 ms_dos_time >>= 6;
38 Time::new(ms_dos_time as u64, minute as u64, second as u64)
39 }
40
41 pub fn from_seconds(mut seconds:u64) -> Self {
42 let hour = seconds / SECONDS_IN_HOUR;
43 seconds %= SECONDS_IN_HOUR;
44 let minute = seconds / SECONDS_IN_MINUTE;
45 seconds %= SECONDS_IN_MINUTE;
46 Time::new(hour, minute, seconds)
47 }
48
49 pub fn to_seconds(&self) -> u64 {
50 self.to_minutes() * SECONDS_IN_MINUTE + self.second
51 }
52
53 pub fn to_minutes(&self) -> u64 {
54 self.hour * MINUTES_IN_HOUR + self.minute
55 }
56
57 pub fn to_microseconds(&self) -> u64 {
58 self.to_seconds() * MICROSECONDS_IN_SECOND + self.microsecond
59 }
60
61 pub fn to_milliseconds(&self) -> u64 {
62 self.to_microseconds() / 1000
63 }
64
65 pub fn from_minutes(mut minutes:u64) -> Self {
66 let hour = minutes / MINUTES_IN_HOUR;
67 minutes %= MINUTES_IN_HOUR;
68 Time::new(hour, minutes, 0)
69 }
70
71 pub fn from_hours(hour:u64) -> Self {
72 Time::new(hour, 0, 0)
73 }
74
75 pub fn from_duration(duration:Duration) -> Time {
76 Self::from_seconds(duration.as_secs())
77 }
78
79 pub fn to_duration(&self) -> Duration {
80 Duration::from_secs(self.to_seconds())
81 }
82
83 pub fn normalize(&self) -> Time {
84 let mut second = self.microsecond / MICROSECONDS_IN_SECOND + self.second;
85 let microseconds = self.microsecond % MICROSECONDS_IN_SECOND;
86 let mut minute = second / SECONDS_IN_MINUTE + self.minute;
87 second = second % SECONDS_IN_MINUTE;
88 let hour = minute / MINUTES_IN_HOUR + self.hour;
89 minute = minute % MINUTES_IN_HOUR;
90 Self::new_with_microseconds(hour, minute, second, microseconds)
91 }
92}
93
94impl FromStr for Time {
95 type Err = DateError;
96
97 fn from_str(time_str: &str) -> Result<Self, Self::Err> {
98 let bytes = time_str.as_bytes();
99 let len = bytes.len();
100
101 if len < 8 || bytes[2] != b':' || bytes[5] != b':' {
102 return Err(DateErrorKind::WrongTimeStringFormat.into());
103 }
104 let hour = parse_digits(&bytes[0..2])?;
105
106 let minute = parse_digits(&bytes[3..5])?;
107 let (second, microseconds) = if len > 8 && bytes[8] == b'.' {
108 let second = parse_digits(&bytes[6..8])?;
109 let micro_str = &bytes[9..];
110 let micro_len = micro_str.len().min(6);
111 let mut microseconds = parse_digits(µ_str[..micro_len])?;
112
113 for _ in micro_len..6 {
114 microseconds *= 10;
115 }
116
117 (second, microseconds)
118 } else {
119 let second = parse_digits(&bytes[6..8])?;
120 (second, 0)
121 };
122
123 Ok(Time::new_with_microseconds(hour, minute, second, microseconds))
124 }
125}
126
127#[inline]
128fn parse_digits(bytes: &[u8]) -> Result<u64, DateError> {
129 let mut result = 0u64;
130 for &byte in bytes {
131 if byte < b'0' || byte > b'9' {
132 return Err(DateErrorKind::WrongTimeStringFormat.into());
133 }
134 result = result * 10 + (byte - b'0') as u64;
135 }
136 Ok(result)
137}
138
139impl fmt::Display for Time {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 write!(f, "{:02}:{:02}:{:02}", self.hour, self.minute, self.second)?;
142 if self.microsecond > 0 {
143 let mut divider = 1;
144 while self.microsecond % (divider * 10) == 0 { divider *= 10; }
145 let zeros = divider.ilog10();
146 let zeros = 6 - zeros as usize;
147 write!(f, ".{:0zeros$}", self.microsecond / divider)?;
148 }
149 Ok(())
150 }
151}
152
153impl fmt::Debug for Time {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 fmt::Display::fmt(self, f)
156 }
157}
158
159impl Ord for Time {
160 fn cmp(&self, other: &Self) -> Ordering {
161 if self.hour != other.hour {
162 return self.hour.cmp(&other.hour);
163 }
164 if self.minute != other.minute {
165 return self.minute.cmp(&other.minute);
166 }
167 if self.second != other.second {
168 return self.second.cmp(&other.second);
169 }
170 self.microsecond.cmp(&other.microsecond)
171 }
172}
173
174impl PartialOrd for Time {
175 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
176 Some(self.cmp(other))
177 }
178}
179
180impl std::ops::Sub for Time {
181 type Output = Time;
182
183 fn sub(self, rhs: Self) -> Self::Output {
184 let mut second = self.to_seconds() - rhs.to_seconds();
185 let mut microseconds = self.microsecond;
186 if self.microsecond < rhs.microsecond {
187 second -= 1;
188 microseconds += MICROSECONDS_IN_SECOND;
189 }
190 microseconds -= rhs.microsecond;
191 let mut result = Self::from_seconds(second);
192 result.microsecond = microseconds;
193 result
194 }
195}
196
197impl std::ops::Add for Time {
198 type Output = Time;
199
200 fn add(self, rhs: Self) -> Self::Output {
201 let mut total_microseconds = self.to_microseconds() + rhs.to_microseconds();
202
203 let microseconds = total_microseconds % MICROSECONDS_IN_SECOND;
204 total_microseconds /= MICROSECONDS_IN_SECOND;
205
206 let seconds = total_microseconds % SECONDS_IN_MINUTE;
207 total_microseconds /= SECONDS_IN_MINUTE;
208
209 let minutes = total_microseconds % MINUTES_IN_HOUR;
210 let hours = total_microseconds / MINUTES_IN_HOUR;
211
212 Time::new_with_microseconds(hours, minutes, seconds, microseconds)
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn test_ms_dos_time(){
222 assert_eq!(Time::from_ms_dos_time(0x7d1c), Time::new(15, 40, 56));
223 }
224
225 #[test]
226 fn test_time_cmp() {
227 assert!(Time::new(2, 12,31) < Time::new(3, 1,1));
228 assert!(Time::new(2, 2,1) > Time::new(2, 1,31));
229 assert!(Time::new(2, 3,31) > Time::new(2, 3,30));
230 assert_eq!(Time::new(2, 1,1), Time::new(2, 1,1));
231 assert!(Time::new_with_microseconds(2, 3,31,11) > Time::new_with_microseconds(2, 3,31, 10))
232 }
233
234 #[test]
235 fn test_from_str() -> Result<(), DateError>{
236 assert_eq!(Time::from_str("21:10:05")?, Time::new_with_microseconds(21, 10, 5, 0));
237 assert_eq!(Time::from_str("21:10:05.779325")?, Time::new_with_microseconds(21, 10, 5, 779325));
238 assert_eq!(Time::from_str("21:10:05.77932599")?, Time::new_with_microseconds(21, 10, 5, 779325));
239 assert_eq!(Time::from_str("21:10:05.77932500")?, Time::new_with_microseconds(21, 10, 5, 779325));
240 assert_eq!(Time::from_str("21:10:05.779000")?, Time::new_with_microseconds(21, 10, 5, 779000));
241 assert_eq!(Time::from_str("21:10:05.779")?, Time::new_with_microseconds(21, 10, 5, 779000));
242 assert_eq!(Time::from_str("21:10:05.034104")?, Time::new_with_microseconds(21, 10, 5, 034104));
243 Ok(())
244 }
245
246 #[test]
247 fn test_to_string(){
248 assert_eq!(Time::new_with_microseconds(21, 10, 5, 0).to_string(), "21:10:05");
249 assert_eq!(Time::new_with_microseconds(21, 10, 5, 779325).to_string(), "21:10:05.779325");
250 assert_eq!(Time::new_with_microseconds(21, 10, 5, 779000).to_string(), "21:10:05.779");
251 assert_eq!(Time::new_with_microseconds(21, 10, 5, 779).to_string(), "21:10:05.000779");
252 assert_eq!(Time::new_with_microseconds(21, 10, 5, 34104).to_string(), "21:10:05.034104");
253 }
254
255 #[test]
256 fn test_time_to_minutes() {
257 assert_eq!(Time::new_with_microseconds(2, 3,31,11).to_minutes(), 123);
258 }
259
260 #[test]
261 fn test_time_to_seconds() {
262 assert_eq!(Time::new_with_microseconds(2, 3,31,11).to_seconds(), 7411);
263 }
264
265 #[test]
266 fn test_time_to_microseconds() {
267 assert_eq!(Time::new_with_microseconds(2, 3,31,11).to_microseconds(), 7411000011);
268 assert_eq!(Time::new_with_microseconds(2, 3,31,23560).to_microseconds(), 7411023560);
269 }
270
271 #[test]
272 fn test_time_to_milliseconds() {
273 assert_eq!(Time::new_with_microseconds(2, 3,31,23560).to_milliseconds(), 7411023);
274 }
275
276 #[test]
277 fn test_time_normalize() {
278 assert_eq!(Time::new_with_microseconds(42, 81,74,76543213).normalize(), Time::new_with_microseconds(43, 23,30, 543213));
279 }
280
281 #[test]
282 fn test_time_add() {
283 assert_eq!(Time::new_with_microseconds(100, 59,59,999999)
284 + Time::new_with_microseconds(0, 0,1, 1),
285 Time::new(101,0,1)
286 );
287 }
288
289 #[test]
290 fn test_time_sub() {
291 assert_eq!(Time::new_with_microseconds(100, 0,0,0)
292 - Time::new_with_microseconds(0, 0,0, 1),
293 Time::new_with_microseconds(99,59,59, 999999)
294 );
295 }
296
297 #[test]
298 fn test_time_validation() {
299 assert!(Time::new(0, 0, 0).valid());
300 assert!(Time::new(23, 59, 59).valid());
301 assert!(Time::new(12, 30, 45).valid());
302 assert!(!Time::new(24, 0, 0).valid()); assert!(!Time::new(25, 0, 0).valid()); assert!(!Time::new(12, 60, 0).valid()); assert!(!Time::new(12, 0, 60).valid()); assert!(!Time::new(12, 61, 0).valid()); assert!(!Time::new(12, 0, 61).valid()); }
309
310 #[test]
311 fn test_time_from_str_invalid() {
312 assert!("invalid".parse::<Time>().is_err());
313 assert!("12:00".parse::<Time>().is_err());
314 assert!("12".parse::<Time>().is_err());
315 assert!("12-00-00".parse::<Time>().is_err());
316 }
317
318 #[test]
319 fn test_time_conversions() {
320 let time = Time::new(2, 30, 45);
321
322 assert_eq!(time.to_minutes(), 150); assert_eq!(time.to_seconds(), 9045); assert_eq!(time.to_milliseconds(), 9045000);
325
326 assert_eq!(Time::from_minutes(150), Time::new(2, 30, 0));
327 assert_eq!(Time::from_hours(2), Time::new(2, 0, 0));
328 assert_eq!(Time::from_seconds(9045), Time::new(2, 30, 45));
329 }
330
331 #[test]
332 fn test_time_with_microseconds() {
333 let time = Time::new_with_microseconds(12, 30, 45, 123456);
334
335 assert_eq!(time.to_microseconds(), 45045123456);
336 assert_eq!(time.to_milliseconds(), 45045123);
337
338 assert_eq!(time.to_string(), "12:30:45.123456");
339 assert_eq!("12:30:45.123456".parse::<Time>().unwrap(), time);
340 }
341
342 #[test]
343 fn test_time_edge_cases() {
344 let midnight = Time::new(0, 0, 0);
345 assert_eq!(midnight.to_string(), "00:00:00");
346 assert_eq!(midnight.to_seconds(), 0);
347
348 let end_of_day = Time::new(23, 59, 59);
349 assert_eq!(end_of_day.to_string(), "23:59:59");
350 assert_eq!(end_of_day.to_seconds(), 86399);
351
352 let time_with_micros = Time::new_with_microseconds(0, 0, 0, 999999);
353 assert_eq!(time_with_micros.to_string(), "00:00:00.999999");
354 }
355
356 #[test]
357 fn test_time_duration_conversion() {
358 let time = Time::new(1, 30, 45);
359 let duration = time.to_duration();
360 assert_eq!(duration.as_secs(), 5445);
361
362 let from_duration = Time::from_duration(duration);
363 assert_eq!(from_duration, time);
364 }
365
366 #[test]
367 fn test_time_hh_mm_string() {
368 let time = Time::new(9, 5, 30);
369 assert_eq!(time.to_hh_mm_string(), "09:05");
370
371 let time2 = Time::new(23, 59, 0);
372 assert_eq!(time2.to_hh_mm_string(), "23:59");
373 }
374
375 #[test]
376 fn test_time_arithmetic_edge_cases() {
377 let time1 = Time::new(23, 59, 59);
378 let time2 = Time::new(0, 0, 1);
379 let result = time1 + time2;
380 assert_eq!(result, Time::new(24, 0, 0));
381 }
382}