1use std::{
2 fmt::{self, Display, Formatter},
3 ops::{Add, Sub},
4};
5
6use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
7
8#[derive(Debug, Eq, PartialEq, Clone, Copy)]
11pub struct Time(i64);
12
13impl Time {
14 pub fn new(h: i64, m: i64, s: i64) -> Self {
20 Time(h * 60 * 60 + m * 60 + s)
21 }
22
23 pub fn h(&self) -> i64 {
24 self.0 / 60 / 60
25 }
26
27 pub fn m(&self) -> i64 {
28 self.0 / 60 % 60
29 }
30
31 pub fn s(&self) -> i64 {
32 self.0 % 60
33 }
34}
35
36impl Display for Time {
37 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
38 let neg = if self.0 < 0 { "-" } else { "" };
39 write!(
40 f,
41 "{}{:02}:{:02}:{:02}",
42 neg,
43 self.h().abs(),
44 self.m().abs(),
45 self.s().abs()
46 )
47 }
48}
49
50impl Serialize for Time {
51 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
52 where
53 S: Serializer,
54 {
55 serializer.serialize_str(&self.to_string())
56 }
57}
58
59impl<'de> Deserialize<'de> for Time {
60 fn deserialize<D>(deserializer: D) -> Result<Time, D::Error>
61 where
62 D: Deserializer<'de>,
63 {
64 fn parse_num<'de, D>(it: &str) -> Result<i64, D::Error>
65 where
66 D: Deserializer<'de>,
67 {
68 it.parse()
69 .map_err(|_| de::Error::invalid_type(de::Unexpected::Str(it), &"an integer"))
70 }
71 let s = String::deserialize(deserializer)?;
72 let is_neg = s.starts_with('-');
73 let s = if !is_neg {
74 s
75 } else {
76 s.chars()
77 .enumerate()
78 .filter(|(i, _)| *i != 0)
79 .map(|(_, v)| v)
80 .collect::<String>()
81 };
82 let v: Vec<&str> = s.split(':').collect();
83 let len = v.len();
84 if len != 3 {
85 return Err(de::Error::invalid_length(len, &"time's must be HH:mm:ss"));
86 }
87 let h = parse_num::<D>(v[0])?;
88 let m = parse_num::<D>(v[1])?;
89 let s = parse_num::<D>(v[2])?;
90 let t = h * 60 * 60 + m * 60 + s;
91 let o = if is_neg { Time(-t) } else { Time(t) };
92 Ok(o)
93 }
94}
95
96impl Add for Time {
97 fn add(self, rhs: Self) -> Self::Output {
98 Time(self.0 + rhs.0)
99 }
100
101 type Output = Time;
102}
103
104impl Sub for Time {
105 type Output = Time;
106
107 fn sub(self, rhs: Self) -> Self::Output {
108 Time(self.0 - rhs.0)
109 }
110}
111
112#[cfg(test)]
113mod test {
114 use super::*;
115
116 #[test]
117 fn test_time() {
118 let t = Time::new(1, 2, 3);
119 assert_eq!(t.h(), 1);
120 assert_eq!(t.m(), 2);
121 assert_eq!(t.s(), 3);
122 assert_eq!(t.to_string(), "01:02:03");
123 }
124
125 #[test]
126 fn test_neg_time() {
127 let t = Time::new(0, -1, -2);
128 assert_eq!(t.h(), 0);
129 assert_eq!(t.m(), -1);
130 assert_eq!(t.s(), -2);
131 assert_eq!(t.to_string(), "-00:01:02")
132 }
133
134 #[test]
135 fn test_time_serde() {
136 let t = Time::new(0, 2, 3);
137 let s = serde_json::to_string(&t).unwrap();
138 assert_eq!(s, "\"00:02:03\"");
139 let t2: Time = serde_json::from_str(&s).unwrap();
140 assert_eq!(t, t2);
141 }
142
143 #[test]
144 fn test_time_serde_neg() {
145 let t = Time::new(-1, -2, -3);
146 let s = serde_json::to_string(&t).unwrap();
147 assert_eq!(s, "\"-01:02:03\"");
148 let t2: Time = serde_json::from_str(&s).unwrap();
149 assert_eq!(t, t2);
150 }
151
152 #[test]
153 fn test_time_add() {
154 let t1 = Time::new(1, 2, 3);
155 let t2 = Time::new(4, 5, 6);
156 let t3 = t1 + t2;
157 assert_eq!(t3.h(), 5);
158 assert_eq!(t3.m(), 7);
159 assert_eq!(t3.s(), 9);
160 }
161
162 #[test]
163 fn test_time_sub() {
164 let t1 = Time::new(1, 2, 3);
165 let t2 = Time::new(4, 5, 6);
166 let t3 = t1 - t2;
167 assert_eq!(t3.h(), -3);
168 assert_eq!(t3.m(), -3);
169 assert_eq!(t3.s(), -3);
170 }
171}