›The Shack ›Developer Tips ›How to Calculate Date Differences in JavaScript

How to Calculate Date Differences in JavaScript (and Online)

Back to All Posts

Date arithmetic is one of those things that looks simple until you're actually doing it. Subtracting two dates in JavaScript gives you milliseconds, not days. Months have different lengths. Daylight saving time shifts clocks by an hour twice a year, which can add or remove 3,600,000 milliseconds from a day. Leap years add a day to February. Timezones mean "today" is a different date depending on where you are.

This guide covers how to calculate date differences correctly in JavaScript, the gotchas that catch developers out, and when to just use the free Date Difference Calculator on DevToolShack instead of writing code.

The Basic Approach: Millisecond Subtraction

JavaScript's Date object stores time internally as milliseconds since the Unix epoch (January 1, 1970 UTC). When you subtract two Date objects, JavaScript coerces them to their numeric values (milliseconds) and returns the difference in milliseconds.

const start = new Date('2026-01-01');
const end   = new Date('2026-07-01');

const diffMs   = end - start;                    // milliseconds
const diffDays = diffMs / (1000 * 60 * 60 * 24); // convert to days

console.log(diffDays); // 181

This works well for getting the total number of days between two dates, as long as both dates are in the same timezone — which brings us to the first big gotcha.

The Timezone Problem

When you write new Date('2026-01-01'), JavaScript parses that ISO 8601 date-only string as UTC midnight. But when you write new Date('2026-01-01T00:00:00') (with a time but no timezone), JavaScript treats it as local time. That inconsistency bites developers constantly.

// Parsed as UTC midnight — safe for date arithmetic
const d1 = new Date('2026-06-15');

// Parsed as LOCAL midnight — may shift the date depending on timezone
const d2 = new Date('2026-06-15T00:00:00');

// These may differ by hours depending on the user's timezone offset

If you're calculating differences between calendar dates (not timestamps), always use the date-only ISO format (YYYY-MM-DD) or explicitly append Z to force UTC parsing.

For anything involving timestamps across timezones, the Timezone Converter on DevToolShack helps you visualize what a timestamp looks like in multiple zones simultaneously, which is far easier than doing the offset math by hand.

Daylight Saving Time

DST is the reason you can't always divide milliseconds by 86,400,000 to get days. On the day clocks spring forward, a day is 23 hours long. On the day clocks fall back, a day is 25 hours long. If your date range spans a DST transition in a timezone that observes it, a naive millisecond-to-days conversion will be off by one.

// More robust: round the result to handle DST transitions
const diffMs   = end - start;
const diffDays = Math.round(diffMs / (1000 * 60 * 60 * 24));

Using Math.round() instead of integer division handles the one-hour shift gracefully. For most calendar-date use cases this is sufficient. If you need precision to the minute across DST transitions, use a library like Temporal (the modern JavaScript date API) or date-fns.

Getting Days, Months, and Years Separately

Total days is straightforward. Breaking a difference into years, months, and days is harder because months have different lengths. You can't just divide days by 30. The correct approach is to walk the calendar:

function dateDiff(start, end) {
  let years  = end.getFullYear() - start.getFullYear();
  let months = end.getMonth()    - start.getMonth();
  let days   = end.getDate()     - start.getDate();

  if (days < 0) {
    months--;
    // Get the number of days in the previous month
    const prevMonth = new Date(end.getFullYear(), end.getMonth(), 0);
    days += prevMonth.getDate();
  }

  if (months < 0) {
    years--;
    months += 12;
  }

  return { years, months, days };
}

const result = dateDiff(new Date('2024-11-15'), new Date('2026-07-05'));
// { years: 1, months: 7, days: 20 }

This is the kind of logic that's easy to get wrong in edge cases — end of month, end of year, February in a leap year. For quick calculations without writing code, the Date Difference Calculator handles all of this and returns the result broken down into years, months, weeks, and days.

Working With Unix Timestamps

Many APIs return dates as Unix timestamps (seconds since epoch) rather than formatted strings. JavaScript's Date works in milliseconds, so you need to multiply by 1000 when constructing from a Unix timestamp:

const unixTimestamp = 1751760000; // seconds
const date = new Date(unixTimestamp * 1000);

// Get current time as Unix timestamp
const nowUnix = Math.floor(Date.now() / 1000);

For converting, inspecting, and doing arithmetic with Unix timestamps directly, the Unix Timestamp Converter is faster than constructing Date objects. For a deeper explanation of what Unix timestamps are and the common pitfalls (milliseconds vs seconds, the year 2038 problem, JWT exp and iat fields), see Unix Timestamps Explained: What They Are and How to Convert Them.

Formatting the Difference as a Human-Readable String

Once you have a difference in milliseconds or days, you often need to present it as "3 days ago" or "in 2 hours." The modern way to do this in JavaScript is Intl.RelativeTimeFormat, which handles pluralization and localization automatically:

const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

rtf.format(-1, 'day');    // "yesterday"
rtf.format(-3, 'day');    // "3 days ago"
rtf.format(1,  'month');  // "next month"
rtf.format(-2, 'week');   // "2 weeks ago"

To choose the right unit automatically based on the magnitude of the difference:

function timeAgo(date) {
  const rtf   = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
  const diffMs = date - Date.now();
  const diffSec = Math.round(diffMs / 1000);
  const diffMin = Math.round(diffSec / 60);
  const diffHr  = Math.round(diffMin / 60);
  const diffDay = Math.round(diffHr  / 24);

  if (Math.abs(diffSec) < 60)  return rtf.format(diffSec, 'second');
  if (Math.abs(diffMin) < 60)  return rtf.format(diffMin, 'minute');
  if (Math.abs(diffHr)  < 24)  return rtf.format(diffHr,  'hour');
  return rtf.format(diffDay, 'day');
}

Using the Temporal API

The Temporal API is a modern replacement for JavaScript's notoriously awkward Date object. It has widespread browser support as of 2025 and handles timezones, calendar arithmetic, and DST correctly without third-party libraries. For date-only arithmetic, Temporal.PlainDate avoids timezone issues entirely:

const start  = Temporal.PlainDate.from('2026-01-01');
const end    = Temporal.PlainDate.from('2026-07-05');
const result = start.until(end);

console.log(result.days);   // total days
// Or broken down:
const full = start.until(end, { largestUnit: 'year' });
console.log(`${full.years}y ${full.months}m ${full.days}d`);

Temporal.PlainDate is date-only with no timezone, which is exactly what you want for calendar date arithmetic. Temporal.ZonedDateTime handles the full timezone-aware case correctly, including DST.

For quick calculations, skip the code entirely. The Date Difference Calculator on DevToolShack gives you the difference in years, months, weeks, and days instantly. Useful for deadlines, age calculations, contract durations, and any situation where you just need the number without writing a function.

Common Use Cases and the Right Approach

Use case Recommended approach
Total days between two calendar dates Millisecond subtraction with Math.round()
Years/months/days broken down Temporal.PlainDate.until() or the date diff function above
Relative time strings ("3 days ago") Intl.RelativeTimeFormat
Timestamp arithmetic across timezones Temporal.ZonedDateTime or date-fns with timezone plugin
Quick one-off calculation Date Difference Calculator