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 49 50 51 52 53 54 55 56 57 58 59 60
use crate::helpers::digits::{dec_digits_2, dec_digits_4}; use chrono::NaiveDate; use nom::{ character::complete::char, combinator::map_opt, sequence::{preceded, tuple}, IResult, }; pub(crate) fn date(i: &str) -> IResult<&str, NaiveDate> { map_opt( tuple(( dec_digits_4, preceded(char('-'), dec_digits_2), preceded(char('-'), dec_digits_2), )), |(year, month, day): (u16, u8, u8)| { NaiveDate::from_ymd_opt(year.into(), month.into(), day.into()) }, )(i) } #[test] fn it_should_parse_valid_dates() { assert_eq!( date("2018-08-15"), Ok(("", NaiveDate::from_ymd(2018, 8, 15))) ); assert_eq!( date("2018-08-15 "), Ok((" ", NaiveDate::from_ymd(2018, 8, 15))) ); assert_eq!( date("2018-08-15 (code)"), Ok((" (code)", NaiveDate::from_ymd(2018, 8, 15))), ); } #[test] fn it_should_fail_on_invalid_date_syntax() { let invalid = [" 2018-08-15 ", "2018-0-1", "2···-··-··"]; for &v in &invalid { assert!(date(v).is_err()); } } #[test] fn it_should_fail_on_dates_out_of_range() { let invalid = [ "2018-00-01", "2018-13-01", "2018-01-32", "2018-02-29", "2018-04-31", "2018-01-00", ]; for &v in &invalid { assert!(date(v).is_err()); } }