Dates show up everywhere: due dates, timestamps, countdowns, "posted 3 days ago." JavaScript handles them with the built-in Date object. It is powerful but has a few famous traps, and this section walks through all of them.
Under the hood, a Date is a single number: the milliseconds since midnight, January 1, 1970 (UTC). That moment is called the Unix epoch. Everything else, like months, weekdays, and time zones, is calculated from that number.
console.log(new Date(0).toISOString()); // "1970-01-01T00:00:00.000Z"
console.log(Date.now()); // e.g. 1790913600000 (right now, in ms)
// 1. Right now
const now = new Date();
// 2. From parts: year, month, day, hours, minutes, seconds, ms
const meeting = new Date(2026, 9, 2, 14, 30);
// 3. From a date string
const launch = new Date("2026-10-02T14:30");
// 4. From a millisecond timestamp
const stamp = new Date(1790913600000);
console.log(meeting.toString());
In all, there are 9 ways to call new Date(). The "from parts" form accepts anywhere from 2 to 7 numbers, always in the same order, and any parts you leave off default to their lowest value:
new Date() // now
new Date(dateString) // from a string
new Date(year, month) // the 1st of that month, midnight
new Date(year, month, day)
new Date(year, month, day, hours)
new Date(year, month, day, hours, minutes)
new Date(year, month, day, hours, minutes, seconds)
new Date(year, month, day, hours, minutes, seconds, ms)
new Date(milliseconds) // from a timestamp
A Date is a snapshot, not a running clock. const now = new Date(); records the moment that line ran. Five minutes later, now still holds the old time. To get the current time again, create a new Date.
When you build a date from parts, January is 0 and December is 11. Days of the month start at 1 as normal. This catches everyone at least once:
new Date(2026, 9, 2) // October 2 (month 9 = October)
new Date(2026, 10, 2) // November 2, not October!
new Date(2026, 11, 25) // December 25
A string with just a date, like "2026-10-02", is treated as midnight in UTC, not your local time. In the Americas, that is still the previous evening:
console.log(new Date("2026-10-02").toString());
Add a time to make it local:
new Date("2026-10-02T00:00") // midnight Oct 2, local time
new Date(2026, 9, 2) // also midnight Oct 2, local time
const a = new Date(2026, 9, 2);
const b = new Date(2026, 9, 2);
console.log(typeof a); // "object"
console.log(a === b); // false (two different objects)
console.log(a.getTime() === b.getTime()); // true (same moment in time)
To compare two dates for equality, compare their getTime() numbers. The < and > operators do work directly on dates.
You cannot leave out the month. With only one number, JavaScript does not read it as a year; it reads it as a millisecond timestamp:
console.log(new Date(2018).toISOString()); // not the year 2018!
console.log(new Date(2018, 0).toDateString()); // Jan 1, 2018
2018 milliseconds is just over two seconds past the epoch. Negative timestamps work too, counting backward from 1970: new Date(-100000000000) is in 1966.
console.log(new Date(99, 11, 24).toDateString());
console.log(new Date(9, 11, 24).toDateString());
Years 0 to 99 are treated as 1900 to 1999, a leftover from the last century. Always write the full four-digit year.
A month above 11 or a day past the end of the month is not an error. The extra spills into the next month or year:
console.log(new Date(2018, 15, 24).toDateString()); // month 15 = 3 months into 2019
console.log(new Date(2018, 5, 35).toDateString()); // June 35 = July 5
This is annoying when it hides a typo, but very handy for date math. JS Date Set uses it to add days and months.
Subtracting one date from another gives the difference in milliseconds. Divide to get days:
const today = new Date(2026, 9, 2);
const christmas = new Date(2026, 11, 25);
const MS_PER_DAY = 1000 * 60 * 60 * 24;
const daysLeft = Math.round((christmas - today) / MS_PER_DAY);
console.log(`${daysLeft} days until Christmas`);
Math.round, not Math.floor, when converting to days. A daylight saving change in between makes one day 23 or 25 hours long, which would otherwise knock the answer off by one.
A string JavaScript cannot understand does not throw an error. It produces a Date that is broken:
const bad = new Date("next Tuesday");
console.log(bad.toString()); // "Invalid Date"
console.log(Number.isNaN(bad.getTime())); // true: the way to test for it
| Date Formats | Which strings to feed in, and how to display dates nicely |
| Date Get | Reading the year, month, weekday, hour... |
| Date Set | Changing parts of a date, and adding days or months |
Which creates March 5, 2027?
new Date(2027, 3, 5)new Date(2027, 2, 5)new Date(2027, 5, 3)new Date("2027-03-05") (in the Americas)What does this log?
const a = new Date(2026, 0, 1);
const b = new Date(2026, 0, 1);
console.log(a === b, a.getTime() === b.getTime());
false true. Dates are objects, so === checks whether they are the same object. Compare their getTime() numbers to check for the same moment.What does new Date(2030) create?
new Date(2030, 0).new Date("2026-10-02") with new Date("2026-10-02T00:00")