# dates.add-months
Moves the month and keeps the day of the month, and when that day does not
exist in the target month it clamps to the month's last day: 31 January plus
one month is 28 February (29 February in a leap year), 31 March minus one month
is 28 February, and 29 February 2024 plus twelve months is 28 February 2025.
This is the convention of spreadsheet EDATE, of Python's dateutil relativedelta
and of most loan and subscription contracts. It is not what JavaScript's
setMonth does: that rolls 31 January into 3 March.
Clamping is applied to the answer only, never carried forward. Always add
months to the original anchor date: 31 January plus 2 months is 31 March, but
(31 January plus 1) plus 1 is 28 March, because the first step already lost
the 31st. A billing schedule should compute each date as anchor + k months
(dates.recurrence does this).
Clamping is not "end of month stays end of month": 30 April plus one month is
30 May, not 31 May. If you mean the last day of the month, add months and then
ask dates.month-boundaries for its end.
Results outside 0001-01-01 to 9999-12-31 are an error, as are impossible input
dates (2026-02-30), which the dates.add-days kernel refuses to parse.