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