Age Calculator in JavaScript: Calculate Age from Date of Birth
8 min read

Age Calculator in JavaScript: Calculate Age from Date of Birth

Age calculator in JavaScript is a useful browser and web-development exercise because it combines date parsing, calendar logic, form validation, and user-friendly output. A reliable calculator should determine completed years from a date of birth and a reference date instead of simply dividing elapsed milliseconds by a fixed number of days.

This guide shows how to calculate age from DOB in JavaScript, calculate age on a fixed date, return years-months-days, validate date input, calculate total days, handle leap years, and build a reusable browser form. It also explains why JavaScript’s older Date API needs careful handling for date-only values and briefly covers Temporal.PlainDate, which MDN currently documents as limited-availability.

For related implementations, see our age calculator in Python, age calculator in PHP, and age calculator in Java guides.

JavaScript logo for an age calculator in JavaScript tutorial
Source: Wikimedia Commons, JavaScript Corp.; CC BY-SA 4.0.

Quick answer: calculate completed age in JavaScript

The simplest dependable approach with the widely supported Date API is to calculate the year difference and subtract one when the birthday has not occurred yet in the reference year.

function calculateAge(birthDate, referenceDate = new Date()) {
  if (birthDate > referenceDate) {
    throw new Error("Birth date cannot be in the future.");
  }

  let age = referenceDate.getFullYear() - birthDate.getFullYear();

  const birthdayThisYear = new Date(
    referenceDate.getFullYear(),
    birthDate.getMonth(),
    birthDate.getDate()
  );

  if (birthdayThisYear > referenceDate) {
    age--;
  }

  return age;
}

const dob = new Date(1995, 7, 21); // August is month 7
console.log(calculateAge(dob));

In JavaScript’s Date constructor, month numbers are zero-based when numeric components are supplied: January is 0 and December is 11. That is an important source of off-by-one errors.

Why subtracting years or dividing milliseconds is not enough

A calculation such as referenceDate.getFullYear() - birthDate.getFullYear() is only correct once the birthday has occurred. Likewise, dividing the millisecond difference by 365 days ignores leap years and the calendar position of the birthday.

Birth dateReference dateCompleted ageWhy
21 Aug 199520 Aug 202630Birthday is tomorrow
21 Aug 199521 Aug 202631Birthday is today
21 Aug 199522 Aug 202631Birthday has passed

Parse a date of birth safely

For a web form, keep the input as a date-only value until you need to perform the calculation. An HTML input type="date" gives the browser a structured date control, while its value is normally exposed as an ISO-style YYYY-MM-DD string.

<input type="date" id="dob" name="dob" required>

const value = document.querySelector("#dob").value;

if (!value) {
  throw new Error("Date of birth is required.");
}

const [year, month, day] = value.split("-").map(Number);
const birthDate = new Date(year, month - 1, day);

Constructing the date from numeric year, month, and day makes the zero-based month rule explicit. For more complex applications, validate that the constructed date still contains the requested calendar components before accepting it.

Calculate age on a fixed date

Eligibility and historical calculations often use a stated cutoff date instead of today. Pass the reference date into the function so the result is reproducible and easy to test.

const dob = new Date(2001, 8, 25);
const cutoff = new Date(2026, 8, 21);

console.log(calculateAge(dob, cutoff));

Making the reference date an argument also prevents a hidden dependency on the system clock. The same function can therefore be used for current-age displays, archived records, eligibility checks, and unit tests.

JavaScript source code example for an age calculator tutorial
Source: Wikimedia Commons, Romainhk; CC BY-SA 3.0.

Calculate exact age in years, months and days

If the interface needs a calendar-style result such as “31 years, 1 month, 4 days,” calculate the components by moving forward from the birth date rather than converting the whole duration to fixed-length units.

function calculateExactAge(birthDate, referenceDate = new Date()) {
  if (birthDate > referenceDate) {
    throw new Error("Birth date cannot be in the future.");
  }

  let years = referenceDate.getFullYear() - birthDate.getFullYear();
  let anniversary = new Date(
    referenceDate.getFullYear(),
    birthDate.getMonth(),
    birthDate.getDate()
  );

  if (anniversary > referenceDate) {
    years--;
    anniversary = new Date(
      referenceDate.getFullYear() - 1,
      birthDate.getMonth(),
      birthDate.getDate()
    );
  }

  let months = 0;
  let cursor = new Date(anniversary);

  while (true) {
    const next = new Date(
      cursor.getFullYear(),
      cursor.getMonth() + 1,
      cursor.getDate()
    );

    if (next > referenceDate) {
      break;
    }

    cursor = next;
    months++;
  }

  const days = Math.floor(
    (referenceDate - cursor) / (1000 * 60 * 60 * 24)
  );

  return { years, months, days };
}

This style is more involved because calendar months do not all contain the same number of days. For production code, test month-end and leap-day cases carefully rather than assuming every month can be represented by a fixed number of milliseconds.

Calculate total elapsed days

If the requirement is total elapsed days rather than birthday-based age, subtract the timestamps and convert milliseconds to days. This is a different measurement from completed age.

const millisecondsPerDay = 1000 * 60 * 60 * 24;

function totalDaysBetween(start, end) {
  return Math.floor((end - start) / millisecondsPerDay);
}

const days = totalDaysBetween(
  new Date(2000, 4, 10),
  new Date(2026, 8, 21)
);

console.log(days);

For date-only applications, be careful with local time and daylight-saving transitions: a calendar day is not always best represented as exactly 24 elapsed local hours. When the distinction matters, use a date-oriented API or normalize the calculation deliberately.

Build a browser age-calculator form

The following small example connects a DOB field to an age result. It validates missing and future dates before displaying the answer.

<label for="dob">Date of birth</label>
<input type="date" id="dob" required>
<button type="button" id="calculate">Calculate age</button>
<p id="result" aria-live="polite"></p>

<script>
function calculateAge(birthDate, referenceDate = new Date()) {
  if (birthDate > referenceDate) {
    throw new Error("Birth date cannot be in the future.");
  }

  let age = referenceDate.getFullYear() - birthDate.getFullYear();
  const birthday = new Date(
    referenceDate.getFullYear(),
    birthDate.getMonth(),
    birthDate.getDate()
  );

  if (birthday > referenceDate) {
    age--;
  }

  return age;
}

document.querySelector("#calculate").addEventListener("click", () => {
  const value = document.querySelector("#dob").value;
  const result = document.querySelector("#result");

  if (!value) {
    result.textContent = "Please enter your date of birth.";
    return;
  }

  const [year, month, day] = value.split("-").map(Number);
  const dob = new Date(year, month - 1, day);

  try {
    result.textContent = "Age: " + calculateAge(dob) + " years";
  } catch (error) {
    result.textContent = error.message;
  }
});
</script>

JavaScript Date versus Temporal.PlainDate

JavaScript’s traditional Date object represents a date/time value and has long been used for browser calculations. For a date of birth, however, the conceptual value is usually a calendar date without a time zone. MDN documents Temporal.PlainDate specifically as a date without a time or time zone, which matches that concept closely. MDN currently marks Temporal as limited availability, so browser support should be checked before using it directly in a production site.

ApproachUse caseImportant point
DateWidely supported browser codeWatch local time, time zones and zero-based months
Temporal.PlainDateDate-only calendar logicDesigned for dates without time or time zone; availability is limited
HTML input type="date"User DOB entryProvides a browser date control and ISO-style value
// Where Temporal is available:
const dob = Temporal.PlainDate.from("1995-08-21");
const today = Temporal.Now.plainDateISO();

console.log(dob.toString());
console.log(today.toString());

Temporal’s date-only model can reduce some of the ambiguity that comes from treating a birthday as a timestamp. Before shipping it, check current browser compatibility or use an appropriate compatibility strategy.

Leap years and February 29

A February 29 birthday needs an explicit policy when the reference year is not a leap year. Do not silently assume that the birthday should always be treated as February 28 or March 1. If the result affects an official eligibility rule, follow the rule specified by the relevant authority or application requirement.

RequirementRecommended JavaScript design
Completed ageCompare the birthday with the reference date
Fixed-date agePass the cutoff date into the function
Total daysMeasure elapsed duration separately
Years-months-daysUse calendar-aware increments and boundary tests
Feb 29 policyDefine the non-leap-year convention explicitly

Common JavaScript age-calculator mistakes

  • Subtracting years only: this overstates age before the birthday.
  • Dividing milliseconds by 365 days: this ignores leap years and birthday boundaries.
  • Forgetting zero-based months: numeric Date constructors use 0 for January.
  • Parsing date-only strings without thinking about time zones: understand how your chosen parsing form is interpreted before comparing dates.
  • Using today’s date inside every helper: pass a reference date when reproducibility matters.
  • Accepting future DOBs: validate the relationship between birth and reference dates.
  • Ignoring month-end cases: test dates such as the 28th, 29th, 30th and 31st across different months.

Testing the age calculation

Test the day before a birthday, the birthday itself, the day after, future DOBs, leap-day birthdays, and month-end dates. Passing the reference date explicitly makes these tests deterministic.

console.assert(
  calculateAge(
    new Date(2000, 4, 10),
    new Date(2026, 4, 9)
  ) === 25
);

console.assert(
  calculateAge(
    new Date(2000, 4, 10),
    new Date(2026, 4, 10)
  ) === 26
);

console.assert(
  calculateAge(
    new Date(2000, 4, 10),
    new Date(2026, 4, 11)
  ) === 26
);

Frequently asked questions

Can JavaScript calculate age without a library?

Yes. A completed-age calculator can be implemented with the built-in Date API. More specialized date-only logic can use Temporal where it is available.

What is the simplest JavaScript age formula?

Subtract the birth year from the reference year and subtract one when the birthday has not yet occurred in that reference year.

Can I calculate age on a past date?

Yes. Pass the historical or eligibility cutoff date as the second argument instead of using the current date.

Why should I not divide milliseconds by 365 days?

Because birthday-based age follows calendar anniversaries, while a millisecond calculation measures elapsed duration. Leap years and calendar boundaries make the two measurements different.

Is Temporal.PlainDate available in every browser?

No. MDN currently marks Temporal and Temporal.PlainDate as limited availability, so check browser compatibility before relying on it without a compatibility strategy.

Final takeaway

A dependable age calculator in JavaScript should treat age as a calendar calculation, not simply as elapsed milliseconds. Use a validated DOB, compare the birthday with a clearly defined reference date, keep total-day calculations separate from completed age, and test leap years and month boundaries. For newer date-only code, Temporal.PlainDate models the concept well, but current browser availability must be considered.

Sources