How to Calculate Days Between Two Dates (Without Excel Tricks)
Calculating the number of days between two dates sounds simple, but every language handles it slightly differently — and the edge cases (DST, timezones, leap years) are the source of countless off-by-one bugs. Here's how to do it correctly in the tools you're likely using.
JavaScript
The cleanest approach is to parse both dates, subtract them, and convert milliseconds to days.
function daysBetween(date1, date2) {
const d1 = new Date(date1);
const d2 = new Date(date2);
const msPerDay = 1000 * 60 * 60 * 24;
return Math.abs(Math.round((d2 - d1) / msPerDay));
}
console.log(daysBetween("2024-01-01", "2024-12-31"));
// 365 (2024 is a leap year)
console.log(daysBetween("2025-03-01", "2026-03-01"));
// 365
Math.round() instead of Math.floor() handles the 1-hour edge case around DST transitions — without it, you'd occasionally get 364 instead of 365 for a 365-day range that crosses a DST boundary.
Using date-fns (recommended for production):
import { differenceInCalendarDays } from 'date-fns';
const days = differenceInCalendarDays(new Date('2024-12-31'), new Date('2024-01-01'));
console.log(days); // 365
differenceInCalendarDays counts calendar day boundaries crossed, which is usually what you want for things like "days since last login."
Python
from datetime import date
def days_between(date1: str, date2: str) -> int:
d1 = date.fromisoformat(date1)
d2 = date.fromisoformat(date2)
return abs((d2 - d1).days)
print(days_between("2024-01-01", "2024-12-31"))
# 365
print(days_between("2025-03-01", "2026-03-01"))
# 365
Python's datetime.date subtraction returns a timedelta object. The .days attribute gives the integer number of days — no DST issues because date objects have no timezone component.
For timezone-aware datetimes:
from datetime import datetime, timezone
def days_between_aware(dt1: str, dt2: str) -> int:
# ISO 8601 with timezone info
d1 = datetime.fromisoformat(dt1)
d2 = datetime.fromisoformat(dt2)
return abs((d2 - d1).days)
Excel
Excel stores dates as serial numbers (days since January 1, 1900), so subtraction is just arithmetic.
Simple subtraction:
=B1 - A1
If A1 is 2024-01-01 and B1 is 2024-12-31, this returns 365. Make sure the cell is formatted as a number, not a date — otherwise Excel displays the result as a date.
DAYS function (cleaner):
=DAYS(B1, A1)
DAYS(end_date, start_date) returns the number of days between them. Positive if end is after start, negative if before.
DATEDIF (legacy but widely used):
=DATEDIF(A1, B1, "D")
DATEDIF is an undocumented legacy function carried over from Lotus 1-2-3. It's reliable for day differences but the documentation in Excel is hidden. The "D" argument returns total days; "M" returns complete months; "Y" returns complete years.
Working days (excluding weekends)
// JavaScript
function workingDaysBetween(start, end) {
let count = 0;
const current = new Date(start);
const endDate = new Date(end);
while (current < endDate) {
const day = current.getDay();
if (day !== 0 && day !== 6) count++;
current.setDate(current.getDate() + 1);
}
return count;
}
# Python
from datetime import date, timedelta
def working_days_between(start: str, end: str) -> int:
d1, d2 = date.fromisoformat(start), date.fromisoformat(end)
count = 0
current = d1
while current < d2:
if current.weekday() < 5: # 0=Mon, 4=Fri
count += 1
current += timedelta(days=1)
return count
Excel:
=NETWORKDAYS(A1, B1)
NETWORKDAYS excludes weekends automatically and optionally accepts a range of holiday dates as a third argument.
Why date math is tricky
Daylight Saving Time — the day the clocks change has 23 or 25 hours. If you're subtracting timestamps (not date objects), 365 days can sometimes look like 364 days in milliseconds.
Timezones — new Date("2024-01-01") in JavaScript parses as UTC midnight. If your local timezone is UTC-5, that's actually December 31 locally. Always specify timezone explicitly or use UTC dates.
Leap years — 2024 has 366 days. A "1-year" range starting on January 1, 2024 has 366 days, not 365.
Using date-specific libraries (date-fns, dateutil, pandas) handles all of this correctly. The manual millisecond approach works but requires the Math.round() trick for DST safety.
Key takeaways
- JavaScript:
Math.round((d2 - d1) / 86400000)ordifferenceInCalendarDaysfrom date-fns. - Python:
(date2 - date1).days— no DST issues withdateobjects. - Excel:
=DAYS(B1, A1)or=DATEDIF(A1, B1, "D"). - For working days only:
NETWORKDAYSin Excel; loop withweekday() < 5in Python. - Use
Math.roundnotMath.floorin JavaScript to survive DST transitions.