Calculate Exact Age In Years

Compute exact years, months and days between a birth date and a reference date using UTC date-only arithmetic.

JavascriptForm Validation

Code

snippet
export function calculateAge(birthDate, asOf = new Date()) {
  const birth = toDateOnly(birthDate);
  const reference = toDateOnly(asOf);
  if (birth > reference) throw new RangeError("birthDate must not be in the future");
  let totalMonths = (reference.getUTCFullYear() - birth.getUTCFullYear()) * 12
    + (reference.getUTCMonth() - birth.getUTCMonth());
  if (reference.getUTCDate() < birth.getUTCDate()) totalMonths -= 1;
  const anchor = addMonthsClamped(birth, totalMonths);
  const days = Math.floor((reference.getTime() - anchor.getTime()) / 86400000);
  return {
    years: Math.floor(totalMonths / 12),
    months: totalMonths % 12,
    days,
    totalMonths,
    totalDays: Math.floor((reference.getTime() - birth.getTime()) / 86400000),
  };
}

function addMonthsClamped(date, months) {
  const target = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + months, 1));
  const lastDay = new Date(Date.UTC(target.getUTCFullYear(), target.getUTCMonth() + 1, 0)).getUTCDate();
  target.setUTCDate(Math.min(date.getUTCDate(), lastDay));
  return target;
}

function toDateOnly(value) {
  if (value instanceof Date) {
    if (Number.isNaN(value.getTime())) throw new RangeError("invalid date");
    return new Date(Date.UTC(value.getUTCFullYear(), value.getUTCMonth(), value.getUTCDate()));
  }
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(String(value));
  if (!match) throw new TypeError("expected YYYY-MM-DD or Date");
  const year = Number(match[1]);
  const month = Number(match[2]) - 1;
  const day = Number(match[3]);
  const date = new Date(Date.UTC(year, month, day));
  if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month || date.getUTCDate() !== day) {
    throw new RangeError("invalid calendar date");
  }
  return date;
}