用于将X月添加到日期的JavaScript函数

Cha*_*adD 192 javascript date

我正在寻找将X个月添加到JavaScript日期的最简单,最干净的方法.

我宁愿不处理今年的滚动或者必须编写我自己的功能.

有内置的东西能做到吗?

Cha*_*adD 257

我认为应该这样做:

var x = 12; //or whatever offset
var CurrentDate = new Date();
console.log("Current date:", CurrentDate);
CurrentDate.setMonth(CurrentDate.getMonth() + x);
console.log("Date after " + x + " months:", CurrentDate);
Run Code Online (Sandbox Code Playgroud)

我相信它应该自动处理递增到适当的年份并修改到适当的月份.

试试吧

  • 小心 - 这不适用于边缘情况,例如添加到大多数月份的第31天.例如,使用此方法的2011年10月31日+ 1个月是使用Javascript的标准Date对象的2011年12月1日. (125认同)
  • 有一个尊重月末的`addMonths`函数[here](http://stackoverflow.com/questions/12793045/adding-2-months-to-an-end-date-in-php-javascript)(例如`2012-01-31 + 1个月= 2012-02-29`等等). (13认同)
  • 好抓,有点儿.我很惊讶我没有看到.请注意,T-SQL选择DATEADD(月,1,'2011-10-31')会产生'2011-11-30',这对我来说是合理的.我得到了10张选票,得分不好.凉.:-) (6认同)
  • 只需添加以设置每月的第一个日期:today.setHours(0,0,0,0); today.setDate(1); (3认同)
  • 同时观察闰年 - 在闰年中将2年增加到2月29日将会给您带来不可预测的结果,具体取决于您使用的语言(作为一般答案).这就是2012年将Microsoft Azure云平台淘汰了几个小时的原因 (2认同)
  • @Mick它是一个[一元加](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus),它相当于“Number(months)” (2认同)

anr*_*nre 55

我正在使用moment.js库进行日期时间操作.添加一个月的示例代码:

var startDate = new Date(...);
var endDateMoment = moment(startDate); // moment(...) can also be used to parse dates in string format
endDateMoment.add(1, 'months');
Run Code Online (Sandbox Code Playgroud)

  • 为了您自己的理智,请使用moment.js. (10认同)
  • 绝对同意@garry:使用moment.js. (3认同)
  • 我同意这是最干净的方法,但问题是“有什么*内置*可以做到这一点?” Moment 将页面大小增加了数十 Kb (2认同)

aMa*_*ruz 24

此函数处理边缘情况并且速度很快:

function addMonthsUTC (date, count) {
  if (date && count) {
    var m, d = (date = new Date(+date)).getUTCDate()

    date.setUTCMonth(date.getUTCMonth() + count, 1)
    m = date.getUTCMonth()
    date.setUTCDate(d)
    if (date.getUTCMonth() !== m) date.setUTCDate(0)
  }
  return date
}
Run Code Online (Sandbox Code Playgroud)

测试:

> d = new Date('2016-01-31T00:00:00Z');
Sat Jan 30 2016 18:00:00 GMT-0600 (CST)
> d = addMonthsUTC(d, 1);
Sun Feb 28 2016 18:00:00 GMT-0600 (CST)
> d = addMonthsUTC(d, 1);
Mon Mar 28 2016 18:00:00 GMT-0600 (CST)
> d.toISOString()
"2016-03-29T00:00:00.000Z"
Run Code Online (Sandbox Code Playgroud)

非UTC日期的更新:(由A.Hatchkins提供)

function addMonths (date, count) {
  if (date && count) {
    var m, d = (date = new Date(+date)).getDate()

    date.setMonth(date.getMonth() + count, 1)
    m = date.getMonth()
    date.setDate(d)
    if (date.getMonth() !== m) date.setDate(0)
  }
  return date
}
Run Code Online (Sandbox Code Playgroud)

测试:

> d = new Date(2016,0,31);
Sun Jan 31 2016 00:00:00 GMT-0600 (CST)
> d = addMonths(d, 1);
Mon Feb 29 2016 00:00:00 GMT-0600 (CST)
> d = addMonths(d, 1);
Tue Mar 29 2016 00:00:00 GMT-0600 (CST)
> d.toISOString()
"2016-03-29T06:00:00.000Z"
Run Code Online (Sandbox Code Playgroud)

  • 另一个问题是它既修改原始日期又返回修改后的值。也许将它添加到日期原型或在函数中为更改的日期使用局部变量是有意义的? (2认同)

Con*_*eak 14

考虑到这些答案中的任何一个都不会占当月的变化,你可以在下面找到我应该处理的答案:

方法:

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;
}
Run Code Online (Sandbox Code Playgroud)

用法:

return new Date().addMonths(2);
Run Code Online (Sandbox Code Playgroud)


Miq*_*uel 8

取自@bmpsini@Jazaret响应,但不扩展原型:使用普通函数(为什么扩展本机对象是一种不好的做法?):

function isLeapYear(year) { 
    return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); 
}

function getDaysInMonth(year, month) {
    return [31, (isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
}

function addMonths(date, value) {
    var d = new Date(date),
        n = date.getDate();
    d.setDate(1);
    d.setMonth(d.getMonth() + value);
    d.setDate(Math.min(n, getDaysInMonth(d.getFullYear(), d.getMonth())));
    return d;
}
Run Code Online (Sandbox Code Playgroud)

用它:

var nextMonth = addMonths(new Date(), 1);
Run Code Online (Sandbox Code Playgroud)


pan*_*say 5

从上面的答案来看,唯一一个处理边缘情况的(来自 datejs 库的 bmpasini)有一个问题:

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)
Run Code Online (Sandbox Code Playgroud)

好的但是:

newDate.toISOString()
//"2015-04-29T22:00:00.000Z"
Run Code Online (Sandbox Code Playgroud)

更差 :

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"
Run Code Online (Sandbox Code Playgroud)

这是由于没有设置时间,因此恢复到 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];
};
Run Code Online (Sandbox Code Playgroud)

单元测试成功:

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')
);
Run Code Online (Sandbox Code Playgroud)


dr.*_*tru 5

简单的解决方案:2678400000以毫秒为单位的31天

var oneMonthFromNow = new Date((+new Date) + 2678400000);
Run Code Online (Sandbox Code Playgroud)

更新:

使用此数据构建我们自己的功能:

  • 2678400000 -31天
  • 2592000000 - 30天
  • 2505600000 -29天
  • 2419200000 -28天

  • 有些月份没有31天 (8认同)
  • 我猜想人们正在寻找的正是这种功能,它会自动考虑数月之内的工作日。 (2认同)
  • 这个答案不适应夏令时,其中并非所有的日子都是 24 小时(或 8.64e7 毫秒)长。 (2认同)