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')andnew 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/28are 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
Dateinherits design problems from Java’sjava.util.Date(zero-based month, bad constructors, etc.). - Java deprecated most
Dateconstructors; JS can’t, due to web compatibility. - The upcoming
TemporalAPI is viewed as the proper fix, with explicit types:Instant(timestamp),ZonedDateTime(timestamp + zone),PlainDateTime/PlainDate/PlainTime, plusDuration.
- Some compare these to PostgreSQL
timestamptz,timestamp,date,time, andinterval.
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.