Skip to content

Commit e8f04f0

Browse files
fable-repo-assist[bot]Copilot
authored andcommitted
fix(js/ts): reject JS-permissive date strings that .NET TryParse rejects
V8's Date constructor accepts strings like "ABC 6" by treating the letter sequence as a timezone abbreviation. .NET DateTime.TryParse rejects such strings as invalid. Add a pre-validation check in parseRaw() that requires the input to start with a digit or a recognised month-name prefix (Jan–Dec). This matches .NET behaviour while preserving all existing valid formats. Closes #3858 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2d9673f commit e8f04f0

2 files changed

Lines changed: 23 additions & 0 deletions

File tree

src/fable-library-ts/Date.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,15 @@ export function parseRaw(input: string): [Date, Offset] {
599599
fail();
600600
}
601601

602+
// Pre-validate: reject strings that JavaScript's Date constructor accepts but .NET does not.
603+
// JS Date (V8) is overly permissive — e.g. "ABC 6" is accepted because V8 treats "ABC" as a
604+
// timezone abbreviation. .NET DateTime.TryParse requires a recognisable date format.
605+
// Valid date strings must start with a digit, or with a recognised month name (Jan–Dec).
606+
// See #3858.
607+
if (!/^\s*(?:\d|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/i.test(input)) {
608+
fail();
609+
}
610+
602611
// ISO dates without TZ are parsed as UTC. Adding time without TZ keeps them local.
603612
if (input.length === 10 && input[4] === "-" && input[7] === "-") {
604613
input += "T00:00:00";

tests/Js/Main/DateTimeTests.fs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,20 @@ let tests =
876876
let r, _date = DateTime.TryParse(invalidAmericanDate, CultureInfo.InvariantCulture, DateTimeStyles.None)
877877
r |> equal false
878878

879+
testCase "DateTime.TryParse rejects JS-permissive strings that .NET rejects" <| fun () ->
880+
// V8's Date constructor accepts "ABC 6" by treating "ABC" as a timezone abbreviation.
881+
// .NET DateTime.TryParse must reject it. See #3858.
882+
let r1, _ = DateTime.TryParse("ABC 6")
883+
r1 |> equal false
884+
885+
let r2, _ = DateTime.TryParse("XYZ 2024")
886+
r2 |> equal false
887+
888+
// Valid dates must still parse
889+
let r3, d = DateTime.TryParse("9/10/2014 1:50:34 PM")
890+
r3 |> equal true
891+
d.Year |> equal 2014
892+
879893
testCase "DateTime.Today works" <| fun () ->
880894
let d = DateTime.Today
881895
equal 0 d.Hour

0 commit comments

Comments
 (0)