Reject impossible dates such as Feb 30 in FormCalc Date2Num and Parse (#2388)

Found while testing crates/js/src/formcalc.rs:1916

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-15 02:58:25 -04:00
committed by GitHub
co-authored by Claude Haiku 5.5
parent c97ca226e6
commit 0d864e2e31
2 changed files with 25 additions and 1 deletions
+11 -1
View File
@@ -1913,7 +1913,17 @@ fn parse_date(text: &str, picture: &str) -> Option<(i64, u32, u32)> {
}
}
let (y, m, d) = (y?, m.unwrap_or(1), d.unwrap_or(1));
((-200_000..=200_000).contains(&y) && (1..=12).contains(&m) && (1..=31).contains(&d)).then_some((y, m, d))
((-200_000..=200_000).contains(&y) && (1..=12).contains(&m) && (1..=days_in(y, m)).contains(&d)).then_some((y, m, d))
}
/// Number of days in month `m` (1-12) of year `y`, leap years included.
fn days_in(y: i64, m: u32) -> u32 {
match m {
2 if (y % 4 == 0 && y % 100 != 0) || y % 400 == 0 => 29,
2 => 28,
4 | 6 | 9 | 11 => 30,
_ => 31,
}
}
fn format_date(y: i64, m: u32, d: u32, picture: &str) -> String {
+14
View File
@@ -692,6 +692,20 @@ mod formcalc {
assert!(go("Nope(1)", "form1[0].page1[0].total[0]", "calculate").error.unwrap().contains("unknown function"));
}
#[test]
fn date2num_rejects_days_past_the_end_of_the_month() {
assert_eq!(calc(r#"Date2Num("2023-02-30")"#), "0");
assert_eq!(calc(r#"Date2Num("31/04/2024", "DD/MM/YYYY")"#), "0");
assert_eq!(calc(r#"Date2Num("2023-02-29")"#), "0");
assert_eq!(calc(r#"Date2Num("1900-02-29")"#), "0");
assert_eq!(calc(r#"Parse("YYYY-MM-DD", "2023-02-30") == null"#), "1");
// Valid month ends still work.
assert_eq!(calc(r#"Date2Num("2024-02-29")"#), "45350");
assert_eq!(calc(r#"Date2Num("2000-02-29") <> 0"#), "1");
assert_eq!(calc(r#"Date2Num("2024-04-30") <> 0"#), "1");
assert_eq!(calc(r#"Date2Num("2024-12-31") <> 0"#), "1");
}
#[test]
fn control_flow_variables_and_functions_work() {
assert_eq!(calc("var x = 3\nif (x > 2) then 10 elseif (x > 1) then 20 else 30 endif"), "10");