Из ответов, приведенных выше, единственная, которая обрабатывает крайние случаи (bmpasini из библиотеки datejs), имеет проблему:
var date = new Date("03/31/2015");
var newDate = date.addMonths(1);
console.log(newDate);
// VM223:4 Thu Apr 30 2015 00:00:00 GMT+0200 (CEST)
хорошо, но:
newDate.toISOString()
//"2015-04-29T22:00:00.000Z"
хуже:
var date = new Date("01/01/2015");
var newDate = date.addMonths(3);
console.log(newDate);
//VM208:4 Wed Apr 01 2015 00:00:00 GMT+0200 (CEST)
newDate.toISOString()
//"2015-03-31T22:00:00.000Z"
Это происходит из-за того, что время не установлено, и поэтому возвращается к 00:00:00, что может привести к сбою предыдущего дня из-за изменений часового пояса или экономии времени или чего-то еще ...
Вот мое предлагаемое решение, которое не имеет этой проблемы, и, я думаю, более элегантно, поскольку оно не опирается на жестко заданные значения.
/**
* @param isoDate {string} in ISO 8601 format e.g. 2015-12-31
* @param numberMonths {number} e.g. 1, 2, 3...
* @returns {string} in ISO 8601 format e.g. 2015-12-31
*/
function addMonths (isoDate, numberMonths) {
var dateObject = new Date(isoDate),
day = dateObject.getDate(); // returns day of the month number
// avoid date calculation errors
dateObject.setHours(20);
// add months and set date to last day of the correct month
dateObject.setMonth(dateObject.getMonth() + numberMonths + 1, 0);
// set day number to min of either the original one or last day of month
dateObject.setDate(Math.min(day, dateObject.getDate()));
return dateObject.toISOString().split('T')[0];
};
Устройство успешно протестировано с:
function assertEqual(a,b) {
return a === b;
}
console.log(
assertEqual(addMonths('2015-01-01', 1), '2015-02-01'),
assertEqual(addMonths('2015-01-01', 2), '2015-03-01'),
assertEqual(addMonths('2015-01-01', 3), '2015-04-01'),
assertEqual(addMonths('2015-01-01', 4), '2015-05-01'),
assertEqual(addMonths('2015-01-15', 1), '2015-02-15'),
assertEqual(addMonths('2015-01-31', 1), '2015-02-28'),
assertEqual(addMonths('2016-01-31', 1), '2016-02-29'),
assertEqual(addMonths('2015-01-01', 11), '2015-12-01'),
assertEqual(addMonths('2015-01-01', 12), '2016-01-01'),
assertEqual(addMonths('2015-01-01', 24), '2017-01-01'),
assertEqual(addMonths('2015-02-28', 12), '2016-02-28'),
assertEqual(addMonths('2015-03-01', 12), '2016-03-01'),
assertEqual(addMonths('2016-02-29', 12), '2017-02-28')
);