Skip to content
Topic 21 of 21
Theory

Dates and time

Why it matters

Dates are in almost every application: the time of a chat message, a delivery date, "posted 3 days ago", a calendar, a countdown to the end of a sale, the user's age. JavaScript has the built-in Date object for this. It has a few traps that break programs for beginners — and for experienced developers too. Let's go through them.

Creating a date

const now = new Date();                       // the current moment
const newYear = new Date(2026, 0, 1);         // January 1, 2026, 00:00 local time
const iso = new Date("2026-11-02");           // from a string in ISO format
const fromMs = new Date(0);                   // from a timestamp

console.log(newYear.getFullYear(), newYear.getMonth(), newYear.getDate());

Output:

2026 0 1

The main trap: months are counted from zero. January is 0, February is 1, December is 11. But days of the month start from one, as usual. That's why you write getMonth() + 1 when displaying the month.

Timestamps

Inside, Date stores one number — how many milliseconds have passed since January 1, 1970, Greenwich time (UTC). This number is called a timestamp:

console.log(new Date(0).toISOString());
console.log(new Date("2026-01-01T00:00:00Z").getTime());

Output:

1970-01-01T00:00:00.000Z
1767225600000

The current timestamp is Date.now(). It's used to measure time:

const start = Date.now();
for (let i = 0; i < 1e6; i++) {}
console.log("The loop took less than a second: " + (Date.now() - start < 1000));

Output:

The loop took less than a second: true

Date parts

Get What it returns
getFullYear() the year, for example 2026
getMonth() the month 0–11
getDate() the day of the month 1–31
getDay() the day of the week 0–6, where 0 is Sunday
getHours(), getMinutes(), getSeconds() the time
getTime() the timestamp
const d = new Date(2026, 10, 2, 14, 5);   // November 2, 2026, 14:05
const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
console.log(days[d.getDay()]);
console.log(`${d.getHours()}:${String(d.getMinutes()).padStart(2, "0")}`);

Output:

Mon
14:05

For each get… there is a set…: setFullYear, setMonth, setDate, setHours…

A date corrects itself

If you give a "non-existent" day, Date carries the extra over to the next month. It's not an error but a handy tool:

console.log(new Date(2026, 1, 30).getDate(), new Date(2026, 1, 30).getMonth());   // February 30?

const d = new Date(2026, 11, 30);
d.setDate(d.getDate() + 5);                 // plus 5 days
console.log(d.getFullYear(), d.getMonth(), d.getDate());

const lastDay = new Date(2024, 2, 0);       // "zeroth" of March = the last day of February
console.log(lastDay.getDate());

Output:

2 2
2027 0 4
29

February 30 became March 2, December 30 + 5 days is January 4 of the next year, and day 0 gives the last day of the previous month (February 2024 had 29 days).

The difference between dates

If you subtract one date from another, you get the difference in milliseconds. To convert it to days, divide by the number of milliseconds in a day: 1000 * 60 * 60 * 24 = 86400000:

const start = new Date("2026-09-01");
const end = new Date("2026-12-31");
const days = Math.round((end - start) / 86400000);
console.log("Days until the end of the year: " + days);

Output:

Days until the end of the year: 121

Math.round is needed because of daylight saving time in some countries: then a day can have 23 or 25 hours.

ISO and time zones

The most reliable format for a date in a string is ISO 8601: 2026-11-02T14:05:00Z. The letter Z means "UTC time". Servers and JSON use it:

const d = new Date(Date.UTC(2026, 10, 2, 9, 30));
console.log(d.toISOString());
console.log(JSON.stringify({ created: d }));

Output:

2026-11-02T09:30:00.000Z
{"created":"2026-11-02T09:30:00.000Z"}

The same moment looks different in different countries: 09:30 UTC is 14:30 in Dushanbe (UTC+5) and 09:30 in London in winter (UTC+0). So:

  • getHours(), getDate() and the others return the time in the computer's time zone;
  • getUTCHours(), getUTCDate()… — in UTC;
  • new Date("2026-11-02") (date only) is parsed as midnight UTC, while new Date(2026, 10, 2) is midnight local time.

The rule: store and send dates in UTC (an ISO string or a timestamp), and convert to local time only when showing them to the user.

Nice output for people

toLocaleDateString and toLocaleTimeString format a date by the rules of a language:

const d = new Date(Date.UTC(2026, 10, 2, 9, 30));
console.log(d.toLocaleDateString("en-US", { timeZone: "UTC" }));
console.log(d.toLocaleDateString("en-GB", { timeZone: "UTC" }));
console.log(d.toLocaleDateString("en-US", { day: "numeric", month: "long", year: "numeric", timeZone: "UTC" }));

Output:

11/2/2026
02/11/2026
November 2, 2026

Without timeZone the user's time zone is used — on websites that's usually exactly what you need.

How it works inside

Date is a wrapper around one timestamp number. All the get… methods compute the year, month and hours from this number taking the time zone into account, and set… recalculate the timestamp. That's why two dates are compared by their timestamps: a.getTime() === b.getTime(). An ordinary a === b compares objects and gives false even for identical dates, but < and > work because they turn dates into numbers.

The Date object is mutable: setDate changes it in place. If a date came into a function from outside and you need to shift it, make a copy first: const copy = new Date(date);.

For complex work with dates (time zones, "in 2 months", calendars) projects often use the date-fns or dayjs libraries, and newer versions of JavaScript are getting the built-in Temporal.

Common mistakes

  1. Months from zero. new Date(2026, 1, 1) is February 1. When displaying — getMonth() + 1.
  2. getDay instead of getDate. getDay is the day of the week, getDate is the day of the month.
  3. Age by dividing by 365. Leap years cause an error of a day or two. Compare years, months and days.
  4. Comparing with ===. Compare getTime().
  5. Changed someone else's date. setDate changes the object — make a copy.
  6. A string in an unclear format. Different browsers understand new Date("02.11.2026") differently. Use ISO 2026-11-02 or numbers.

Cheat sheet

What How
Now new Date(), timestamp — Date.now()
A specific date new Date(2026, 10, 2) (months from zero!)
From ISO new Date("2026-11-02T14:05:00Z")
Parts getFullYear(), getMonth() + 1, getDate(), getDay()
Shift d.setDate(d.getDate() + 7)
Difference in days Math.round((b - a) / 86400000)
To ISO d.toISOString()
For people d.toLocaleDateString("en-US")
Two digits String(n).padStart(2, "0")

How many days

Easy+10 XP

Write a function daysBetween(from, to). Both dates are strings in the YYYY-MM-DD format. Return how many days there are from from to to (if to is earlier, the number is negative).

daysBetween("2026-01-01", "2026-01-31")   → 30
daysBetween("2026-03-01", "2026-02-01")   → -28

Connect the connector to solve tasks

Task code runs on your own computer — faster and more reliable than in the browser. This needs the free CodeWithMe connector app. You only connect it once.

Looking for the connector on this computer…

  1. 1
    Download the connector for your system (Windows, macOS or Linux).Download the connectorOn the download page pick the file with your system in its name, e.g. windows-amd64.
  2. 2Run it and choose a folder for your solutions. It will install Python and Node.js there by itself when needed.
  3. 3
    Enter below the 6-digit code shown in the connector window (“Code for CodeWithMe”). If the browser asks about local network access — allow it.

The connector is open source (on GitHub), works only on your computer and runs code only after you enter the pairing code.