1use chrono::{Local, Timelike};
6use std::fmt::Display;
7
8#[derive(Clone, Copy, Debug)]
10pub enum Time {
11 Hm {
13 hour: u32,
15 minute: u32,
17 period: Period,
19 },
20
21 Hms {
23 hour: u32,
25 minute: u32,
27 second: u32,
29 period: Period,
31 },
32}
33
34impl Default for Time {
35 fn default() -> Self {
36 Self::Hm {
37 hour: 1,
38 minute: 0,
39 period: Period::Am,
40 }
41 }
42}
43
44impl Time {
45 #[must_use]
47 pub fn now_hm(use_24h: bool) -> Self {
48 let now = Local::now().naive_local().time();
49
50 let (hour, period) = if use_24h {
51 (now.hour(), Period::H24)
52 } else {
53 let (period, hour12) = now.hour12();
54
55 (hour12, if period { Period::Pm } else { Period::Am })
56 };
57
58 Self::Hm {
59 hour,
60 minute: now.minute(),
61 period,
62 }
63 }
64
65 #[must_use]
67 pub fn now_hms(use_24h: bool) -> Self {
68 let now = Local::now().naive_local().time();
69
70 let (hour, period) = if use_24h {
71 (now.hour(), Period::H24)
72 } else {
73 let (period, hour12) = now.hour12();
74
75 (hour12, if period { Period::Pm } else { Period::Am })
76 };
77
78 Self::Hms {
79 hour,
80 minute: now.minute(),
81 second: now.second(),
82 period,
83 }
84 }
85
86 #[must_use]
88 pub const fn default_hm(period: Period) -> Self {
89 Self::Hm {
90 hour: 0,
91 minute: 0,
92 period,
93 }
94 }
95
96 #[must_use]
98 pub const fn default_hms(period: Period) -> Self {
99 Self::Hms {
100 hour: 0,
101 minute: 0,
102 second: 0,
103 period,
104 }
105 }
106}
107
108impl Display for Time {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 match self {
111 Self::Hm {
112 hour,
113 minute,
114 period,
115 } => {
116 write!(f, "{hour:02}:{minute:02}{period}")
117 }
118 Self::Hms {
119 hour,
120 minute,
121 second,
122 period,
123 } => {
124 write!(f, "{hour:02}:{minute:02}:{second:02}{period}")
125 }
126 }
127 }
128}
129
130#[derive(Clone, Copy, Debug, PartialEq, Eq)]
132pub enum Period {
133 H24,
135 Am,
137 Pm,
139}
140
141impl Display for Period {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 write!(
144 f,
145 "{}",
146 match self {
147 Self::H24 => "",
148 Self::Am => " AM",
149 Self::Pm => " PM",
150 }
151 )
152 }
153}
154
155impl From<Time> for chrono::NaiveTime {
156 fn from(time: Time) -> Self {
157 let (h, m, s, p) = match time {
158 Time::Hm {
159 hour,
160 minute,
161 period,
162 } => (hour, minute, 0, period),
163 Time::Hms {
164 hour,
165 minute,
166 second,
167 period,
168 } => (hour, minute, second, period),
169 };
170
171 let h = if h == 12 && p != Period::H24 { 0 } else { h };
172
173 let h = match p {
174 Period::H24 | Period::Am => h,
175 Period::Pm => (h + 12) % 24,
176 };
177
178 Self::from_hms_opt(h, m, s).expect("Time Conversion failed. H, M, or S was too large.")
179 }
180}
181
182impl From<chrono::NaiveTime> for Time {
183 fn from(time: chrono::NaiveTime) -> Self {
184 Self::Hms {
185 hour: time.hour(),
186 minute: time.minute(),
187 second: time.second(),
188 period: Period::H24,
189 }
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use chrono::NaiveTime;
196
197 use super::{Period, Time};
198
199 #[test]
200 fn time_to_naive() {
201 let time = Time::Hms {
202 hour: 8,
203 minute: 52,
204 second: 17,
205 period: Period::H24,
206 };
207
208 let naive: NaiveTime = time.into();
209 assert_eq!(
210 naive,
211 NaiveTime::from_hms_opt(8, 52, 17).expect("Time Conversion failed")
212 );
213
214 let time = Time::Hms {
215 hour: 23,
216 minute: 48,
217 second: 39,
218 period: Period::H24,
219 };
220
221 let naive: NaiveTime = time.into();
222 assert_eq!(
223 naive,
224 NaiveTime::from_hms_opt(23, 48, 39).expect("Time Conversion failed")
225 );
226
227 let time = Time::Hms {
228 hour: 8,
229 minute: 52,
230 second: 17,
231 period: Period::Am,
232 };
233
234 let naive: NaiveTime = time.into();
235 assert_eq!(
236 naive,
237 NaiveTime::from_hms_opt(8, 52, 17).expect("Time Conversion failed")
238 );
239
240 let time = Time::Hms {
241 hour: 8,
242 minute: 52,
243 second: 17,
244 period: Period::Pm,
245 };
246
247 let naive: NaiveTime = time.into();
248 assert_eq!(
249 naive,
250 NaiveTime::from_hms_opt(20, 52, 17).expect("Time Conversion failed")
251 );
252
253 let time = Time::Hms {
254 hour: 12,
255 minute: 52,
256 second: 17,
257 period: Period::Am,
258 };
259
260 let naive: NaiveTime = time.into();
261 assert_eq!(
262 naive,
263 NaiveTime::from_hms_opt(0, 52, 17).expect("Time Conversion failed")
264 );
265
266 let time = Time::Hms {
267 hour: 12,
268 minute: 52,
269 second: 17,
270 period: Period::Pm,
271 };
272
273 let naive: NaiveTime = time.into();
274 assert_eq!(
275 naive,
276 NaiveTime::from_hms_opt(12, 52, 17).expect("Time Conversion failed")
277 );
278
279 let time = Time::Hm {
280 hour: 17,
281 minute: 52,
282 period: Period::H24,
283 };
284
285 let naive: NaiveTime = time.into();
286 assert_eq!(
287 naive,
288 NaiveTime::from_hms_opt(17, 52, 0).expect("Time Conversion failed")
289 );
290 }
291}