1use std::fmt::{self, Display, Formatter};
5
6use serde::{
7 Deserialize, Deserializer, Serialize, Serializer,
8 de::{self, Visitor},
9};
10
11use crate::{
12 error::{TemporalKind, TypeError},
13 fragment::Fragment,
14};
15
16#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
21pub struct Time {
22 nanos_since_midnight: u64,
24}
25
26impl Time {
27 const MAX_NANOS_IN_DAY: u64 = 86_399_999_999_999;
29 const NANOS_PER_SECOND: u64 = 1_000_000_000;
30 const NANOS_PER_MINSVTE: u64 = 60 * Self::NANOS_PER_SECOND;
31 const NANOS_PER_HOUR: u64 = 60 * Self::NANOS_PER_MINSVTE;
32
33 fn overflow_err(message: impl Into<String>) -> TypeError {
34 TypeError::Temporal {
35 kind: TemporalKind::TimeOverflow {
36 message: message.into(),
37 },
38 message: "time overflow".to_string(),
39 fragment: Fragment::None,
40 }
41 }
42
43 pub fn new(hour: u32, min: u32, sec: u32, nano: u32) -> Option<Self> {
44 if hour >= 24 || min >= 60 || sec >= 60 || nano >= Self::NANOS_PER_SECOND as u32 {
46 return None;
47 }
48
49 let nanos = hour as u64 * Self::NANOS_PER_HOUR
50 + min as u64 * Self::NANOS_PER_MINSVTE
51 + sec as u64 * Self::NANOS_PER_SECOND
52 + nano as u64;
53
54 Some(Self {
55 nanos_since_midnight: nanos,
56 })
57 }
58
59 pub fn from_hms(hour: u32, min: u32, sec: u32) -> Result<Self, Box<TypeError>> {
60 Self::new(hour, min, sec, 0).ok_or_else(|| {
61 Box::new(Self::overflow_err(format!("invalid time: {:02}:{:02}:{:02}", hour, min, sec)))
62 })
63 }
64
65 pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> Result<Self, Box<TypeError>> {
66 Self::new(hour, min, sec, nano).ok_or_else(|| {
67 Box::new(Self::overflow_err(format!(
68 "invalid time: {:02}:{:02}:{:02}.{:09}",
69 hour, min, sec, nano
70 )))
71 })
72 }
73
74 pub fn midnight() -> Self {
75 Self {
76 nanos_since_midnight: 0,
77 }
78 }
79
80 pub fn noon() -> Self {
81 Self {
82 nanos_since_midnight: 12 * Self::NANOS_PER_HOUR,
83 }
84 }
85
86 pub fn hour(&self) -> u32 {
87 (self.nanos_since_midnight / Self::NANOS_PER_HOUR) as u32
88 }
89
90 pub fn minute(&self) -> u32 {
91 ((self.nanos_since_midnight % Self::NANOS_PER_HOUR) / Self::NANOS_PER_MINSVTE) as u32
92 }
93
94 pub fn second(&self) -> u32 {
95 ((self.nanos_since_midnight % Self::NANOS_PER_MINSVTE) / Self::NANOS_PER_SECOND) as u32
96 }
97
98 pub fn nanosecond(&self) -> u32 {
99 (self.nanos_since_midnight % Self::NANOS_PER_SECOND) as u32
100 }
101
102 pub fn to_nanos_since_midnight(&self) -> u64 {
104 self.nanos_since_midnight
105 }
106
107 pub fn from_nanos_since_midnight(nanos: u64) -> Option<Self> {
109 if nanos > Self::MAX_NANOS_IN_DAY {
110 return None;
111 }
112 Some(Self {
113 nanos_since_midnight: nanos,
114 })
115 }
116}
117
118impl Display for Time {
119 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
120 let hours = self.hour();
121 let minutes = self.minute();
122 let seconds = self.second();
123 let nanos = self.nanosecond();
124
125 write!(f, "{:02}:{:02}:{:02}.{:09}", hours, minutes, seconds, nanos)
126 }
127}
128
129impl Serialize for Time {
131 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
132 where
133 S: Serializer,
134 {
135 serializer.serialize_str(&self.to_string())
136 }
137}
138
139struct TimeVisitor;
140
141impl<'de> Visitor<'de> for TimeVisitor {
142 type Value = Time;
143
144 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
145 formatter.write_str("a time in ISO 8601 format (HH:MM:SS or HH:MM:SS.nnnnnnnnn)")
146 }
147
148 fn visit_str<E>(self, value: &str) -> Result<Time, E>
149 where
150 E: de::Error,
151 {
152 let (time_part, nano_part) = if let Some(dot_pos) = value.find('.') {
154 (&value[..dot_pos], Some(&value[dot_pos + 1..]))
155 } else {
156 (value, None)
157 };
158
159 let time_parts: Vec<&str> = time_part.split(':').collect();
160 if time_parts.len() != 3 {
161 return Err(E::custom(format!("invalid time format: {}", value)));
162 }
163
164 let hour = time_parts[0]
165 .parse::<u32>()
166 .map_err(|_| E::custom(format!("invalid hour: {}", time_parts[0])))?;
167 let minute = time_parts[1]
168 .parse::<u32>()
169 .map_err(|_| E::custom(format!("invalid minute: {}", time_parts[1])))?;
170 let second = time_parts[2]
171 .parse::<u32>()
172 .map_err(|_| E::custom(format!("invalid second: {}", time_parts[2])))?;
173
174 let nano = if let Some(nano_str) = nano_part {
175 let padded = if nano_str.len() < 9 {
177 format!("{:0<9}", nano_str)
178 } else {
179 nano_str[..9].to_string()
180 };
181 padded.parse::<u32>().map_err(|_| E::custom(format!("invalid nanoseconds: {}", nano_str)))?
182 } else {
183 0
184 };
185
186 Time::new(hour, minute, second, nano).ok_or_else(|| {
187 E::custom(format!("invalid time: {:02}:{:02}:{:02}.{:09}", hour, minute, second, nano))
188 })
189 }
190}
191
192impl<'de> Deserialize<'de> for Time {
193 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
194 where
195 D: Deserializer<'de>,
196 {
197 deserializer.deserialize_str(TimeVisitor)
198 }
199}
200
201#[cfg(test)]
202pub mod tests {
203 use std::fmt::Debug;
204
205 use serde_json::{from_str, to_string};
206
207 use super::*;
208 use crate::error::{TemporalKind, TypeError};
209
210 #[test]
211 fn test_time_display_standard_format() {
212 let time = Time::new(14, 30, 45, 123456789).unwrap();
213 assert_eq!(format!("{}", time), "14:30:45.123456789");
214
215 let time = Time::new(0, 0, 0, 0).unwrap();
216 assert_eq!(format!("{}", time), "00:00:00.000000000");
217
218 let time = Time::new(23, 59, 59, 999999999).unwrap();
219 assert_eq!(format!("{}", time), "23:59:59.999999999");
220 }
221
222 #[test]
223 fn test_time_display_millisecond_precision() {
224 let time = Time::new(14, 30, 45, 123000000).unwrap();
226 assert_eq!(format!("{}", time), "14:30:45.123000000");
227
228 let time = Time::new(14, 30, 45, 001000000).unwrap();
229 assert_eq!(format!("{}", time), "14:30:45.001000000");
230
231 let time = Time::new(14, 30, 45, 999000000).unwrap();
232 assert_eq!(format!("{}", time), "14:30:45.999000000");
233 }
234
235 #[test]
236 fn test_time_display_microsecond_precision() {
237 let time = Time::new(14, 30, 45, 123456000).unwrap();
239 assert_eq!(format!("{}", time), "14:30:45.123456000");
240
241 let time = Time::new(14, 30, 45, 000001000).unwrap();
242 assert_eq!(format!("{}", time), "14:30:45.000001000");
243
244 let time = Time::new(14, 30, 45, 999999000).unwrap();
245 assert_eq!(format!("{}", time), "14:30:45.999999000");
246 }
247
248 #[test]
249 fn test_time_display_nanosecond_precision() {
250 let time = Time::new(14, 30, 45, 123456789).unwrap();
252 assert_eq!(format!("{}", time), "14:30:45.123456789");
253
254 let time = Time::new(14, 30, 45, 000000001).unwrap();
255 assert_eq!(format!("{}", time), "14:30:45.000000001");
256
257 let time = Time::new(14, 30, 45, 999999999).unwrap();
258 assert_eq!(format!("{}", time), "14:30:45.999999999");
259 }
260
261 #[test]
262 fn test_time_display_zero_fractional_seconds() {
263 let time = Time::new(14, 30, 45, 0).unwrap();
264 assert_eq!(format!("{}", time), "14:30:45.000000000");
265
266 let time = Time::new(0, 0, 0, 0).unwrap();
267 assert_eq!(format!("{}", time), "00:00:00.000000000");
268 }
269
270 #[test]
271 fn test_time_display_edge_times() {
272 let time = Time::new(0, 0, 0, 0).unwrap();
274 assert_eq!(format!("{}", time), "00:00:00.000000000");
275
276 let time = Time::new(23, 59, 59, 999999999).unwrap();
278 assert_eq!(format!("{}", time), "23:59:59.999999999");
279
280 let time = Time::new(12, 0, 0, 0).unwrap();
282 assert_eq!(format!("{}", time), "12:00:00.000000000");
283
284 let time = Time::new(23, 59, 58, 999999999).unwrap();
286 assert_eq!(format!("{}", time), "23:59:58.999999999");
287
288 let time = Time::new(0, 0, 1, 0).unwrap();
290 assert_eq!(format!("{}", time), "00:00:01.000000000");
291 }
292
293 #[test]
294 fn test_time_display_special_times() {
295 let midnight = Time::midnight();
297 assert_eq!(format!("{}", midnight), "00:00:00.000000000");
298
299 let noon = Time::noon();
300 assert_eq!(format!("{}", noon), "12:00:00.000000000");
301
302 let default = Time::default();
304 assert_eq!(format!("{}", default), "00:00:00.000000000");
305 }
306
307 #[test]
308 fn test_time_display_all_hours() {
309 for hour in 0..24 {
310 let time = Time::new(hour, 30, 45, 123456789).unwrap();
311 let expected = format!("{:02}:30:45.123456789", hour);
312 assert_eq!(format!("{}", time), expected);
313 }
314 }
315
316 #[test]
317 fn test_time_display_all_minutes() {
318 for minute in 0..60 {
319 let time = Time::new(14, minute, 45, 123456789).unwrap();
320 let expected = format!("14:{:02}:45.123456789", minute);
321 assert_eq!(format!("{}", time), expected);
322 }
323 }
324
325 #[test]
326 fn test_time_display_all_seconds() {
327 for second in 0..60 {
328 let time = Time::new(14, 30, second, 123456789).unwrap();
329 let expected = format!("14:30:{:02}.123456789", second);
330 assert_eq!(format!("{}", time), expected);
331 }
332 }
333
334 #[test]
335 fn test_time_display_from_hms() {
336 let time = Time::from_hms(14, 30, 45).unwrap();
337 assert_eq!(format!("{}", time), "14:30:45.000000000");
338
339 let time = Time::from_hms(0, 0, 0).unwrap();
340 assert_eq!(format!("{}", time), "00:00:00.000000000");
341
342 let time = Time::from_hms(23, 59, 59).unwrap();
343 assert_eq!(format!("{}", time), "23:59:59.000000000");
344 }
345
346 #[test]
347 fn test_time_display_from_hms_nano() {
348 let time = Time::from_hms_nano(14, 30, 45, 123456789).unwrap();
349 assert_eq!(format!("{}", time), "14:30:45.123456789");
350
351 let time = Time::from_hms_nano(0, 0, 0, 0).unwrap();
352 assert_eq!(format!("{}", time), "00:00:00.000000000");
353
354 let time = Time::from_hms_nano(23, 59, 59, 999999999).unwrap();
355 assert_eq!(format!("{}", time), "23:59:59.999999999");
356 }
357
358 #[test]
359 fn test_time_display_from_nanos_since_midnight() {
360 let time = Time::from_nanos_since_midnight(0).unwrap();
362 assert_eq!(format!("{}", time), "00:00:00.000000000");
363
364 let time = Time::from_nanos_since_midnight(1_000_000_000).unwrap();
366 assert_eq!(format!("{}", time), "00:00:01.000000000");
367
368 let time = Time::from_nanos_since_midnight(60_000_000_000).unwrap();
370 assert_eq!(format!("{}", time), "00:01:00.000000000");
371
372 let time = Time::from_nanos_since_midnight(3_600_000_000_000).unwrap();
374 assert_eq!(format!("{}", time), "01:00:00.000000000");
375
376 let nanos = 14 * 3600 * 1_000_000_000 + 30 * 60 * 1_000_000_000 + 45 * 1_000_000_000 + 123456789;
378 let time = Time::from_nanos_since_midnight(nanos).unwrap();
379 assert_eq!(format!("{}", time), "14:30:45.123456789");
380 }
381
382 #[test]
383 fn test_time_display_boundary_values() {
384 let nanos = 24 * 3600 * 1_000_000_000 - 1;
386 let time = Time::from_nanos_since_midnight(nanos).unwrap();
387 assert_eq!(format!("{}", time), "23:59:59.999999999");
388
389 let time = Time::from_nanos_since_midnight(1).unwrap();
391 assert_eq!(format!("{}", time), "00:00:00.000000001");
392 }
393
394 #[test]
395 fn test_time_display_precision_patterns() {
396 let time = Time::new(14, 30, 45, 100000000).unwrap(); assert_eq!(format!("{}", time), "14:30:45.100000000");
399
400 let time = Time::new(14, 30, 45, 010000000).unwrap(); assert_eq!(format!("{}", time), "14:30:45.010000000");
402
403 let time = Time::new(14, 30, 45, 001000000).unwrap(); assert_eq!(format!("{}", time), "14:30:45.001000000");
405
406 let time = Time::new(14, 30, 45, 000100000).unwrap(); assert_eq!(format!("{}", time), "14:30:45.000100000");
408
409 let time = Time::new(14, 30, 45, 000010000).unwrap(); assert_eq!(format!("{}", time), "14:30:45.000010000");
411
412 let time = Time::new(14, 30, 45, 000001000).unwrap(); assert_eq!(format!("{}", time), "14:30:45.000001000");
414
415 let time = Time::new(14, 30, 45, 000000100).unwrap(); assert_eq!(format!("{}", time), "14:30:45.000000100");
417
418 let time = Time::new(14, 30, 45, 000000010).unwrap(); assert_eq!(format!("{}", time), "14:30:45.000000010");
420
421 let time = Time::new(14, 30, 45, 000000001).unwrap(); assert_eq!(format!("{}", time), "14:30:45.000000001");
423 }
424
425 #[test]
426 fn test_invalid_times() {
427 assert!(Time::new(24, 0, 0, 0).is_none()); assert!(Time::new(0, 60, 0, 0).is_none()); assert!(Time::new(0, 0, 60, 0).is_none()); assert!(Time::new(0, 0, 0, 1_000_000_000).is_none()); }
432
433 #[test]
434 fn test_time_roundtrip() {
435 let test_times = [(0, 0, 0, 0), (12, 30, 45, 123456789), (23, 59, 59, 999999999)];
436
437 for (h, m, s, n) in test_times {
438 let time = Time::new(h, m, s, n).unwrap();
439 let nanos = time.to_nanos_since_midnight();
440 let recovered = Time::from_nanos_since_midnight(nanos).unwrap();
441
442 assert_eq!(time.hour(), recovered.hour());
443 assert_eq!(time.minute(), recovered.minute());
444 assert_eq!(time.second(), recovered.second());
445 assert_eq!(time.nanosecond(), recovered.nanosecond());
446 }
447 }
448
449 #[test]
450 fn test_serde_roundtrip() {
451 let time = Time::new(14, 30, 45, 123456789).unwrap();
452 let json = to_string(&time).unwrap();
453 assert_eq!(json, "\"14:30:45.123456789\"");
454
455 let recovered: Time = from_str(&json).unwrap();
456 assert_eq!(time, recovered);
457 }
458
459 fn assert_time_overflow<T: Debug>(result: Result<T, Box<TypeError>>) {
460 let err = result.expect_err("expected TimeOverflow error");
461 match *err {
462 TypeError::Temporal {
463 kind: TemporalKind::TimeOverflow {
464 ..
465 },
466 ..
467 } => {}
468 other => panic!("expected TimeOverflow, got: {:?}", other),
469 }
470 }
471
472 #[test]
473 fn test_from_hms_invalid_hour() {
474 assert_time_overflow(Time::from_hms(24, 0, 0));
475 }
476
477 #[test]
478 fn test_from_hms_invalid_minute() {
479 assert_time_overflow(Time::from_hms(0, 60, 0));
480 }
481
482 #[test]
483 fn test_from_hms_invalid_second() {
484 assert_time_overflow(Time::from_hms(0, 0, 60));
485 }
486
487 #[test]
488 fn test_from_hms_nano_invalid_nano() {
489 assert_time_overflow(Time::from_hms_nano(0, 0, 0, 1_000_000_000));
490 }
491}