我正在寻找最简单、最干净的方法将X个月添加到JavaScript日期中。
我宁愿不处理一年的滚动,也不愿意自己写函数。
有什么内置的东西可以做到这一点吗?
我正在寻找最简单、最干净的方法将X个月添加到JavaScript日期中。
我宁愿不处理一年的滚动,也不愿意自己写函数。
有什么内置的东西可以做到这一点吗?
当前回答
从上面的答案,唯一一个处理边缘情况(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')
);
其他回答
所有这些看起来都太复杂了,我猜这引发了一场关于增加“一个月”到底是什么意思的争论。是指30天吗?是从1号到1号的意思吗?从最后一天到最后一天?
如果是后者,那么加一个月到2月27日就会到3月27日,但加一个月到2月28日就会到3月31日(闰年除外,会到3月28日)。那么从3月30日减去一个月…2月27日吗?谁知道……
对于那些寻找简单解决方案的人来说,只需要增加几毫秒就可以了。
function getDatePlusDays(dt, days) {
return new Date(dt.getTime() + (days * 86400000));
}
or
Date.prototype.addDays = function(days) {
this = new Date(this.getTime() + (days * 86400000));
};
这适用于所有的边缘情况。newMonth的奇怪计算处理负月份输入。如果新的月份与预期的月份不匹配(比如31 Feb),它会将月份的日期设置为0,这意味着“上个月的结束”:
function dateAddCalendarMonths(date, months) {
monthSum = date.getMonth() + months;
newMonth = (12 + (monthSum % 12)) % 12;
newYear = date.getFullYear() + Math.floor(monthSum / 12);
newDate = new Date(newYear, newMonth, date.getDate());
return (newDate.getMonth() != newMonth)
? new Date(newDate.setDate(0))
: newDate;
}
最简单的解决方法是:
const todayDate = Date.now();
return new Date(todayDate + 1000 * 60 * 60 * 24 * 30* X);
其中X是我们想要增加的月份数。
考虑到这些答案中没有一个会在月份变化时解释当年的情况,你可以在下面找到我做的一个答案,它应该可以处理这个问题:
方法:
Date.prototype.addMonths = function (m) {
var d = new Date(this);
var years = Math.floor(m / 12);
var months = m - (years * 12);
if (years) d.setFullYear(d.getFullYear() + years);
if (months) d.setMonth(d.getMonth() + months);
return d;
}
用法:
return new Date().addMonths(2);
容易的,简单的
function addMonths(date, months) {date.setMonth(date.getMonth() + months); return date;};
使用它作为
alert(new Date().toLocaleString()); //will say today
alert(addMonths(new Date(),12).toLocaleString()); //will say next year, same day and month