Skip to content

fix(date): Date.UTC defaults, setter optional args, Date.parse grammar - #3407

Merged
proggeramlug merged 1 commit into
mainfrom
fix-date-semantics-2826-2851-2827
May 30, 2026
Merged

fix(date): Date.UTC defaults, setter optional args, Date.parse grammar#3407
proggeramlug merged 1 commit into
mainfrom
fix-date-semantics-2826-2851-2827

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Closes #2826
Closes #2851
Closes #2827

Implementation

Reworks Date argument semantics in crates/perry-runtime/src/date.rs to match Node exactly, with the supporting HIR/codegen plumbing to carry full argument lists.

#2826Date.UTC defaults, year rebasing, invalid-argument semantics

  • js_date_utc now takes (args_ptr, argc) (a NaN-boxed args buffer + count) instead of seven pre-padded f64s, so the runtime can distinguish omitted from explicit-zero components.
  • argc == 0NaN; omitted month → 0, omitted day → 1, omitted time fields → 0.
  • Integral year in 0..=99 is rebased to 1900 + year (rebase_two_digit_year).
  • Any provided component that coerces to NaN → Invalid (NaN).
  • Out-of-range components (day 0, month 12/-1, negative days, time overflow) normalize via a new signed days_from_civil + make_utc_ms (ECMA MakeDay/MakeTime), shared by new Date(...) local construction.

#2851 — Date setters honor optional trailing arguments

  • The 15 setter HIR variants changed from { date, value } to { date, args: Vec<Expr> } (crates/perry-hir/src/ir/expr.rs), with matching updates to the stable-hash field hashing, both HIR walkers, lowering (url_date_instance.rs, no longer gated on !args.is_empty()), and all native/JS/wasm codegen backends.
  • A single runtime entry point js_date_apply_setter(date, is_utc, field, args_ptr, argc) replaces the per-setter helpers. It applies every supplied component (setUTCHours(h, min?, sec?, ms?), setUTCFullYear(y, mo?, d?), etc.), keeps omitted trailing fields, and treats an omitted/undefined leading argument as NaN → Invalid Date (setHours() → Invalid). rebuild_with / rebuild_local_with were rewritten to take Option<f64> overrides with NaN-propagation.

#2827Date.parse string grammar + timezone handling

parse_date_string rewritten into parse_iso8601 + parse_rfc_or_named:

  • ISO 8601 YYYY, YYYY-MM, YYYY-MM-DD, optional THH:MM[:SS[.sss]], optional Z / +HH:MM / -HH:MM / +HHMM offset; date-only/no-offset treated as UTC.
  • YYYY-MM-DD HH:MM:SS (MySQL).
  • RFC-1123 / IETF: Thu, 01 Jan 1970 00:00:00 GMT, 01 Jan 1970 00:00:00 GMT (optional weekday, GMT/UTC/offset).
  • Month-name forms (March 7, 2020), interpreted as local time when no zone token is present.
  • The old s.parse::<f64>()-first behavior that made Date.parse("2020") return 2020 is gone.

New #[no_mangle] symbols js_date_utc (signature change) and js_date_apply_setter get #[used] keepalive anchors so the auto-optimize whole-program LLVM rebuild doesn't dead-strip them.

Validation

  • Gap test test-files/test_gap_date_2826_2851_2827.ts (fixed inputs only — no Date.now()/argless new Date()) is byte-identical to node --experimental-strip-types under the default auto-optimize compile.
  • cargo test --release -p perry-runtime date (19 passed) and cargo test --release -p perry-hir (green, including expr_variant_stable_hash_tags_are_unique).
  • ./scripts/check_file_size.sh exit 0, cargo fmt --all -- --check clean, full cargo build --release clean (cold).
  • Existing test_gap_date_methods.ts, test_issue_1187_date_setters.ts, test_issue_2089_date_reference.ts, test_issue_748_invalid_date.ts, test_gap_2371_console_invalid_date.ts remain byte-identical to Node. Extra edge cases (negative ISO offset, month underflow Date.UTC(2020,-1,1), Mar 31 → setUTCMonth(1) rollover) also verified identical.

@proggeramlug
proggeramlug merged commit 3804b35 into main May 30, 2026
11 checks passed
@proggeramlug
proggeramlug deleted the fix-date-semantics-2826-2851-2827 branch May 30, 2026 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant