日付にXか月を追加するJavaScript関数


209

私はJavaScriptの日付にXか月を追加する最も簡単でクリーンな方法を探しています。

私はむしろないと思い転がり年以上のを扱うか、しなければならない自分自身の関数を書きます

これを行うことができる組み込みのものはありますか?


4
次のように、日付のプロトタイプオブジェクトにメソッドを追加してみてください。---------------Date.prototype.addMonth = function(n){return new Date(this.setMonth(this.getMonth( )+ n)); };
Moises Hidalgo

1
@ kr37、対象月に今日の日数がない場合、Moises Hidalgoの回答は正しく機能しません。bmpasiniの回答もこれを処理します
Alexandru Severin

ここでの答えはあまり良くありません。より良い答えは、JavaScriptで日付に月を追加することです。
RobG

回答:


277

次の関数は、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());

上記の解決策は、移動先の月よりも日数が多い月から移動するという極端なケースをカバーしています。例えば。

  • 2020年2月29日に12か月を追加します(2021年2月28日である必要があります)
  • 2020年8月31日に1か月追加します(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);

130
注意-これは、ほとんどの月の31日目を追加するなど、エッジケースでは機能しません。たとえば、このメソッドを使用した2011年10月31日+ 1か月は、JavaScriptの標準の日付オブジェクトを使用した2011年12月1日です。
TAD

6
良いキャッチ、少し。見なかったのには驚きました。T-SQL select DATEADD(month、1、 '2011-10-31')は '2011-11-30'を生成することに注意してください。これは私には合理的です。私は悪い答えで10票を獲得しました。涼しい。:-)
チャド

2
また、うるう年にも注意してください。うるう年の2月29日に1年を加えると、(一般的な回答として)使用している言語によっては予測できない結果が生じます。これが、2012年にMicrosoft Azureクラウドプラットフォームを数時間
停止させた理由です

15
あるaddMonths機能は、ここでの点(例えば月末こと2012-01-31 + 1 month = 2012-02-29など)。
RobG 2012年

3
毎月1日を設定するために追加するだけです。today.setHours(0、0、0、0); today.setDate(1);
Alexey Strakh 2014

56

日付と時刻の操作にmoment.jsライブラリを使用しています。1か月を追加するサンプルコード:

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

12
あなた自身の正気のために、moment.jsを使用してください。
Gaʀʀʏ

3
@garryに完全に同意します。moment.jsを使用します。
ミシェル

2
これが最もクリーンな方法であることに同意しますが、問題は「これを行うことができる何かが組み込まれているのか」ということでした。モーメントにより、ページサイズに数十KBが追加されます
Evgeny

これは良かった。これよりもはるかに良いことができる他のプラグインはネットで見つけられませんでした。
Eraniichan

26

この関数はエッジケースを処理し、高速です。

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日付の更新:(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"

ここで唯一の合理的な答え。ただし、UTC以外の日付には注意が必要です。予期しない結果をもたらす可能性があります(たとえば、1月31日+ 1か月= UTC + 1タイムゾーンの真夜中の1月3日)
Antony Hatchkins

1
別の問題は、元の日付を変更し、変更された値を返すことです。多分それを日付プロトタイプに追加するか、関数の変更された日付にローカル変数を使用することは理にかなっていますか?
アントニーハッチキンズ2016

Antonyに感謝します。ローカル変数は理にかなっています。
aMarCruz 2016

1
「return date」の行を削除するか、ローカル変数を追加することをお勧めします。
アントニーハッチキンズ2016

ローカル変数と個別のテストを使用して更新されました。
aMarCruz 2016

12

これらの回答のいずれも、月が変更された現在の年を説明しないことを考慮して、それを処理する必要のある以下で作成したものを見つけることができます。

メソッド:

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

結果の月に対応する日付がない場合、この回答では月の追加は考慮されません(例:Jan 31 + 1か月=> 2または3 Mar)。また、Dateに12か月以上追加すると問題があると考えられているようです。問題はありません。たとえば、13か月を追加する場合、1年と1か月を追加する必要はありません。13か月追加するだけです。
RobG

9

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

4

上記の回答から、エッジケースを処理する唯一のもの(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)

はい、でも:

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

3

ほとんどの回答が強調表示されているので、setMonth()メソッドをgetMonth()メソッドと一緒に使用して、特定の日付に特定の月数を追加できます。

例:(@ChadDが彼の回答で述べたように。)

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

ただし、エッジケースで問題が発生するため、このソリューションは慎重に使用する必要があります。

エッジケースを処理するには、次のリンクにある回答が役立ちます。

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


3

単純なソリューション:2678400000ミリ秒で31日

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

更新:

このデータを使用して、独自の関数を作成します。

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

8
31日がない月もある
Alexandru Severin

同意しますが、簡単に調整したり、関数を記述したりできます
dr.dimitru

2
人々が求めているのは、月単位の日数を自動的に考慮に入れる関数そのものだと思います。
Alexander Bird、

@AlexanderBirdは、moment.jsなど、他の誰かが作成した防弾ツールを使用します
dr.dimitru

2
この回答は、すべての日が24時間(または8.64e7ミリ秒)であるとは限らない夏時間には対応していません。
RobG 2017年

2
d = new Date();

alert(d.getMonth()+1);

月のインデックスは0から始まり、alert(4)は5(5月)になるはずです。


このメソッドは、0未満で12より大きい値を返す可能性があります
Patrick

2

承認された回答とコメントに追加するだけです。

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

2
Date(31)を「1月2日」に設定すると、「3月3日」になります。あなたが本当に欲しいものですか?
アントニーハッチキンズ2016

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

0

以下は、フォームフィールドを介した日付入力(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;
}

0

提示された複雑で醜い答えの多くで示されているように、日付と時刻は、任意の言語を使用するプログラマにとって悪夢になる可能性があります。私のアプローチは、日付と「デルタt」値をエポック時間(ミリ秒)に変換し、任意の算術演算を実行してから、「人間の時間」に戻すことです。

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

これは少し異なるユースケース用に作成されましたが、関連するタスクに簡単に適応できるはずです。

編集:ここに完全なソースがあります


3
それは問題である、日数の異なる月を処理しないため、役に立たない答えです。
Benubird、2015年

1
@Benubird-あなたがとても丁寧に尋ねたので、私は完全なソースをアップロードしました。この投稿にリンクします。
Dan Ahlquist、2015年

これは、すべての日が24時間(または8.64e7ミリ秒)であるとは限らない夏時間にも対応していません。
RobG 2017年

いいえ、ありません。DSTはローカリゼーションの問題です。
Dan Ahlquist 2017年

0

これらはすべて複雑すぎるように思われ、「1か月」を正確に追加することの意味についての議論に入ると思います。30日ということですか?1日から1日までという意味ですか?最終日から最終日まで?

後者の場合、2月27日に月を追加すると3月27日になり、2月28日に月を追加すると3月31日になります(うるう年では3月28日になります)。次に、3月30日から1か月差し引くと、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));
};

「Xか月を追加する」とは、月がXずつ増えることを意味することは明らかだと思います。答えのコード化のアルゴリズム手順が少ないのは事実ですが、残念ながら、正確さが単純さよりも優先されます。人々は答えを探すとき、「2016年7月31日」が「2016年8月31日」になることを望みます。そして、これはそれをしません。その上、正確さを犠牲にして本当にシンプルさが必要な場合は、こだわりませんd.setMonth(d.getMonth()+1)か?したがって、これは最も単純なアイデアではありません。
Alexander Bird、

これは、すべての日が24時間(または8.64e7ミリ秒)であるとは限らない夏時間にも対応していません。
RobG 2017年

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

}

1
ほとんどのコードが英語であり、Deutschの変数である場合、私はそれが非常に不気味であると思います。;)
Bernhard Hofmann 2014年

-1

BIRTパラメータのように、1人のオペレーターが便利な日付を作成する

私は1か月前に作成しました:

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

-3
var a=new Date();
a.setDate(a.getDate()+5);

上記の方法のように、Date関数に月を追加できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.