Functional Weave
Code in Python

health.age-in-months@1.0.1

impl/python.py

1,373 bytes · the Python 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.

from .dates_add_days import add_days, days_between, parse_iso_date  ← from dates.add-days ^1.0.0 · built alongside by fune
from .dates_add_months import add_months  ← from dates.add-months ^1.0.0 · built alongside by fune
from .health_age_in_months_types import AgeInMonths


def _month_anniversary(birth_date: str, birth_day: int, months: int) -> str:
    """The day the given number of months is completed. add_months 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."""
    shifted = add_months(birth_date, months)
    return add_days(shifted, 1) if parse_iso_date(shifted).day < birth_day else shifted


def age_in_months(birth_date: str, on_date: str) -> AgeInMonths:
    """Completed months and remaining days from ``birth_date`` to ``on_date``."""
    birth = parse_iso_date(birth_date)
    on = parse_iso_date(on_date)
    if on_date < birth_date:
        raise ValueError("onDate %s is before birthDate %s" % (on_date, birth_date))
    months = (on.year - birth.year) * 12 + (on.month - birth.month)
    anniversary = _month_anniversary(birth_date, birth.day, months)
    if anniversary > on_date:
        months -= 1
        anniversary = _month_anniversary(birth_date, birth.day, months)
    return AgeInMonths(months=months, days=days_between(anniversary, on_date), total_days=days_between(birth_date, on_date))