Skip to content

Commit 64c98ac

Browse files
committed
fix: implementation
1 parent e8f04f0 commit 64c98ac

2 files changed

Lines changed: 35 additions & 17 deletions

File tree

src/fable-library-ts/Date.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,18 @@ export function maxValue() {
590590
return DateTime(253402300799999, DateTimeKind.Utc);
591591
}
592592

593+
// The only date words .NET's invariant parser recognises: month names, weekday names,
594+
// meridiem designators and zone markers (plus the ISO "T" separator). Anything else is
595+
// rejected. Used to reject JS-permissive inputs (see `parseRaw`).
596+
const recognizedDateWords = new Set([
597+
"january", "february", "march", "april", "may", "june",
598+
"july", "august", "september", "october", "november", "december",
599+
"jan", "feb", "mar", "apr", "jun", "jul", "aug", "sep", "sept", "oct", "nov", "dec",
600+
"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday",
601+
"mon", "tue", "wed", "thu", "fri", "sat", "sun",
602+
"am", "pm", "gmt", "utc", "ut", "t", "z",
603+
]);
604+
593605
export function parseRaw(input: string): [Date, Offset] {
594606
function fail() {
595607
throw new Exception(`The string is not a valid Date: ${input}`);
@@ -599,12 +611,7 @@ export function parseRaw(input: string): [Date, Offset] {
599611
fail();
600612
}
601613

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)) {
614+
if ((input.match(/[a-z]+/gi) ?? []).some(word => !recognizedDateWords.has(word.toLowerCase()))) {
608615
fail();
609616
}
610617

tests/Js/Main/DateTimeTests.fs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -877,18 +877,29 @@ let tests =
877877
r |> equal false
878878

879879
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")
880+
// JS's Date constructor treats unrecognised words as timezone abbreviations, so it
881+
// accepts strings .NET rejects: "ABC 6" (ABC), "XYZ 2024" (XYZ), and words that merely
882+
// start with a month name like "Maybe 6" (May) or "Junk 2024" (Jun).
883+
[ "ABC 6"; "XYZ 2024"; "Maybe 6"; "Junk 2024" ]
884+
|> List.map (fun s -> fst (DateTime.TryParse s))
885+
|> equal [ false; false; false; false ]
886+
887+
// Recognised date words (weekday / month names, GMT) must still parse, matching .NET.
888+
let r1, d1 = DateTime.TryParse("Sun, 06 Nov 1994 08:49:37 GMT")
889+
r1 |> equal true
890+
d1.Year |> equal 1994
891+
892+
let r2, d2 = DateTime.TryParse("Mon, 15 Jan 2024")
893+
r2 |> equal true
894+
d2.Year |> equal 2024
895+
896+
let r3, d3 = DateTime.TryParse("January 15, 2024")
890897
r3 |> equal true
891-
d.Year |> equal 2014
898+
d3.Year |> equal 2024
899+
900+
let r4, d4 = DateTime.TryParse("9/10/2014 1:50:34 PM")
901+
r4 |> equal true
902+
d4.Year |> equal 2014
892903

893904
testCase "DateTime.Today works" <| fun () ->
894905
let d = DateTime.Today

0 commit comments

Comments
 (0)