Why are 2025/05/28 and 2025-05-28 different days in JavaScript?

JavaScript Date Parsing & “Undefined” Behavior

  • The core issue: new Date('2025/05/28') and new Date('2025-05-28') are specified differently.
  • The spec only guarantees behavior for ISO-like strings; other formats are explicitly left to implementations, so browsers can interpret them however they like.
  • Slash formats like 2025/05/28 are treated as legacy, local-time dates; dash ISO-like ones may involve time zones and are handled differently.
  • Some see this as “undocumented undefined behavior”; others point out it is documented as implementation-defined, just surprising.

Legacy of Date and the Temporal Fix

  • JS Date inherits design problems from Java’s java.util.Date (zero-based month, bad constructors, etc.).
  • Java deprecated most Date constructors; JS can’t, due to web compatibility.
  • The upcoming Temporal API is viewed as the proper fix, with explicit types:
    • Instant (timestamp), ZonedDateTime (timestamp + zone), PlainDateTime / PlainDate / PlainTime, plus Duration.
  • Some compare these to PostgreSQL timestamptz, timestamp, date, time, and interval.

Why the Web Runs on This Anyway

  • Historical path dependence: JS was “the toy language” shipped in browsers while heavier plugin-based stacks (Java applets, Flash, Silverlight) failed due to security, performance, and crash issues.
  • Despite a weak early standard library (even Node.js started on ES3), browser ubiquity and incremental improvements made JS the de facto web language.

Browser Monoculture & Standards Politics

  • Debate over whether a single dominant browser plus strong standard library would be better or worse than today’s de facto Chrome/Safari duopoly.
  • Temporal’s rollout illustrates how one dominant engine can effectively gate new language features.
  • The date-string behavior got locked in after complaints that spec-conforming changes in Chrome were “breaking,” eventually pushing the spec toward legacy behavior.

Dates, Time Zones, and Best Practices

  • Strong consensus: date/time handling is hard everywhere; never rely on generic “auto-parse” of arbitrary date strings.
  • Recurrent advice:
    • Distinguish absolute timestamps vs. calendar/clock times; store the correct concept.
    • Use explicit parsing/formatting functions and high-level APIs, not manual string hacking.
    • “Just use UTC” is not a universal solution: you may need to store original time zone (and sometimes location) for meetings, logs, or legal/UX reasons.
    • For pure calendar dates (e.g., birthdays, age checks), store date-only types; timestamps and time zones are often irrelevant or misleading.

ISO 8601, RFC3339, and Human Formats

  • Many advocate ISO 8601 YYYY-MM-DD (or RFC3339) as the only sane interchange format.
  • Others note ISO 8601’s permissiveness and odd variants; RFC3339 is praised for being stricter and freely accessible.
  • There’s extended debate on separators (- vs /), regional formats (MDY, DMY, YMD), and how easily ambiguity creeps in.

Frustration, Humor, and War Stories

  • Multiple anecdotes of bugs caused by JS silently attaching local midnight to date-only values, shifting days when converted to UTC.
  • Calls for separate “Day” or local-date types and for languages to avoid forcing every date into a timestamp-plus-time-zone model.
  • Links to classic “WAT” talks, xkcd, and “falsehoods programmers believe about time” underline that these problems are pervasive and longstanding, not unique to JS.