1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
use crate::helpers::digits::{dec_digits_2, dec_digits_9};
use chrono::NaiveTime;
use nom::{
    character::complete::char,
    combinator::{map_opt, opt},
    sequence::{preceded, tuple},
    IResult,
};

pub(crate) fn time(i: &str) -> IResult<&str, NaiveTime> {
    map_opt(
        tuple((
            dec_digits_2,
            preceded(char(':'), dec_digits_2),
            preceded(char(':'), dec_digits_2),
            opt(preceded(char('.'), dec_digits_9)),
        )),
        |(hours, minutes, seconds, nanoseconds)| {
            NaiveTime::from_hms_nano_opt(
                hours.into(),
                minutes.into(),
                seconds.into(),
                nanoseconds.unwrap_or(0).into(),
            )
        },
    )(i)
}

#[test]
fn it_should_parse_simple_time() {
    assert_eq!(time("12:03:12"), Ok(("", NaiveTime::from_hms(12, 3, 12))));
}

#[test]
fn it_should_parse_time_with_nanoseconds() {
    assert_eq!(
        time("13:01:01.123456789"),
        Ok(("", NaiveTime::from_hms_nano(13, 1, 1, 123456789)))
    );
}

#[test]
fn it_should_fail_given_time_is_out_of_range() {
    let invalid = ["25:00:00", "01:60:00", "01:59:60"];
    for &v in &invalid {
        assert!(time(v).is_err());
    }
}