iced_aw/core/
time.rs

1//! Use a time picker as an input element for picking times.
2//!
3//! *This API requires the following crate features to be activated: `time_picker`*
4
5use chrono::{Local, Timelike};
6use std::fmt::Display;
7
8/// The time value
9#[derive(Clone, Copy, Debug)]
10pub enum Time {
11    /// The time value containing hour, minute and period.
12    Hm {
13        /// The hour value.
14        hour: u32,
15        /// The minute value.
16        minute: u32,
17        /// The current period of the time.
18        period: Period,
19    },
20
21    /// The time value containing hour, minute, second and period.
22    Hms {
23        /// The hour value.
24        hour: u32,
25        /// The minute value.
26        minute: u32,
27        /// The second value.
28        second: u32,
29        /// The current period of the time.
30        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    /// Creates a new time (hours, minutes) from the current timestamp.
46    #[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    /// Creates a new time (hours, minutes, seconds) from the current timestamp.
66    #[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    /// The default time `00:00` with the given period.
87    #[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    /// The default time `00:00:00` with the given period.
97    #[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/// The current period of the clock
131#[derive(Clone, Copy, Debug, PartialEq, Eq)]
132pub enum Period {
133    /// No period - using 24 hour format.
134    H24,
135    /// Ante meridiem: Before noon.
136    Am,
137    /// Post meridiem: After noon.
138    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}