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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2706125/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:33:43  来源:igfitidea点击:

JavaScript function to add X months to a date

javascriptdate

提问by Chad

I'm looking for the easiest, cleanest way to add X months to a JavaScript date.

我正在寻找将 X 个月添加到 JavaScript 日期的最简单、最简洁的方法。

I'd rather not handle the rolling over of the yearor have to write my own function.

我宁愿不处理年份的滚动或必须编写自己的函数

Is there something built in that can do this?

是否有内置的东西可以做到这一点?

回答by Chad

The following function adds months to a date in JavaScript (source). It takes into account year roll-overs and varying month lengths:

以下函数将月份添加到 JavaScript 中的日期 ( source)。它考虑了年份滚动和不同的月份长度:

function addMonths(date, months) {
    var d = date.getDate();
    date.setMonth(date.getMonth() + +months);
    if (date.getDate() != d) {
      date.setDate(0);
    }
    return date;
}

// Add 12 months to 29 Feb 2016 -> 28 Feb 2017
console.log(addMonths(new Date(2016,1,29),12).toString());

// Subtract 1 month from 1 Jan 2017 -> 1 Dec 2016
console.log(addMonths(new Date(2017,0,1),-1).toString());

// Subtract 2 months from 31 Jan 2017 -> 30 Nov 2016
console.log(addMonths(new Date(2017,0,31),-2).toString());

// Add 2 months to 31 Dec 2016 -> 28 Feb 2017
console.log(addMonths(new Date(2016,11,31),2).toString());

The above solution covers the edge case of moving from a month with a greater number of days than the destination month. eg.

上述解决方案涵盖了从天数多于目标月份的月份移动的边缘情况。例如。

  • Add twelve months to February 29th 2020 (should be February 28th 2021)
  • Add one month to August 31st 2020 (should be September 30th 2020)
  • 将 2020 年 2 月 29 日加上十二个月(应该是 2021 年 2 月 28 日)
  • 2020年8月31日加一个月(应该是2020年9月30日)

If the day of the month changes when applying setMonth, then we know we have overflowed into the following month due to a difference in month length. In this case, we use setDate(0)to move back to the last day of the previous month.

如果申请时月份的日期发生变化setMonth,那么我们知道由于月份长度的差异,我们已经溢出到下个月。在这种情况下,我们使用setDate(0)返回到上个月的最后一天。

Note: this version of this answer replaces an earlier version (below) that did not gracefully handle different month lengths.

注意:这个答案的这个版本替换了早期版本(下面),它不能很好地处理不同的月份长度。

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);

回答by anre

I'm using moment.jslibrary for date-time manipulations. Sample code to add one month:

我正在使用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');

回答by aMarCruz

This function handles edge cases and is fast:

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

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
}

test:

测试:

> 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"

Update for non-UTC dates:(by A.Hatchkins)

更新非 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
}

test:

测试:

> 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"

回答by Control Freak

Considering none of these answers will account for the current year when the month changes, you can find one I made below which should handle it:

考虑到这些答案都不会在月份发生变化时考虑当前年份,您可以在下面找到我制作的应该处理它的答案:

The method:

方法:

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;
}

Usage:

用法:

return new Date().addMonths(2);

回答by Miquel

Taken from @bmpsiniand @Jazaretresponses, but not extending prototypes: using plain functions (Why is extending native objects a bad practice?):

取自@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;
}

Use it:

用它:

var nextMonth = addMonths(new Date(), 1);

回答by pansay

From the answers above, the only one that handles the edge cases (bmpasini's from datejs library) has an issue:

从上面的答案来看,唯一一个处理边缘情况的(来自 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)

ok, but:

好的但是:

newDate.toISOString()
//"2015-04-29T22:00:00.000Z"

worse :

更差 :

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"

This is due to the time not being set, thus reverting to 00:00:00, which then can glitch to previous day due to timezone or time-saving changes or whatever...

这是由于未设置时间,因此恢复到 00:00:00,然后由于时区或节省时间的更改或其他原因,可能会出现故障到前一天......

Here's my proposed solution, which does not have that problem, and is also, I think, more elegant in that it does not rely on hard-coded values.

这是我提出的解决方案,它没有这个问题,而且我认为它更优雅,因为它不依赖于硬编码值。

/**
* @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];
};

Unit tested successfully with:

单元测试成功:

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')
);

回答by dr.dimitru

Simple solution: 2678400000is 31 day in milliseconds

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

var oneMonthFromNow = new Date((+new Date) + 2678400000);

Update:

更新:

Use this data to build our own function:

使用这些数据构建我们自己的函数:

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

回答by Sampath Dilhan

As most of the answers highlighted, we could use setMonth()method together with getMonth()method to add specific number of months to a given date.

正如大多数答案所强调的那样,我们可以将setMonth()方法与getMonth()方法一起使用,以将特定月数添加到给定日期。

Example: (as mentioned by @ChadD in his answer. )

示例:(正如@ChadD 在他的回答中提到的。)

var x = 12; //or whatever offset 
var CurrentDate = new Date();
CurrentDate.setMonth(CurrentDate.getMonth() + x);
var x = 12; //or whatever offset 
var CurrentDate = new Date();
CurrentDate.setMonth(CurrentDate.getMonth() + x);

But we should carefully use this solution as we will get trouble with edge cases.

但是我们应该谨慎使用这个解决方案,因为我们会遇到边缘情况的问题。

To handle edge cases, answer which is given in following link is helpful.

https://stackoverflow.com/a/13633692/3668866

为了处理边缘情况,以下链接中给出的答案很有帮助。

https://stackoverflow.com/a/13633692/3668866

回答by David Ragazzi

I wrote this alternative solution which works fine to me. It is useful when you wish calculate the end of a contract. For example, start=2016-01-15, months=6, end=2016-7-14 (i.e. last day - 1):

我写了这个对我来说很好用的替代解决方案。当您希望计算合同的结束时间时,它很有用。例如,start=2016-01-15,months=6,end=2016-7-14(即最后一天 - 1):

<script>
function daysInMonth(year, month)
{
    return new Date(year, month + 1, 0).getDate();
}

function addMonths(date, months)
{
    var target_month = date.getMonth() + months;
    var year = date.getFullYear() + parseInt(target_month / 12);
    var month = target_month % 12;
    var day = date.getDate();
    var last_day = daysInMonth(year, month);
    if (day > last_day)
    {
        day = last_day;
    }
    var new_date = new Date(year, month, day);
    return new_date;
}

var endDate = addMonths(startDate, months);
</script>

Examples:

例子:

addMonths(new Date("2016-01-01"), 1); // 2016-01-31
addMonths(new Date("2016-01-01"), 2); // 2016-02-29 (2016 is a leap year)
addMonths(new Date("2016-01-01"), 13); // 2017-01-31
addMonths(new Date("2016-01-01"), 14); // 2017-02-28

回答by iamjt

Just to add on to the accepted answer and the comments.

只是添加到已接受的答案和评论中。

var x = 12; //or whatever offset
var CurrentDate = new Date();

//For the very rare cases like the end of a month
//eg. May 30th - 3 months will give you March instead of February
var date = CurrentDate.getDate();
CurrentDate.setDate(1);
CurrentDate.setMonth(CurrentDate.getMonth()+X);
CurrentDate.setDate(date);