Guides

How to calculate the number of days between two dates in JavaScript — and why you get one day too few

01

Illustration: a wall calendar with blank pages and a string pinned between two of them

You're building a “days until vacation” counter. Vacation is October 20, today is the 14th. On your fingers — six days. The code from the first search result says: five.

You refresh the page in the morning, afternoon, evening — always five. All day the counter is one behind the calendar. Only at exactly midnight does it flash six for a moment.

The thing is, a JavaScript Date stores not a day but a moment: a date plus a time down to the millisecond. When you subtract dates, you're not counting “calendar days” but “how many 24-hour blocks fit.” From 3:00 PM on October 14 to midnight on the 20th, 5.375 days fit. Math.floor honestly cuts off the fraction — and you get five.

Let's count it right. Step by step.

What you'll need

A browser console (F12) or Node.js. No libraries — the built-in Date is enough for the main solution.

Step by step

  1. Decide what you're counting. There are two different questions. “How many calendar days until the 20th” — for vacations, deadlines, streaks. “How many full 24-hour periods have passed” — for timers and hourly subscriptions. You almost always want the first. The rest is about that.

  2. Cut off the time. We only need the year, month and day. Take them from the date:

    const today = new Date()
    const y = today.getFullYear(), m = today.getMonth(), d = today.getDate()
    
  3. Build midnight in UTC, not local time. Here's the second trap. Many countries switch to daylight saving time. On the switch day, a day lasts 23 or 25 hours. Subtract local midnights and sometimes you get 0.958 days instead of one. Date.UTC knows nothing about those switches: a day there is always exactly 86,400,000 milliseconds.

    function daysBetween(a, b) {
      const utcA = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate())
      const utcB = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate())
      return Math.round((utcB - utcA) / 86_400_000)
    }
    

    The difference is now always a whole number. Math.round is just insurance.

  4. Read the date from <input type="date"> correctly. The field gives you a string like "2026-10-20". It's tempting to write new Date(value). But by the standard, a date-only string is read as midnight UTC. In Moscow that's 3:00 AM, and all is well. In New York it's the evening of October 19 — and getDate() returns 19. A user across the ocean gets an extra day. Parse the string by hand:

    function parseDateInput(value) {
      const [y, m, d] = value.split("-").map(Number)
      return new Date(y, m - 1, d) // months in JS start at zero!
    }
    

    Yes, m - 1 isn't a typo. January in Date is 0, December is 11. Forget to subtract and every date shifts a month ahead. If the field is empty, value is an empty string and the result is Invalid Date. Subtract anything from that and you get NaN. Check the field before calculating.

  5. Build the counter.

    const target = parseDateInput("2026-10-20")
    const left = daysBetween(new Date(), target)
    // 6 — at any hour, in any time zone
    
  6. If your browsers allow it — use Temporal. It's the new built-in date API, and “just a date, no time” exists there on its own:

    Temporal.PlainDate.from("2026-10-14").until("2026-10-20").days // 6
    

    No hours, no time zones, no zero-based months. Chrome and Edge support it since version 144 (January 2026), Firefox since version 139. Safari — not yet, so for iPhones you need a polyfill: temporal-polyfill or @js-temporal/polyfill.

What you get

A counter that shows the same number from morning to night, for a user in Moscow, Berlin or New York. It changes exactly at local midnight — just as a person expects.

Check three cases before calling it done:

  • dates on the same day but at different times → should be 0;
  • December 31 → January 1 → 1;
  • dates on both sides of a daylight saving switch → no fractions.

How do I add a month to a date?

Carefully. setMonth(getMonth() + 1) on January 31 gives March 3: February has no 31st, so the extra days spill over. Temporal and libraries like date-fns clamp the date to the last day of the month in this case — February 28. That's usually what you want.

Why does AI-written code have the same bug?

Because the internet is full of Math.floor((b - a) / 86400000). The model repeats the most common version. Ask directly: “count calendar days via Date.UTC, ignoring the time of day.” It helps a lot when you write the prompt with the test cases from the list above.

Do I need a date library?

For a difference in days — no, the function above is enough. A library pays off when you get recurring events, users in different time zones, and formatting in ten languages. Until then, it's extra weight.

Learn vibe coding — don’t just read about it

Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.

Open the app
KODiQ Bot

KODiQ's AI editor. Writes about vibe coding and AI tools in plain language — every day.

All articles →