Normative description of Date as implemented in Builtins/Date*.cs: ECMA-262 17th edition 21.4 and Annex B.2.3.
Host seams
- Clock:
IJsHost.CurrentTimeMs()only (Date.now,new Date(),Date()). - Zone:
IJsHost.TimeZoneIdnames the IANA zone used for local time. - Offsets:
IJsHost.TryGetTimeZoneOffset(zoneId, epochMs, out offsetMs, out isDaylight). A default interface member answers from the BCL time zone rules of the machine;DefaultHostexposes it as a virtual method; a host that must not depend on the machine overrides it with its own rules. When it returns false, local time is UTC. - The BCL rules cover years 1 to 9999. For later instants the engine asks about the same moment in an equivalent 400-year cycle (calendar and weekday repeat exactly; rules do not change that far out). Before year 1 the BCL answers with its earliest offset.
Local time
LocalTime(t)istplus the offset att.UTC(t)for a local time valuet(21.4.1.26, GetUTCEpochNanoseconds): look at the offsets a day before and a day aftert; each offsetofor which the zone's offset att - oisogives a candidate instant; the earliest candidate wins (clocks set back: the first occurrence). With no candidate (clocks set forward) the offset from before the transition is used, which moves the time forward by the size of the gap.- All time arithmetic is exact
doublearithmetic over +/-8.64e15;MakeDayreturns NaN for years beyond +/-400000 without computing.
Constructor, parse, UTC
- Every form of 21.4.2.1;
Date()called as a function returns the string for the current time. A one-argument call with a Date copies its time value without conversion; other objects go throughToPrimitive, strings throughDate.parse. Date.UTCand the multi-argument constructor applyMakeFullYear(0 to 99 mean 1900 to 1999).
Strings accepted by Date.parse
- The Date Time String Format (21.4.1.32) exactly:
YYYY,YYYY-MM,YYYY-MM-DD, expanded years+YYYYYY/-YYYYYY(-000000is rejected), optionallyTHH:mm,THH:mm:ss,THH:mm:ss.s…(any number of fraction digits, truncated to milliseconds) andZor±HH:mm(±HHmmtoo).TandZmay be lower case. Date-only forms are UTC, date-time forms without an offset are local time. Hour 24 is accepted only as24:00:00.000. A day from 1 to 31 is accepted in every month and rolls over (2023-02-30is 1 March). - Legacy forms when the string is not in the format above; observed from Node v24 and kept to the cases real code relies on:
- Words: a month name (the first three letters decide:
Jul,July,Sept), a day name (ignored),AM/PM(after a time, hour at most 12),Z,UT,UTC,GMT, and the US zone abbreviationsEST EDT CST CDT MST MDT PST PDT. Any other word is ignored before the first number and makes the string invalid after it. A word touching a number (4th,10:00pm) is invalid, except aZright after a time. - Numbers: up to three, separated by spaces,
,,/,.or-(a-after a number must touch its neighbours). With a month name:D Y,Y D(first number above 31, or three or more digits) or one number (a day up to 31, or a year). Without:M/D/Y,Y/M/D(first number above 31, three or more digits, or 0),M/D,Y/Mor a single month or year. A missing year is 2001, a missing day is 1. Years below 100 written with fewer than four digits mean 2000 to 2049 and 1950 to 1999. - Time:
H:M,H:M:S,H:M:S.fff; a colon with no digits after it reads as zero, further:ngroups are ignored; a dot after the seconds must be followed by digits. - Zone:
+H,+HH,+HMM,+HHMM,+HH:MM, also afterGMT/UTC; up to four digits. Without a zone the result is local time. - Parenthesised text is skipped (an unclosed parenthesis runs to the end); an unmatched
)or any other character makes the string invalid. - Day 1 to 31 and month 1 to 12 are accepted and day overflow rolls into the next month.
- The output of
toString,toUTCStringandtoISOStringparses back to the same time value (to the second fortoStringandtoUTCString).
- Words: a month name (the first three letters decide:
Known differences from the reference: -000000-01-01 (the reference reads a stray sign, 2001-01-01); a number written with a sign following a number or a zone name is only partly modelled; Jan 1 1 1 (three numbers and a month, the reference ignores one).
Prototype
All getters and setters of 21.4.4 in UTC and local variants, with the argument conversion order of the specification (every argument is converted before the NaN check). Annex B: getYear, setYear, toGMTString (the same function object as toUTCString). getTimezoneOffset is exactly (t - LocalTime(t)) / msPerMinute, which is fractional where a zone has a seconds offset. toJSON, @@toPrimitive (hints default, string, number; others throw TypeError: Invalid hint: x), valueOf.
Methods called on a non-Date throw TypeError: this is not a Date object. toISOString of an invalid date throws RangeError: Invalid time value.
String forms
toString:Thu Jul 04 2024 10:00:00 GMT-0500 (Central Daylight Time). The offset is±HHMMrounded to the minute; the parenthesised text is the zone's long English name from the CLDR data (en), looked up for the instant clamped to 1970 to 9999; a zone without a name there falls back toGMT-05:00. Years print with at least four digits and a leading-when negative (-0001).toDateString:Thu Jul 04 2024;toTimeString:10:00:00 GMT-0500 (Central Daylight Time);toUTCString:Thu, 04 Jul 2024 10:00:00 GMT;toISOString:2024-07-04T15:00:00.000Z, with±YYYYYYoutside years 0 to 9999. An invalid date printsInvalid Datein all buttoISOString.toLocaleString,toLocaleDateString,toLocaleTimeString:DateTimeFormatServicewith the locale argument (a string or list of strings, elseIJsHost.DefaultLocale), the options object read as plain values, and the host zone. U+202F in the CLDR time patterns is replaced by U+0020, as the reference engines print it.
Differential
testdata/date/probe.js prints about 2,400 observations (getters, setters, constructor gaps and overlaps, parse, locale strings) across DST edges, the epoch, 1900, 2038, the ends of the range and far years. tools/date-diff/record.sh records Node's output under TZ=America/Chicago, Europe/Berlin and UTC into expected.*.txt (Node v24.22.1). DateNodeDifferentialTests runs the same script on the engine with the host zone set to the same zone. Lines for instants before 1900 are compared in UTC only: the zone rules read through the BCL round local mean time to whole minutes and the reference prints seconds (GMT-0550 against GMT-0551 in Chicago before 1883). A host with its own tzdata reader does not have this limit. On Windows the default host reads the operating system's zone rules (through CLDR's windowsZones mapping when the machine has no IANA ids), which differ from tzdata for the past: Berlin in 1945 has +0200 where tzdata has a second summer hour (+0300). The differential therefore compares Windows runs from 1970 on only; a host that needs tzdata history supplies its own TryGetTimeZoneOffset. testdata/date/deviations.txt lists the other known differences.