Sitemap

Understanding JavaScript Date class

4 min readJul 22, 2026

--

Press enter or click to view image in full size
javascript date class

Dates seem simple until you actually need to work with one. Then suddenly you’re comparing timestamps, formatting things for different locales, and running into a “day 6 instead of day 7” bug that turns out to be a single 0-indexed month messing everything up.

Background

Date is a built-in JavaScript class for working with dates and times. Under the hood, it stores everything as milliseconds since January 1, 1970 a reference point known as the Unix Epoch.

Dates are everywhere order timestamps, delivery windows, user date-of-birth, session expiry, log entries. Most real projects lean on a helper library like day.js or date-fns on top of this, because raw Date formatting is clunky. But that native class is the foundation everything else is built on, so it's worth actually understanding rather than skipping straight to the library.

Get Vrishali’s stories in your inbox

Join Medium for free to get updates from this writer.

And here’s the one thing to burn into memory before anything else: month is 0-indexed : January is 0, December is 11.(same for weeks : Sunday is 0, Saturday is 6) Remember this.

Making a Date object

There are four ways I keep running into:

// 1. Current date and time
const now = new Date();
console.log(now); // 2025-07-06T10:30:00.000Z (your current time)

// 2. From a date string
const d1 = new Date("2025-01-15");
console.log(d1); // 2025-01-15T00:00:00.000Z

// 3. From year, month, day (month is 0-indexed!)
const d2 = new Date(2025, 0, 15); // Jan 15, 2025
console.log(d2);

// 4. From milliseconds since epoch
const d3 = new Date(0);
console.log(d3); // 1970-01-01T00:00:00.000Z

Option 3 is where the 0-indexing thing actually bites 0 means January, not "invalid" or some placeholder. I still double-check this one every time.

Pulling pieces out of a date

Once you’ve got a Date object, these get you the individual parts:

const now = new Date("2025-07-06T10:30:45");
console.log(now.getFullYear()); // 2025
console.log(now.getMonth()); // 6 ← July (0-indexed!)
console.log(now.getDate()); // 6 ← day of month
console.log(now.getDay()); // 0 ← day of week (0=Sun, 6=Sat)
console.log(now.getHours()); // 10
console.log(now.getMinutes()); // 30
console.log(now.getSeconds()); // 45
console.log(now.getTime()); // milliseconds since epoch

getMonth() returning 6 for July same gotcha, again. And don't mix up getDay() with getDate(): one's the day of the week, the other's the day of the month. I mixed these up more than once before it stuck.

Changing pieces of a date

You can mutate a Date directly too:

const d = new Date("2025-07-06");
d.setFullYear(2026);
d.setMonth(11); // December
d.setDate(25); // 25th
console.log(d); // 2026-12-25

Making a date actually readable

A raw Date object isn't something you'd want to show a user. These methods turn it into something presentable:

const d = new Date("2025-07-06");
console.log(d.toDateString());
// Sun Jul 06 2025
console.log(d.toLocaleDateString());
// 7/6/2025 (format depends on your system locale)
console.log(d.toLocaleDateString("en-IN"));
// 06/07/2025 ← Indian format
console.log(d.toLocaleString());
// 7/6/2025, 12:00:00 AM (date + time)
console.log(d.toISOString());
// 2025-07-06T00:00:00.000Z ← used in APIs, databases

Out of all of these, toISOString() is the one I use most it's the standard format APIs and databases expect, so it shows up the second you start touching backend data.

Date.now() : when you just need a timestamp

No need to build a full object if all you want is “what time is it right now, in milliseconds”:

console.log(Date.now()); // 1751234567890  (some big number)

I mostly reach for this to measure how long something takes to run:

const start = Date.now();
// some code running...
for (let i = 0; i < 1000000; i++) {}
const end = Date.now();
console.log(`Time taken: ${end - start} ms`); // Time taken: 4 ms

Comparing two dates

Since Date objects are really just numbers underneath (milliseconds since the epoch), you can subtract one from another:

const d1 = new Date("2025-01-01");
const d2 = new Date("2025-07-06");
const diff = d2 - d1; // milliseconds
const days = diff / (1000 * 60 * 60 * 24);
console.log(`Difference: ${days} days`); // Difference: 186 days

That 1000 * 60 * 60 * 24 looks intimidating the first time, but it's just unit conversion, one step at a time — ms to seconds, seconds to minutes, minutes to hours, hours to days. Write it once and it sticks.

Putting it together an age calculator

Here’s where it all comes together in something you’d actually build:

function calculateAge(birthDateStr) {
const birth = new Date(birthDateStr);
const today = new Date();
let age = today.getFullYear() - birth.getFullYear();
// Check if birthday has passed this year
const monthDiff = today.getMonth() - birth.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--;
}
return age;
}
console.log(calculateAge("2003-11-20")); // 21

The part worth actually paying attention to is that if check it's not just subtracting years, it's checking whether the birthday has happened yet this year and knocking off a year if not. That extra bit of logic is what separates "technically runs" from "actually correct," and I'd rather understand it than just copy it.

The bits I keep having to look up

  • getFullYear() — the 4-digit year
  • getMonth() — 0 to 11, remember January is 0
  • getDate() — day of the month, 1 to 31
  • getDay() — day of the week, 0 (Sunday) to 6
  • getTime() / Date.now() — milliseconds since the epoch
  • toISOString() — the API/database-friendly format
  • toLocaleDateString() — whatever format makes sense for your locale

If none of this sticks the first time, that’s fine that’s basically what this list is for.

So that’s Date in a nutshell small on the surface, but it's the kind of thing that quietly powers half of every real app you'll build. The epoch and the 0-indexed month are really the only two ideas doing all the work here; everything else is just methods built on top of them.

Has the month 0-indexing bug ever gotten you? I’d genuinely like to hear your worst Date-related debugging story in the comments.

--

--

Vrishali
Vrishali

Written by Vrishali

FULL STACK DEVELOPER ➡ I share my learnings in tech/life