diff --git a/crates/core/src/parse.rs b/crates/core/src/parse.rs index a612a0b..a943103 100644 --- a/crates/core/src/parse.rs +++ b/crates/core/src/parse.rs @@ -252,10 +252,14 @@ fn parse_date(t: &str, sys: DateSystem) -> Option<(f64, &'static str)> { // "Mar 4, 2026" / "March 4 2026" / "4 March 2026" let words: Vec<&str> = t.split([' ', ',']).filter(|w| !w.is_empty()).collect(); if words.len() == 3 { + // Two-digit years follow the same 2029 rule as the dashed forms above. + let expand = |w: &str, y: i64| if w.len() <= 2 { if y < 30 { 2000 + y } else { 1900 + y } } else { y }; if let (Some(m), Some(d), Some(y)) = (month_from_name(words[0]), num(words[1]), num(words[2])) { + let y = expand(words[2], y); return valid_ymd(sys, y, m as i64, d).map(|s| (s, "d-mmm-yy")); } if let (Some(d), Some(m), Some(y)) = (num(words[0]), month_from_name(words[1]), num(words[2])) { + let y = expand(words[2], y); return valid_ymd(sys, y, m as i64, d).map(|s| (s, "d-mmm-yy")); } } @@ -317,6 +321,16 @@ mod tests { parse_input(s, DateSystem::D1900) } + #[test] + fn month_name_short_year() { + for s in ["Mar 4, 26", "Mar 4 26", "March 4 26", "4 March 26", "Mar 4, 2026"] { + assert_eq!(p(s).value, Value::Number(46085.0), "{s}"); + } + assert_eq!(p("Mar 4, 99").value, p("Mar 4, 1999").value); + assert_eq!(p("Mar 4, 1776").value, Value::text("Mar 4, 1776")); + assert_eq!(p("Feb 30, 26").value, Value::text("Feb 30, 26")); + } + #[test] fn numbers() { assert_eq!(p("42").value, Value::Number(42.0));