How to calculate the number of days between two dates in JavaScript — and why you get one day too few
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
-
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.
-
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() -
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.UTCknows 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.roundis just insurance. -
Read the date from
<input type="date">correctly. The field gives you a string like"2026-10-20". It's tempting to writenew 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 — andgetDate()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 - 1isn't a typo. January inDateis 0, December is 11. Forget to subtract and every date shifts a month ahead. If the field is empty,valueis an empty string and the result isInvalid Date. Subtract anything from that and you get NaN. Check the field before calculating. -
Build the counter.
const target = parseDateInput("2026-10-20") const left = daysBetween(new Date(), target) // 6 — at any hour, in any time zone -
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 // 6No 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-polyfillor@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.
Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.




