Functional Weave
Code in Rust

health.age-in-months@1.0.1

impl/typescript.ts

1,389 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { addDays, daysBetween, parseIsoDate } from "./dates_add_days.ts";  ← from dates.add-days ^1.0.0 · built alongside by fune
import { addMonths } from "./dates_add_months.ts";  ← from dates.add-months ^1.0.0 · built alongside by fune
import { type AgeInMonths } from "./health_age_in_months_types.ts";

/**
 * The day the given number of months is completed. addMonths clamps 31 January
 * + 1 month to 28 February; a clamped day has not yet reached the birth day, so
 * the month completes the day after it (1 March), the same rule dates.age uses
 * for a 29 February birthday.
 */
function monthAnniversary(birthDate: string, birthDay: number, months: number): string {
  const shifted = addMonths(birthDate, months);
  return parseIsoDate(shifted).day < birthDay ? addDays(shifted, 1) : shifted;
}

/** Completed months and remaining days from birthDate to onDate. */
export function ageInMonths(birthDate: string, onDate: string): AgeInMonths {
  const birth = parseIsoDate(birthDate);
  const on = parseIsoDate(onDate);
  if (onDate < birthDate) {
    throw new RangeError(`onDate ${onDate} is before birthDate ${birthDate}`);
  }
  let months = (on.year - birth.year) * 12 + (on.month - birth.month);
  let anniversary = monthAnniversary(birthDate, birth.day, months);
  if (anniversary > onDate) {
    months -= 1;
    anniversary = monthAnniversary(birthDate, birth.day, months);
  }
  return { months, days: daysBetween(anniversary, onDate), totalDays: daysBetween(birthDate, onDate) };
}