The JavaScript Date object stores one number, the milliseconds since the Unix epoch (1970-01-01T00:00:00Z), and every getter and formatter is a view of that number in a time zone. This sheet is for developers who parse date strings, do date math or format dates for display. The confusion it clears up: the same string can parse to different instants depending on whether it has a time part, and months count from 0.
| Expression | Result |
|---|---|
| `new Date()` | Now |
| `Date.now()` | Now as a number of milliseconds, no object |
| `new Date(ms)` | From a timestamp in milliseconds |
| `new Date('2026-10-05T09:30:00+02:00')` | From an ISO string, `2026-10-05T07:30:00.000Z` |
| `new Date(2026, 9, 5)` | Local midnight, month 9 is October |
| `new Date(Date.UTC(2026, 9, 5, 12))` | UTC components, `1791201600000` |
| `new Date(otherDate)` | Copy |
| `Date()` without `new` | A string, not an object |
| Local | UTC | Range |
|---|---|---|
| `getFullYear()` | `getUTCFullYear()` | Four-digit year |
| `getMonth()` | `getUTCMonth()` | 0 to 11 |
| `getDate()` | `getUTCDate()` | 1 to 31 |
| `getDay()` | `getUTCDay()` | 0 (Sunday) to 6 |
| `getHours()` | `getUTCHours()` | 0 to 23 |
| `getMinutes()` | `getUTCMinutes()` | 0 to 59 |
| `getSeconds()` | `getUTCSeconds()` | 0 to 59 |
| `getMilliseconds()` | `getUTCMilliseconds()` | 0 to 999 |
| `getTime()` or `valueOf()` | same | Milliseconds since the epoch |
| `getTimezoneOffset()` | none | Minutes, UTC minus local, so New York in summer is `240` |
Each getter has a set twin, such as setDate(n), setMonth(m, d) and setUTCHours(h). Setters mutate the object and return the new timestamp.
Values below are for Date.UTC(2026, 9, 5, 12) with the process time zone set to America/New_York.
| Method | Output |
|---|---|
| `toISOString()` | `2026-10-05T12:00:00.000Z` |
| `toJSON()` | `2026-10-05T12:00:00.000Z` |
| `toUTCString()` | `Mon, 05 Oct 2026 12:00:00 GMT` |
| `toString()` | `Mon Oct 05 2026 08:00:00 GMT-0400 (Eastern Daylight Time)` |
| `toDateString()` | `Mon Oct 05 2026` |
| `toLocaleDateString('en-US')` | `10/5/2026` |
| `toLocaleDateString('en-GB')` | `05/10/2026` |
| `toLocaleDateString('de-DE')` | `5.10.2026` |
| `toLocaleTimeString('en-US')` | `8:00:00 AM` |
| Fact | Value |
|---|---|
| Latest representable time | `8.64e15` ms, `+275760-09-13T00:00:00.000Z` |
| Earliest representable time | `-8.64e15` ms, `-271821-04-20T00:00:00.000Z` |
| Beyond the range | `NaN`, shown as `Invalid Date` |
| Invalid check | `isNaN(date)` or `Number.isNaN(date.getTime())` |
| Two-digit year in the constructor | `new Date(99, 0, 1)` is 1999 |
| Year 100 and up | Taken literally, `new Date(100, 0, 1)` is year 100 |
console.log(new Date('2026-10-05').toISOString());
console.log(new Date('2026-10-05T00:00:00').toISOString());
console.log(new Date('2026-10-05T00:00:00Z').toISOString());
2026-10-05T00:00:00.000Z
2026-10-05T04:00:00.000Z
2026-10-05T00:00:00.000Z
Run with TZ=America/New_York. A date-only string is read as UTC, a date-time without an offset is read as local time, and a trailing Z or offset is exact. Add an offset or Z whenever the time zone matters.
const d = new Date(Date.UTC(2026, 9, 5, 12));
console.log(d.toLocaleDateString('en-US', {weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', timeZone: 'UTC'}));
console.log(d.toLocaleString('en-US', {dateStyle: 'medium', timeStyle: 'short', timeZone: 'UTC'}));
console.log(d.toLocaleString('en-US', {timeZone: 'Asia/Tokyo', hour12: false}));
Monday, October 5, 2026
Oct 5, 2026, 12:00 PM
10/5/2026, 21:00:00
Pass timeZone to format in any IANA zone without changing the Date. The JS Intl.DateTimeFormat Playground lets you try the options interactively.
const day = new Date(2026, 9, 31, 12);
console.log(new Date(day.getTime() + 24 * 3600e3).toString());
const dd = new Date(day);
dd.setDate(dd.getDate() + 1);
console.log(dd.toString());
Sun Nov 01 2026 11:00:00 GMT-0500 (Eastern Standard Time)
Sun Nov 01 2026 12:00:00 GMT-0500 (Eastern Standard Time)
Adding 24 hours of milliseconds crossed the November 1 clock change and landed at 11:00. setDate keeps the wall-clock time. Use milliseconds only for durations, and setDate or setMonth for calendar steps.
console.log(new Date(2026, 2, 0).getDate(), new Date(2026, 1, 0).getDate(), new Date(2024, 2, 0).getDate());
console.log(Math.round((new Date('2026-12-25') - new Date('2026-10-05')) / 864e5));
28 31 29
81
Day 0 of a month is the last day of the previous month, so new Date(2026, 2, 0) gives 28 for February 2026. Both strings above are date-only, so both are UTC and the difference is a clean multiple of 86,400,000.
const d = new Date(Date.UTC(2026, 9, 5, 12));
console.log(d.getTime(), Math.floor(d / 1000), +d);
console.log(JSON.stringify({d}));
1791201600000 1791201600 1791201600000
{"d":"2026-10-05T12:00:00.000Z"}
getTime() is milliseconds. Divide by 1000 and floor it for the seconds that most APIs use. Unix Timestamp Converter handles both units.
console.log(new Date('2026-10-05') < new Date('2026-10-06'));
console.log(new Date(0) == new Date(0), new Date(0).getTime() === new Date(0).getTime());
true
false true
Relational operators coerce to numbers, but and = compare object identity. Compare getTime() values for equality.
const ok = (y, m, d) => {
const x = new Date(y, m - 1, d);
return x.getFullYear() === y && x.getMonth() === m - 1 && x.getDate() === d;
};
console.log(ok(2026, 2, 28), ok(2026, 2, 30), ok(2024, 2, 29));
true false true
The constructor rolls impossible dates forward instead of failing, so build the date and read the parts back. If any part differs, the input was not a real date. This also handles leap years.
const s = new Date('2026-10-05T12:00:00Z');
console.log(s.toISOString().slice(0, 10));
2026-10-05
The first ten characters of toISOString() are the UTC calendar date. For the local calendar date, assemble it from getFullYear(), getMonth() + 1 and getDate() with padStart(2, '0').
new Date(2026, 10, 1) is November 1, not October 1. Days start at 1, and getDay() returns the weekday 0 to 6, not the day of the month.new Date('2026-10-05').getDate() returned 4, and toLocaleDateString('en-US') printed 10/4/2026. Format with timeZone: 'UTC' or build the date from parts.'2026-10-05T00:00:00' is a different instant on every machine. Server and browser then disagree. Send Z or an offset.new Date('05/10/2026') was read as May 10 in Node 22, not October 5. Formats outside the ISO profile are implementation-defined, so parse them yourself.'2026-02-30' into 2026-03-02T00:00:00.000Z instead of an invalid date. Do not rely on rollover from strings, and validate the parts first.setMonth(1) on January 31 gave Tue Mar 03 2026, because February has no 31st. Set the day to 1 first, or clamp it.new Date('nope') prints Invalid Date and getTime() is NaN. Only toISOString() throws, with RangeError: Invalid time value. Check with isNaN(date).new Date(2026, 2, 8, 2, 30) in New York, a skipped hour, came back as 03:30:00 GMT-0400. Use UTC for scheduling.JSON.stringify loses the type: a Date becomes an ISO string, and JSON.parse returns a string, not a Date. Convert back with new Date(value).dateStyle, timeStyle and timeZone options and see the outputtimeZone