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) };
}