From 9c95c9549b155c81cc4644b5eca66b7c21af5451 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 29 Oct 2025 10:23:52 +0100 Subject: [PATCH] feat: support formats Nov-14-2024/November-14-2024 --- src/items/date.rs | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/items/date.rs b/src/items/date.rs index 34533db..5de3351 100644 --- a/src/items/date.rs +++ b/src/items/date.rs @@ -128,7 +128,7 @@ impl TryFrom for jiff::civil::Date { } pub(super) fn parse(input: &mut &str) -> ModalResult { - alt((iso1, iso2, us, literal1, literal2)).parse_next(input) + alt((iso1, iso2, us, literal1, literal2, literal3)).parse_next(input) } /// Parse `[year]-[month]-[day]` @@ -252,6 +252,18 @@ fn literal2(input: &mut &str) -> ModalResult { } } +/// Parse `November-14-2022` and `Nov-14-2022`. Unlike `literal2`, the year is mandatory +/// to match the behavior of GNU `date`. +fn literal3(input: &mut &str) -> ModalResult { + let (month, _, day, _, year) = + (s(literal_month), s('-'), s(dec_uint), s('-'), year_str).parse_next(input)?; + + // Map err to Backtrack instead of Cut to avoid early termination of parsing + (year, month, day) + .try_into() + .map_err(|e| ErrMode::Backtrack(ctx_err(e))) +} + /// Parse the name of a month (case-insensitive) fn literal_month(input: &mut &str) -> ModalResult { s(alpha1) @@ -549,6 +561,27 @@ mod tests { assert_eq!(s, ", 2022a"); } + #[test] + fn literal3() { + let reference = Date { + year: Some(2022), + month: 11, + day: 14, + }; + + for mut s in [ + "november-14-2022", + "november----14----2022", + "november - 14 - 2022", + "nov-14-2022", + "nov---14---2022", + "nov - 14 - 2022", + ] { + let old_s = s.to_owned(); + assert_eq!(parse(&mut s).unwrap(), reference, "Format string: {old_s}"); + } + } + #[test] fn with_year() { let reference = Date {