Add Months With End-Of-Month Clamping
Add or subtract months in UTC while clamping the day to the target month's last day, avoiding date rollover bugs.
Code
export function daysInMonth(year: number, monthIndex: number): number {
if (!Number.isInteger(year) || !Number.isInteger(monthIndex)) {
throw new TypeError("year and monthIndex must be integers");
}
return new Date(Date.UTC(year, monthIndex + 1, 0)).getUTCDate();
}
// Add months with end-of-month clamping.
export function addMonthsClamped(date: Date, months: number): Date {
if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
throw new RangeError("date must be a valid Date");
}
if (!Number.isInteger(months)) throw new TypeError("months must be an integer");
const target = new Date(Date.UTC(
date.getUTCFullYear(),
date.getUTCMonth() + months,
1,
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds(),
date.getUTCMilliseconds(),
));
const day = Math.min(date.getUTCDate(), daysInMonth(target.getUTCFullYear(), target.getUTCMonth()));
target.setUTCDate(day);
return target;
}
export function addYearsClamped(date: Date, years: number): Date {
if (!Number.isInteger(years)) throw new TypeError("years must be an integer");
return addMonthsClamped(date, years * 12);
}Report a problem with this exampleOpens a pre-filled issue on GitHub.