JavaScript函数添加X个月的日期

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

我宁愿不处理年度的周转或不得不写自己的函数

有什么内置的东西可以做到这一点吗?

323493 次浏览

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

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

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

  • 增加12个月至2020年2月29日(应该是2021年2月28日)
  • 增加一个月至2020年8月31日(应该是2020年9月30日)

如果在应用setMonth时,该月的日期发生了变化,则我们知道由于月份长度的差异,已经溢出到下一个月。在本例中,我们使用setDate(0)返回到前一个月的最后一天。

注意:这个答案的这个版本取代了之前的版本(下面),之前的版本没有优雅地处理不同的月份长度。

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);
d = new Date();


alert(d.getMonth()+1);

月份有一个基于0的指数,它应该警报(4),这是5(五月);

下面是一个如何根据日期输入(membershipssignup_date) +通过表单字段添加的月份(membershipsmonths)计算未来日期的示例。

membershipsmonths字段的默认值为0

触发链接(可以是附加到成员资格术语字段的onchange事件):

<a href="#" onclick="calculateMshipExp()"; return false;">Calculate Expiry Date</a>


function calculateMshipExp() {


var calcval = null;


var start_date = document.getElementById("membershipssignup_date").value;
var term = document.getElementById("membershipsmonths").value;  // Is text value


var set_start = start_date.split('/');


var day = set_start[0];
var month = (set_start[1] - 1);  // January is 0 so August (8th month) is 7
var year = set_start[2];
var datetime = new Date(year, month, day);
var newmonth = (month + parseInt(term));  // Must convert term to integer
var newdate = datetime.setMonth(newmonth);


newdate = new Date(newdate);
//alert(newdate);


day = newdate.getDate();
month = newdate.getMonth() + 1;
year = newdate.getFullYear();


// This is British date format. See below for US.
calcval = (((day <= 9) ? "0" + day : day) + "/" + ((month <= 9) ? "0" + month : month) + "/" + year);


// mm/dd/yyyy
calcval = (((month <= 9) ? "0" + month : month) + "/" + ((day <= 9) ? "0" + day : day) + "/" + year);


// Displays the new date in a <span id="memexp">[Date]</span> // Note: Must contain a value to replace eg. [Date]
document.getElementById("memexp").firstChild.data = calcval;


// Stores the new date in a <input type="hidden" id="membershipsexpiry_date" value="" name="membershipsexpiry_date"> for submission to database table
document.getElementById("membershipsexpiry_date").value = calcval;
}
var a=new Date();
a.setDate(a.getDate()+5);

如上所述的方法,可以将month添加到Date函数中。

addDateMonate : function( pDatum, pAnzahlMonate )
{
if ( pDatum === undefined )
{
return undefined;
}


if ( pAnzahlMonate === undefined )
{
return pDatum;
}


var vv = new Date();


var jahr = pDatum.getFullYear();
var monat = pDatum.getMonth() + 1;
var tag = pDatum.getDate();


var add_monate_total = Math.abs( Number( pAnzahlMonate ) );


var add_jahre = Number( Math.floor( add_monate_total / 12.0 ) );
var add_monate_rest = Number( add_monate_total - ( add_jahre * 12.0 ) );


if ( Number( pAnzahlMonate ) > 0 )
{
jahr += add_jahre;
monat += add_monate_rest;


if ( monat > 12 )
{
jahr += 1;
monat -= 12;
}
}
else if ( Number( pAnzahlMonate ) < 0 )
{
jahr -= add_jahre;
monat -= add_monate_rest;


if ( monat <= 0 )
{
jahr = jahr - 1;
monat = 12 + monat;
}
}


if ( ( Number( monat ) === 2 ) && ( Number( tag ) === 29 ) )
{
if ( ( ( Number( jahr ) % 400 ) === 0 ) || ( ( Number( jahr ) % 100 ) > 0 ) && ( ( Number( jahr ) % 4 ) === 0 ) )
{
tag = 29;
}
else
{
tag = 28;
}
}


return new Date( jahr, monat - 1, tag );
}




testAddMonate : function( pDatum , pAnzahlMonate )
{
var datum_js = fkDatum.getDateAusTTMMJJJJ( pDatum );
var ergebnis = fkDatum.addDateMonate( datum_js, pAnzahlMonate );


app.log( "addDateMonate( \"" + pDatum + "\", " + pAnzahlMonate + " ) = \"" + fkDatum.getStringAusDate( ergebnis ) + "\"" );
},




test1 : function()
{
app.testAddMonate( "15.06.2010",    10 );
app.testAddMonate( "15.06.2010",   -10 );
app.testAddMonate( "15.06.2010",    37 );
app.testAddMonate( "15.06.2010",   -37 );
app.testAddMonate( "15.06.2010",  1234 );
app.testAddMonate( "15.06.2010", -1234 );
app.testAddMonate( "15.06.2010",  5620 );
app.testAddMonate( "15.06.2010", -5120 );


}

只是在已接受的答案和评论上加上一点。

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

从所给出的许多复杂而丑陋的答案可以看出,日期和时间对于使用任何语言的程序员来说都是一场噩梦。我的方法是将日期和“delta t”值转换为Epoch Time(以毫秒为单位),执行任何算术运算,然后转换回“人类时间”。

// Given a number of days, return a Date object
//   that many days in the future.
function getFutureDate( days ) {


// Convert 'days' to milliseconds
var millies = 1000 * 60 * 60 * 24 * days;


// Get the current date/time
var todaysDate = new Date();


// Get 'todaysDate' as Epoch Time, then add 'days' number of mSecs to it
var futureMillies = todaysDate.getTime() + millies;


// Use the Epoch time of the targeted future date to create
//   a new Date object, and then return it.
return new Date( futureMillies );
}


// Use case: get a Date that's 60 days from now.
var twoMonthsOut = getFutureDate( 60 );

这是为一个略有不同的用例编写的,但您应该能够轻松地将其用于相关任务。

编辑:完整源代码在这里!

有时有用的创建日期由一个操作符,如在BIRT参数

我在1个月前用:

new Date(new Date().setMonth(new Date().getMonth()-1));

正如大多数答案突出显示的那样,我们可以使用setMonth ()方法和getMonth ()方法来为给定的日期添加特定的月份数。

例子:(@ChadD在他的回答中提到。)

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

但是我们应该小心地使用这个解决方案,因为我们会在边界情况下遇到麻烦。

要处理边缘情况,下面链接中给出的答案是有帮助的。

https://stackoverflow.com/a/13633692/3668866 < / p >

所有这些看起来都太复杂了,我猜这引发了一场关于增加“一个月”到底是什么意思的争论。是指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));
}

Date.prototype.addDays = function(days) {
this = new Date(this.getTime() + (days * 86400000));
};
我正在为日期-时间操作使用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');

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

简单的解决方法:2678400000是31天,单位是毫秒

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

更新:

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

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

这个函数处理边缘情况,并且速度很快:

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
}

测试:

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

非utc日期更新: (by 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
}

测试:

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

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

使用它:

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

考虑到这些答案中没有一个会在月份变化时解释当年的情况,你可以在下面找到我做的一个答案,它应该可以处理这个问题:

方法:

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

我写了另一种解决方案,对我来说很好。当您希望计算合同的结束时,它很有用。例如,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>

例子:

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

这适用于所有的边缘情况。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;
}

我改变了一点接受的答案,以保持原始日期完整,因为我认为它应该在这样的函数中。

function addMonths(date, months) {
let newDate = new Date(date);
var day = newDate.getDate();
newDate.setMonth(newDate.getMonth() + +months);
if (newDate.getDate() != day)
newDate.setDate(0);
return newDate;
}

最简单的解决方法是:

const todayDate = Date.now();
return new Date(todayDate + 1000 * 60 * 60 * 24 * 30* X);

其中X是我们想要添加的月份数。

容易的,简单的

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

在typescript中寻找一些东西?

export const addMonths = (inputDate: Date | string, monthsToAdd: number): Date => {
const date = new Date(inputDate);
if (!monthsToAdd) {
return date;
}
const dayOfMonth = date.getDate();
const endOfDesiredMonth = new Date(date.getTime());
endOfDesiredMonth.setMonth(date.getMonth() + monthsToAdd + 1, 0);
const daysInMonth = endOfDesiredMonth.getDate();
if (dayOfMonth >= daysInMonth) {
return endOfDesiredMonth;
} else {
date.setFullYear(endOfDesiredMonth.getFullYear(), endOfDesiredMonth.getMonth(), dayOfMonth);
return date;
}
}