Functional Weave
Code in Rust

dates.add-months@1.0.0

impl/typescript.ts

1,135 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 { daysInMonth, formatIsoDate, parseIsoDate } from "./dates_add_days.ts";  ← from dates.add-days ^1.0.0 · built alongside by fune

/**
 * Add whole months, keeping the day of the month and clamping it to the last
 * day of the target month when that month is shorter (31 Jan + 1 = 28/29 Feb).
 *
 * The clamp is applied to the result only. Callers stepping through a schedule
 * must add k months to the original anchor, not 1 month k times, or the 31st
 * decays to the 28th after February.
 */
export function addMonths(iso: string, months: number): string {
  if (!Number.isInteger(months)) {
    throw new TypeError(`months must be an integer, received ${months}`);
  }
  const date = parseIsoDate(iso);
  // Count months from year 0 so the year and month fall out of one division.
  const total = date.year * 12 + (date.month - 1) + months;
  const year = Math.floor(total / 12);
  const month = total - year * 12 + 1;
  if (year < 1 || year > 9999) {
    throw new RangeError(`"${iso}" plus ${months} months is outside the supported range 0001-01-01 to 9999-12-31`);
  }
  const day = Math.min(date.day, daysInMonth(year, month));
  return formatIsoDate({ year, month, day });
}