1 use super::NaiveTime;
2 use crate::{FixedOffset, TimeDelta, Timelike};
3
4 #[test]
test_time_from_hms_milli()5 fn test_time_from_hms_milli() {
6 assert_eq!(
7 NaiveTime::from_hms_milli_opt(3, 5, 7, 0),
8 Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 0).unwrap())
9 );
10 assert_eq!(
11 NaiveTime::from_hms_milli_opt(3, 5, 7, 777),
12 Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 777_000_000).unwrap())
13 );
14 assert_eq!(
15 NaiveTime::from_hms_milli_opt(3, 5, 59, 1_999),
16 Some(NaiveTime::from_hms_nano_opt(3, 5, 59, 1_999_000_000).unwrap())
17 );
18 assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 59, 2_000), None);
19 assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 59, 5_000), None); // overflow check
20 assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 59, u32::MAX), None);
21 }
22
23 #[test]
test_time_from_hms_micro()24 fn test_time_from_hms_micro() {
25 assert_eq!(
26 NaiveTime::from_hms_micro_opt(3, 5, 7, 0),
27 Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 0).unwrap())
28 );
29 assert_eq!(
30 NaiveTime::from_hms_micro_opt(3, 5, 7, 333),
31 Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 333_000).unwrap())
32 );
33 assert_eq!(
34 NaiveTime::from_hms_micro_opt(3, 5, 7, 777_777),
35 Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 777_777_000).unwrap())
36 );
37 assert_eq!(
38 NaiveTime::from_hms_micro_opt(3, 5, 59, 1_999_999),
39 Some(NaiveTime::from_hms_nano_opt(3, 5, 59, 1_999_999_000).unwrap())
40 );
41 assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 59, 2_000_000), None);
42 assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 59, 5_000_000), None); // overflow check
43 assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 59, u32::MAX), None);
44 }
45
46 #[test]
test_time_hms()47 fn test_time_hms() {
48 assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().hour(), 3);
49 assert_eq!(
50 NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(0),
51 Some(NaiveTime::from_hms_opt(0, 5, 7).unwrap())
52 );
53 assert_eq!(
54 NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(23),
55 Some(NaiveTime::from_hms_opt(23, 5, 7).unwrap())
56 );
57 assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(24), None);
58 assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_hour(u32::MAX), None);
59
60 assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().minute(), 5);
61 assert_eq!(
62 NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(0),
63 Some(NaiveTime::from_hms_opt(3, 0, 7).unwrap())
64 );
65 assert_eq!(
66 NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(59),
67 Some(NaiveTime::from_hms_opt(3, 59, 7).unwrap())
68 );
69 assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(60), None);
70 assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_minute(u32::MAX), None);
71
72 assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().second(), 7);
73 assert_eq!(
74 NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(0),
75 Some(NaiveTime::from_hms_opt(3, 5, 0).unwrap())
76 );
77 assert_eq!(
78 NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(59),
79 Some(NaiveTime::from_hms_opt(3, 5, 59).unwrap())
80 );
81 assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(60), None);
82 assert_eq!(NaiveTime::from_hms_opt(3, 5, 7).unwrap().with_second(u32::MAX), None);
83 }
84
85 #[test]
test_time_add()86 fn test_time_add() {
87 macro_rules! check {
88 ($lhs:expr, $rhs:expr, $sum:expr) => {{
89 assert_eq!($lhs + $rhs, $sum);
90 //assert_eq!($rhs + $lhs, $sum);
91 }};
92 }
93
94 let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap();
95
96 check!(hmsm(3, 5, 59, 900), TimeDelta::zero(), hmsm(3, 5, 59, 900));
97 check!(hmsm(3, 5, 59, 900), TimeDelta::milliseconds(100), hmsm(3, 6, 0, 0));
98 check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(-1800), hmsm(3, 5, 58, 500));
99 check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(-800), hmsm(3, 5, 59, 500));
100 check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(-100), hmsm(3, 5, 59, 1_200));
101 check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(100), hmsm(3, 5, 59, 1_400));
102 check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(800), hmsm(3, 6, 0, 100));
103 check!(hmsm(3, 5, 59, 1_300), TimeDelta::milliseconds(1800), hmsm(3, 6, 1, 100));
104 check!(hmsm(3, 5, 59, 900), TimeDelta::seconds(86399), hmsm(3, 5, 58, 900)); // overwrap
105 check!(hmsm(3, 5, 59, 900), TimeDelta::seconds(-86399), hmsm(3, 6, 0, 900));
106 check!(hmsm(3, 5, 59, 900), TimeDelta::days(12345), hmsm(3, 5, 59, 900));
107 check!(hmsm(3, 5, 59, 1_300), TimeDelta::days(1), hmsm(3, 5, 59, 300));
108 check!(hmsm(3, 5, 59, 1_300), TimeDelta::days(-1), hmsm(3, 6, 0, 300));
109
110 // regression tests for #37
111 check!(hmsm(0, 0, 0, 0), TimeDelta::milliseconds(-990), hmsm(23, 59, 59, 10));
112 check!(hmsm(0, 0, 0, 0), TimeDelta::milliseconds(-9990), hmsm(23, 59, 50, 10));
113 }
114
115 #[test]
test_time_overflowing_add()116 fn test_time_overflowing_add() {
117 let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap();
118
119 assert_eq!(
120 hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(11)),
121 (hmsm(14, 4, 5, 678), 0)
122 );
123 assert_eq!(
124 hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(23)),
125 (hmsm(2, 4, 5, 678), 86_400)
126 );
127 assert_eq!(
128 hmsm(3, 4, 5, 678).overflowing_add_signed(TimeDelta::hours(-7)),
129 (hmsm(20, 4, 5, 678), -86_400)
130 );
131
132 // overflowing_add_signed with leap seconds may be counter-intuitive
133 assert_eq!(
134 hmsm(3, 4, 59, 1_678).overflowing_add_signed(TimeDelta::days(1)),
135 (hmsm(3, 4, 59, 678), 86_400)
136 );
137 assert_eq!(
138 hmsm(3, 4, 59, 1_678).overflowing_add_signed(TimeDelta::days(-1)),
139 (hmsm(3, 5, 0, 678), -86_400)
140 );
141 }
142
143 #[test]
test_time_addassignment()144 fn test_time_addassignment() {
145 let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap();
146 let mut time = hms(12, 12, 12);
147 time += TimeDelta::hours(10);
148 assert_eq!(time, hms(22, 12, 12));
149 time += TimeDelta::hours(10);
150 assert_eq!(time, hms(8, 12, 12));
151 }
152
153 #[test]
test_time_subassignment()154 fn test_time_subassignment() {
155 let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap();
156 let mut time = hms(12, 12, 12);
157 time -= TimeDelta::hours(10);
158 assert_eq!(time, hms(2, 12, 12));
159 time -= TimeDelta::hours(10);
160 assert_eq!(time, hms(16, 12, 12));
161 }
162
163 #[test]
test_time_sub()164 fn test_time_sub() {
165 macro_rules! check {
166 ($lhs:expr, $rhs:expr, $diff:expr) => {{
167 // `time1 - time2 = duration` is equivalent to `time2 - time1 = -duration`
168 assert_eq!($lhs.signed_duration_since($rhs), $diff);
169 assert_eq!($rhs.signed_duration_since($lhs), -$diff);
170 }};
171 }
172
173 let hmsm = |h, m, s, ms| NaiveTime::from_hms_milli_opt(h, m, s, ms).unwrap();
174
175 check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), TimeDelta::zero());
176 check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), TimeDelta::milliseconds(300));
177 check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), TimeDelta::seconds(3600 + 60 + 1));
178 check!(
179 hmsm(3, 5, 7, 200),
180 hmsm(2, 4, 6, 300),
181 TimeDelta::seconds(3600 + 60) + TimeDelta::milliseconds(900)
182 );
183
184 // treats the leap second as if it coincides with the prior non-leap second,
185 // as required by `time1 - time2 = duration` and `time2 - time1 = -duration` equivalence.
186 check!(hmsm(3, 6, 0, 200), hmsm(3, 5, 59, 1_800), TimeDelta::milliseconds(400));
187 //check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), TimeDelta::milliseconds(1400));
188 //check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), TimeDelta::milliseconds(1400));
189
190 // additional equality: `time1 + duration = time2` is equivalent to
191 // `time2 - time1 = duration` IF AND ONLY IF `time2` represents a non-leap second.
192 assert_eq!(hmsm(3, 5, 6, 800) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200));
193 //assert_eq!(hmsm(3, 5, 6, 1_800) + TimeDelta::milliseconds(400), hmsm(3, 5, 7, 200));
194 }
195
196 #[test]
test_core_duration_ops()197 fn test_core_duration_ops() {
198 use core::time::Duration;
199
200 let mut t = NaiveTime::from_hms_opt(11, 34, 23).unwrap();
201 let same = t + Duration::ZERO;
202 assert_eq!(t, same);
203
204 t += Duration::new(3600, 0);
205 assert_eq!(t, NaiveTime::from_hms_opt(12, 34, 23).unwrap());
206
207 t -= Duration::new(7200, 0);
208 assert_eq!(t, NaiveTime::from_hms_opt(10, 34, 23).unwrap());
209 }
210
211 #[test]
test_time_fmt()212 fn test_time_fmt() {
213 assert_eq!(
214 format!("{}", NaiveTime::from_hms_milli_opt(23, 59, 59, 999).unwrap()),
215 "23:59:59.999"
216 );
217 assert_eq!(
218 format!("{}", NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap()),
219 "23:59:60"
220 );
221 assert_eq!(
222 format!("{}", NaiveTime::from_hms_milli_opt(23, 59, 59, 1_001).unwrap()),
223 "23:59:60.001"
224 );
225 assert_eq!(
226 format!("{}", NaiveTime::from_hms_micro_opt(0, 0, 0, 43210).unwrap()),
227 "00:00:00.043210"
228 );
229 assert_eq!(
230 format!("{}", NaiveTime::from_hms_nano_opt(0, 0, 0, 6543210).unwrap()),
231 "00:00:00.006543210"
232 );
233
234 // the format specifier should have no effect on `NaiveTime`
235 assert_eq!(
236 format!("{:30}", NaiveTime::from_hms_milli_opt(3, 5, 7, 9).unwrap()),
237 "03:05:07.009"
238 );
239 }
240
241 #[test]
test_time_from_str()242 fn test_time_from_str() {
243 // valid cases
244 let valid = [
245 "0:0:0",
246 "0:0:0.0000000",
247 "0:0:0.0000003",
248 " 4 : 3 : 2.1 ",
249 " 09:08:07 ",
250 " 09:08 ",
251 " 9:8:07 ",
252 "01:02:03",
253 "4:3:2.1",
254 "9:8:7",
255 "09:8:7",
256 "9:08:7",
257 "9:8:07",
258 "09:08:7",
259 "09:8:07",
260 "09:08:7",
261 "9:08:07",
262 "09:08:07",
263 "9:8:07.123",
264 "9:08:7.123",
265 "09:8:7.123",
266 "09:08:7.123",
267 "9:08:07.123",
268 "09:8:07.123",
269 "09:08:07.123",
270 "09:08:07.123",
271 "09:08:07.1234",
272 "09:08:07.12345",
273 "09:08:07.123456",
274 "09:08:07.1234567",
275 "09:08:07.12345678",
276 "09:08:07.123456789",
277 "09:08:07.1234567891",
278 "09:08:07.12345678912",
279 "23:59:60.373929310237",
280 ];
281 for &s in &valid {
282 eprintln!("test_time_parse_from_str valid {:?}", s);
283 let d = match s.parse::<NaiveTime>() {
284 Ok(d) => d,
285 Err(e) => panic!("parsing `{}` has failed: {}", s, e),
286 };
287 let s_ = format!("{:?}", d);
288 // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same
289 let d_ = match s_.parse::<NaiveTime>() {
290 Ok(d) => d,
291 Err(e) => {
292 panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e)
293 }
294 };
295 assert!(
296 d == d_,
297 "`{}` is parsed into `{:?}`, but reparsed result \
298 `{:?}` does not match",
299 s,
300 d,
301 d_
302 );
303 }
304
305 // some invalid cases
306 // since `ParseErrorKind` is private, all we can do is to check if there was an error
307 let invalid = [
308 "", // empty
309 "x", // invalid
310 "15", // missing data
311 "15:8:", // trailing colon
312 "15:8:x", // invalid data
313 "15:8:9x", // invalid data
314 "23:59:61", // invalid second (out of bounds)
315 "23:54:35 GMT", // invalid (timezone non-sensical for NaiveTime)
316 "23:54:35 +0000", // invalid (timezone non-sensical for NaiveTime)
317 "1441497364.649", // valid datetime, not a NaiveTime
318 "+1441497364.649", // valid datetime, not a NaiveTime
319 "+1441497364", // valid datetime, not a NaiveTime
320 "001:02:03", // invalid hour
321 "01:002:03", // invalid minute
322 "01:02:003", // invalid second
323 "12:34:56.x", // invalid fraction
324 "12:34:56. 0", // invalid fraction format
325 "09:08:00000000007", // invalid second / invalid fraction format
326 ];
327 for &s in &invalid {
328 eprintln!("test_time_parse_from_str invalid {:?}", s);
329 assert!(s.parse::<NaiveTime>().is_err());
330 }
331 }
332
333 #[test]
test_time_parse_from_str()334 fn test_time_parse_from_str() {
335 let hms = |h, m, s| NaiveTime::from_hms_opt(h, m, s).unwrap();
336 assert_eq!(
337 NaiveTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
338 Ok(hms(12, 34, 56))
339 ); // ignore date and offset
340 assert_eq!(NaiveTime::parse_from_str("PM 12:59", "%P %H:%M"), Ok(hms(12, 59, 0)));
341 assert_eq!(NaiveTime::parse_from_str("12:59 \n\t PM", "%H:%M \n\t %P"), Ok(hms(12, 59, 0)));
342 assert_eq!(NaiveTime::parse_from_str("\t\t12:59\tPM\t", "\t\t%H:%M\t%P\t"), Ok(hms(12, 59, 0)));
343 assert_eq!(
344 NaiveTime::parse_from_str("\t\t1259\t\tPM\t", "\t\t%H%M\t\t%P\t"),
345 Ok(hms(12, 59, 0))
346 );
347 assert!(NaiveTime::parse_from_str("12:59 PM", "%H:%M\t%P").is_ok());
348 assert!(NaiveTime::parse_from_str("\t\t12:59 PM\t", "\t\t%H:%M\t%P\t").is_ok());
349 assert!(NaiveTime::parse_from_str("12:59 PM", "%H:%M %P").is_ok());
350 assert!(NaiveTime::parse_from_str("12:3456", "%H:%M:%S").is_err());
351 }
352
353 #[test]
test_overflowing_offset()354 fn test_overflowing_offset() {
355 let hmsm = |h, m, s, n| NaiveTime::from_hms_milli_opt(h, m, s, n).unwrap();
356
357 let positive_offset = FixedOffset::east_opt(4 * 60 * 60).unwrap();
358 // regular time
359 let t = hmsm(5, 6, 7, 890);
360 assert_eq!(t.overflowing_add_offset(positive_offset), (hmsm(9, 6, 7, 890), 0));
361 assert_eq!(t.overflowing_sub_offset(positive_offset), (hmsm(1, 6, 7, 890), 0));
362 // leap second is preserved, and wrap to next day
363 let t = hmsm(23, 59, 59, 1_000);
364 assert_eq!(t.overflowing_add_offset(positive_offset), (hmsm(3, 59, 59, 1_000), 1));
365 assert_eq!(t.overflowing_sub_offset(positive_offset), (hmsm(19, 59, 59, 1_000), 0));
366 // wrap to previous day
367 let t = hmsm(1, 2, 3, 456);
368 assert_eq!(t.overflowing_sub_offset(positive_offset), (hmsm(21, 2, 3, 456), -1));
369 // an odd offset
370 let negative_offset = FixedOffset::west_opt(((2 * 60) + 3) * 60 + 4).unwrap();
371 let t = hmsm(5, 6, 7, 890);
372 assert_eq!(t.overflowing_add_offset(negative_offset), (hmsm(3, 3, 3, 890), 0));
373 assert_eq!(t.overflowing_sub_offset(negative_offset), (hmsm(7, 9, 11, 890), 0));
374
375 assert_eq!(t.overflowing_add_offset(positive_offset).0, t + positive_offset);
376 assert_eq!(t.overflowing_sub_offset(positive_offset).0, t - positive_offset);
377 }
378
379 #[test]
380 #[cfg(feature = "rkyv-validation")]
test_rkyv_validation()381 fn test_rkyv_validation() {
382 let t_min = NaiveTime::MIN;
383 let bytes = rkyv::to_bytes::<_, 8>(&t_min).unwrap();
384 assert_eq!(rkyv::from_bytes::<NaiveTime>(&bytes).unwrap(), t_min);
385
386 let t_max = NaiveTime::MAX;
387 let bytes = rkyv::to_bytes::<_, 8>(&t_max).unwrap();
388 assert_eq!(rkyv::from_bytes::<NaiveTime>(&bytes).unwrap(), t_max);
389 }
390