JavaScriptの2つの日付間の月数の違い


135

JavaScriptで2つのDate()オブジェクトの違いを計算するには、違いの月数のみを返しますか?

どんな助けも素晴らしいでしょう:)


月の長さは月によって異なるため、月はあまり正確な測定単位ではありません。1月から2月までの間隔が30日間続く場合、31日の月で考えると1ヶ月未満ですが、2月の28日または29日を考えると1ヶ月以上です。
Mark Byers、

7
あまり明確な質問ではありません。2月28日23:58から3月1日00:01は1か月ですか。それともたった一日?それともわずか3分?それとも3つすべて?
Thilo

1
@Thiloこれを実装する必要のある人はおそらく答えがないでしょう。なぜなら、彼らのマネージャーはそもそも何を求めているのかわからないからです。:)
AlbertEngelB

回答:


228

「差異の月数」の定義は、多くの解釈の対象となります。:-)

JavaScriptの日付オブジェクトから年、月、日を取得できます。探している情報に応じて、それらを使用して、2つの時点の間の月数を把握できます。

たとえば、オフザカフ:

function monthDiff(d1, d2) {
    var months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;
    months -= d1.getMonth();
    months += d2.getMonth();
    return months <= 0 ? 0 : months;
}

(JavaScriptの月の値は0 = 1月で始まることに注意してください。)

通常の2月の3日間は、8月の3日間(〜9.677%)よりもその月の比率(〜10.714%)が大きいため、上記に端数のある月を含めることはさらに複雑です。うるう年かどうかによります。

JavaScriptで使用できるいくつかの日付と時刻のライブラリもあり、おそらくこのようなことをより簡単にします。


+ 1上記のa は以前ここにありました:

months = (d2.getFullYear() - d1.getFullYear()) * 12;
months -= d1.getMonth() + 1;
// −−−−−−−−−−−−−−−−−−−−^^^^
months += d2.getMonth();

それはもともと私が言ったからです:

...これは、部分的な月を数えずに、2つの日付の間に何月あるかを調べます(たとえば、各日付が含まれる月を除外します)。

私は2つの理由でそれを削除しました:

  1. 部分的な月を数えないことは、答えに来る多くの(ほとんどの)人々が望んでいるものではないことが判明したので、それらを分離する必要があると思いました。

  2. その定義によっても、常に機能するとは限りませんでした。:-D(申し訳ありません。)


82

月の日を考慮しない場合、これははるかに簡単な解決策です

function monthDiff(dateFrom, dateTo) {
 return dateTo.getMonth() - dateFrom.getMonth() + 
   (12 * (dateTo.getFullYear() - dateFrom.getFullYear()))
}


//examples
console.log(monthDiff(new Date(2000, 01), new Date(2000, 02))) // 1
console.log(monthDiff(new Date(1999, 02), new Date(2000, 02))) // 12 full year
console.log(monthDiff(new Date(2009, 11), new Date(2010, 0))) // 1

月のインデックスは0ベースであることに注意してください。これは、January = 0とを意味しDecember = 11ます。


11
これは、これまでに見たコードの中で最も短くて理解しやすいコードです。
オマール

毎月始まったという事実を除いて、これで複雑になることは何もありません。2011年3月31日-> 2011年5月1日は2か月で、2011年1月3日-> 2011年5月31日ですが、正確には3か月でなければなりません。
ナティム2013

あなただけの月数を知りたいなら、これは完璧です!!!!! 月の日数に基づいて知る必要がある場合、これは機能しません。
OSDM

1
2018/01と2017/01が12か月離れているという事実から始めます。そこから逆方向に作業します。この答えはそれを理解します。;)
Gerard ONeill

1
ありがとう!この機能は、私にとって非常に有用である
チュオンロング

29

場合によっては、2つの日付の間の月数だけを取得して、日の部分を完全に無視することもできます。たとえば、2013/06/21と2013/10/18の2つの日付があり、2013/06と2013/10のパーツのみを気にした場合、シナリオと可能な解決策は次のとおりです。

var date1=new Date(2013,5,21);//Remember, months are 0 based in JS
var date2=new Date(2013,9,18);
var year1=date1.getFullYear();
var year2=date2.getFullYear();
var month1=date1.getMonth();
var month2=date2.getMonth();
if(month1===0){ //Have to take into account
  month1++;
  month2++;
}
var numberOfMonths; 

1. month1とmonth2の両方を除く2つの日付の間の月数だけが必要な場合

numberOfMonths = (year2 - year1) * 12 + (month2 - month1) - 1;

2.いずれかの月を含める場合

numberOfMonths = (year2 - year1) * 12 + (month2 - month1);

3.両方の月を含める場合

numberOfMonths = (year2 - year1) * 12 + (month2 - month1) + 1;

良いですね!私にとって完璧に働いた。

3
最後の1つについては、次のことをお勧めします。numberOfMonths=(year2-year1)*12+(month2-month1)+1;同じことを行いますが、意味的には私にとってより適切です
Natim

ええ、素敵でよりエレガントなアプローチ。
Mikayil Abdullayev 2013

これが最良の答えでした。ありがとう!
マリエンケ

これはシンプルでクリーンです。すばらしいコードを書いてくれてありがとう。
zeros-and-ones

28

2つの日付の間の月数を正確に提供する関数を次に示します。
デフォルトの動作では月全体がカウントされます。たとえば、3か月と1日の場合、3か月の差が生じます。これを防ぐには、roundUpFractionalMonthsparamをtrueに設定します。これにより、3か月と1日の差が4か月として返されます。

上記の受け入れられた答え(TJ Crowderの答え)は正確ではなく、時々間違った値を返します。

たとえば、明らかに間違っているmonthDiff(new Date('Jul 01, 2015'), new Date('Aug 05, 2015'))リターン0。正しい差は、丸1か2か月に切り上げられます。

これが私が書いた関数です:

function getMonthsBetween(date1,date2,roundUpFractionalMonths)
{
    //Months will be calculated between start and end dates.
    //Make sure start date is less than end date.
    //But remember if the difference should be negative.
    var startDate=date1;
    var endDate=date2;
    var inverse=false;
    if(date1>date2)
    {
        startDate=date2;
        endDate=date1;
        inverse=true;
    }

    //Calculate the differences between the start and end dates
    var yearsDifference=endDate.getFullYear()-startDate.getFullYear();
    var monthsDifference=endDate.getMonth()-startDate.getMonth();
    var daysDifference=endDate.getDate()-startDate.getDate();

    var monthCorrection=0;
    //If roundUpFractionalMonths is true, check if an extra month needs to be added from rounding up.
    //The difference is done by ceiling (round up), e.g. 3 months and 1 day will be 4 months.
    if(roundUpFractionalMonths===true && daysDifference>0)
    {
        monthCorrection=1;
    }
    //If the day difference between the 2 months is negative, the last month is not a whole month.
    else if(roundUpFractionalMonths!==true && daysDifference<0)
    {
        monthCorrection=-1;
    }

    return (inverse?-1:1)*(yearsDifference*12+monthsDifference+monthCorrection);
};

6
しかし真剣に、誰がこれに反対票を投じたのですか?彼は正しい、受け入れられた答えはただ...間違っています。
マイケルブラックバーン

2
これが最適な答えです。
Kalyan Chavali

これは、date1が1月22日で、date2が8月22日であるとしましょう。次に、7を返します。明らかに8になりますか?
Nicolai Harbo 2017

この受け入れられた答えを作ってください。これは受け入れられたものよりも正確です。たとえば、受け入れられた回答は日数を計算しません
Munkhdelger Tumenbayar

クラウダーの承認された回答はそれ以降更新されました。それとこの回答の間にはまだ重要な違いがあるかもしれませんが、これを書いている時点で、ここにリストされている懸念は対処されています。
クロザック

23

月が28日、29日、30日、または31日であるかどうかに関係なく、月全体をカウントする必要がある場合。以下で動作するはずです。

var months = to.getMonth() - from.getMonth() 
    + (12 * (to.getFullYear() - from.getFullYear()));

if(to.getDate() < from.getDate()){
    months--;
}
return months;

これは回答https://stackoverflow.com/a/4312956/1987208の拡張バージョンですが、1月31日から2月1日(1日)までのケースの1か月を計算するケースを修正します。

これは以下をカバーします。

  • 1月1日から1月31日---> 30days --->は0になります(1か月ではないため、論理値)
  • 2月1日から3月1日---> 28日または29日--->結果は1(1か月なので論理的)
  • 2月15日から3月15日---> 28日または29日--->結果は1(1か月経過後の論理)
  • 1月31日から2月1日---> 1日--->の結果は0になります(明らかですが、投稿で述べた回答は1か月になります)

2
Thaは私が確認のためにここに来たと私が思ったものであり、それは私にとって意味のある唯一の答えです
Andreas

2
これは、月が短い2か月を比較する場合は機能しません。たとえば、3月31日から4月30日までです。それが4月のすべてなので、答えは「1」になります。
マイケルブラックバーン

7

JavaScriptの2つの日付間の月数の違い:

 start_date = new Date(year, month, day); //Create start date object by passing appropiate argument
 end_date = new Date(new Date(year, month, day)

start_dateからend_dateまでの合計月数:

 total_months = (end_date.getFullYear() - start_date.getFullYear())*12 + (end_date.getMonth() - start_date.getMonth())

6

私はこれが本当に遅いことを知っていますが、他の人を助けるためにとにかく投稿します。これは私が思いついた関数で、2つの日付の間の月の違いを数えるのに適しています。確かに、Mr.Crowderのものよりかなり不快ですが、日付オブジェクトをステップ実行することにより、より正確な結果を提供します。それはAS3にありますが、強い型付けをドロップするだけでJSが得られます。そこにいる人をもっと素敵に見せるのをお気軽に!

    function countMonths ( startDate:Date, endDate:Date ):int
    {
        var stepDate:Date = new Date;
        stepDate.time = startDate.time;
        var monthCount:int;

        while( stepDate.time <= endDate.time ) { 
            stepDate.month += 1;
            monthCount += 1;
        }           

        if ( stepDate != endDate ) { 
            monthCount -= 1;
        }

        return monthCount;
    }

これは、ほとんどの状況で最も可能性の高い正しいアプローチです。私たちのカレンダーには非常に多くの例外と気まぐれがあります。最善のアプローチは、それらの処理をDate()などの十分にテストされたライブラリに委任することです。ほとんどの(短い)スパンの場合、これは計算されたアプローチと同じ答えを返しますが、長いスパン(うるう年、うるう年、うるう年ではない、うるう年を含む)を扱う場合秒など)月の減算と年の加算が正しくない例外に遭遇する可能性が高くなります。計算が最適になる例外については、私の回答を参照してください。
マイケルブラックバーン

5

各日付を月数で検討し、差を求めて差し引きます。

var past_date = new Date('11/1/2014');
var current_date = new Date();

var difference = (current_date.getFullYear()*12 + current_date.getMonth()) - (past_date.getFullYear()*12 + past_date.getMonth());

これにより、日を無視して、2つの日付間の月の差が得られます。


4

@TJの答えをさらに詳しく説明するには、暦月全体ではなく単純な月を探す場合は、d2の日付がd1の日付以上かどうかを確認するだけです。つまり、d2がその月よりもd1がその月より遅い場合、1つ多い月があります。したがって、これを行うことができるはずです:

function monthDiff(d1, d2) {
    var months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;
    months -= d1.getMonth() + 1;
    months += d2.getMonth();
    // edit: increment months if d2 comes later in its month than d1 in its month
    if (d2.getDate() >= d1.getDate())
        months++
    // end edit
    return months <= 0 ? 0 : months;
}

monthDiff(
    new Date(2008, 10, 4), // November 4th, 2008
    new Date(2010, 2, 12)  // March 12th, 2010
);
// Result: 16; 4 Nov – 4 Dec '08, 4 Dec '08 – 4 Dec '09, 4 Dec '09 – 4 March '10

これは時間の問題(たとえば、3月3日の午後4時と4月3日の午後3時)を完全に考慮したものではありませんが、より正確で数行のコードです。


4

数学的および迅速な2つのアプローチがありますが、カレンダーのばらつきが多いか、反復的で低速ですが、すべての奇妙な要素を処理します(または、少なくとも十分にテストされたライブラリにそれらを処理するデリゲート)。

カレンダーを反復処理する場合は、開始日を1か月増やし、終了日を過ぎているかどうかを確認します。この代表団は、組み込みの日付()のクラスに異常ハンドリングが、遅くなる可能性のIFあなたは日付の数が多いためにこれをやっています。ジェームズの答えはこのアプローチを取ります。アイデアが嫌いなほど、これは「最も安全な」アプローチだと思います。1つの計算だけを実行している場合、パフォーマンスの違いはごくわずかです。私たちは、一度しか実行されないタスクを過度に最適化しようとする傾向があります。

ここで、データセットに対してこの関数を計算している場合、その関数を各行で実行することは望ましくありません(または、レコードごとに複数回禁止されています)。その場合、あなたはここでほぼすべての他の回答のを使用することができますを除いて、単に間違っている受け入れ答え、(違いをnew Date()してnew Date()いる-1)?

これは、数か月の長さとうるう年の違いを説明する数学的かつ迅速なアプローチの私の試みです。これをデータセットに適用する場合(この計算を繰り返し実行する場合)は、このような関数を実際に使用する必要があります。一度だけ実行する必要がある場合は、すべての(多くの)例外の処理をDate()オブジェクトに委任しているため、上記のJamesの反復アプローチを使用します。

function diffInMonths(from, to){
    var months = to.getMonth() - from.getMonth() + (12 * (to.getFullYear() - from.getFullYear()));

    if(to.getDate() < from.getDate()){
        var newFrom = new Date(to.getFullYear(),to.getMonth(),from.getDate());
        if (to < newFrom  && to.getMonth() == newFrom.getMonth() && to.getYear() %4 != 0){
            months--;
        }
    }

    return months;
}

3

ここでは、ループの少ない他のアプローチを使用します。

calculateTotalMonthsDifference = function(firstDate, secondDate) {
        var fm = firstDate.getMonth();
        var fy = firstDate.getFullYear();
        var sm = secondDate.getMonth();
        var sy = secondDate.getFullYear();
        var months = Math.abs(((fy - sy) * 12) + fm - sm);
        var firstBefore = firstDate > secondDate;
        firstDate.setFullYear(sy);
        firstDate.setMonth(sm);
        firstBefore ? firstDate < secondDate ? months-- : "" : secondDate < firstDate ? months-- : "";
        return months;
}

1
このメソッドには注意してください。(明らかに注意深く読むと、明らかに)呼び出し元に渡される最初の日付が変化します(日付は参照で渡されるため)。
Andiih

3

このソリューションを検討することもできfunctionます。これにより、月または月の差が整数または数値で返されます。

開始日を最初または最後として渡すと、paramフォールトトレラントになります。つまり、関数は同じ値を返します。

const diffInMonths = (end, start) => {
   var timeDiff = Math.abs(end.getTime() - start.getTime());
   return Math.round(timeDiff / (2e3 * 3600 * 365.25));
}

const result = diffInMonths(new Date(2015, 3, 28), new Date(2010, 1, 25));

// shows month difference as integer/number
console.log(result);


うるう年を考慮に入れるには、365.25を掛ける必要があります
darryn.ten

2

2つの日付間の差を計算するには、月の一部(日)が含まれます。


var difference = (date2.getDate() - date1.getDate()) / 30 +
    date2.getMonth() - date1.getMonth() +
    (12 * (date2.getFullYear() - date1.getFullYear()));

例:
date1:2015年9月24日(2015年9月24日)
date2:2015年9月11日(2015年11月9日)
差:2.5(月)


2

これはうまくいくはずです:

function monthDiff(d1, d2) {
    var months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;
    months += d2.getMonth() - d1.getMonth();
    return months;
}

1
function calcualteMonthYr(){
    var fromDate =new Date($('#txtDurationFrom2').val()); //date picker (text fields)
    var toDate = new Date($('#txtDurationTo2').val());

var months=0;
        months = (toDate.getFullYear() - fromDate.getFullYear()) * 12;
        months -= fromDate.getMonth();
        months += toDate.getMonth();
            if (toDate.getDate() < fromDate.getDate()){
                months--;
            }
    $('#txtTimePeriod2').val(months);
}

1

次のコードは、部分的な月のnr日も考慮して、2つの日付間の完全な月を返します。

var monthDiff = function(d1, d2) {
  if( d2 < d1 ) { 
    var dTmp = d2;
    d2 = d1;
    d1 = dTmp;
  }

  var months = (d2.getFullYear() - d1.getFullYear()) * 12;
  months -= d1.getMonth() + 1;
  months += d2.getMonth();

  if( d1.getDate() <= d2.getDate() ) months += 1;

  return months;
}

monthDiff(new Date(2015, 01, 20), new Date(2015, 02, 20))
> 1

monthDiff(new Date(2015, 01, 20), new Date(2015, 02, 19))
> 0

monthDiff(new Date(2015, 01, 20), new Date(2015, 01, 22))
> 0

1
function monthDiff(d1, d2) {
var months, d1day, d2day, d1new, d2new, diffdate,d2month,d2year,d1maxday,d2maxday;
months = (d2.getFullYear() - d1.getFullYear()) * 12;
months -= d1.getMonth() + 1;
months += d2.getMonth();
months = (months <= 0 ? 0 : months);
d1day = d1.getDate();
d2day = d2.getDate();
if(d1day > d2day)
{
    d2month = d2.getMonth();
    d2year = d2.getFullYear();
    d1new = new Date(d2year, d2month-1, d1day,0,0,0,0);
    var timeDiff = Math.abs(d2.getTime() - d1new.getTime());
          diffdate = Math.abs(Math.ceil(timeDiff / (1000 * 3600 * 24))); 
    d1new = new Date(d2year, d2month, 1,0,0,0,0);
    d1new.setDate(d1new.getDate()-1);
    d1maxday = d1new.getDate();
    months += diffdate / d1maxday;
}
else
{
      if(!(d1.getMonth() == d2.getMonth() && d1.getFullYear() == d2.getFullYear()))
    {
        months += 1;
    }
    diffdate = d2day - d1day + 1;
    d2month = d2.getMonth();
    d2year = d2.getFullYear();
    d2new = new Date(d2year, d2month + 1, 1, 0, 0, 0, 0);
    d2new.setDate(d2new.getDate()-1);
    d2maxday = d2new.getDate();
    months += diffdate / d2maxday;
}

return months;

}


1

以下のロジックは月単位で差を取得します

(endDate.getFullYear()*12+endDate.getMonth())-(startDate.getFullYear()*12+startDate.getMonth())

1
function monthDiff(date1, date2, countDays) {

  countDays = (typeof countDays !== 'undefined') ?  countDays : false;

  if (!date1 || !date2) {
    return 0;
  }

  let bigDate = date1;
  let smallDate = date2;

  if (date1 < date2) {
    bigDate = date2;
    smallDate = date1;
  }

  let monthsCount = (bigDate.getFullYear() - smallDate.getFullYear()) * 12 + (bigDate.getMonth() - smallDate.getMonth());

  if (countDays && bigDate.getDate() < smallDate.getDate()) {
    --monthsCount;
  }

  return monthsCount;
}

0

私が使うものを見てください:

function monthDiff() {
    var startdate = Date.parseExact($("#startingDate").val(), "dd/MM/yyyy");
    var enddate = Date.parseExact($("#endingDate").val(), "dd/MM/yyyy");
    var months = 0;
    while (startdate < enddate) {
        if (startdate.getMonth() === 1 && startdate.getDate() === 28) {
            months++;
            startdate.addMonths(1);
            startdate.addDays(2);
        } else {
            months++;
            startdate.addMonths(1);
        }
    }
    return months;
}

0

また、日数を数え、月単位で変換します。

function monthDiff(d1, d2) {
    var months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;   //calculates months between two years
    months -= d1.getMonth() + 1; 
    months += d2.getMonth();  //calculates number of complete months between two months
    day1 = 30-d1.getDate();  
    day2 = day1 + d2.getDate();
    months += parseInt(day2/30);  //calculates no of complete months lie between two dates
    return months <= 0 ? 0 : months;
}

monthDiff(
    new Date(2017, 8, 8), // Aug 8th, 2017    (d1)
    new Date(2017, 12, 12)  // Dec 12th, 2017   (d2)
);
//return value will be 4 months 

これがどのように機能するかについて、より詳細な説明を追加できますか?これにより、答えがより良くなります
serge1peshcoff '12

月が30日であるという仮定はありますか?
ベンタリアドロス2018

0

日時が問題にならない場合の月数

この場合、月全体、月の一部、月の長さなどは関係ありません。月数を知る必要があるだけです。関連する現実世界のケースは、毎月レポートが期日になる場合であり、私はレポートがいくつあるべきかを知る必要があります。

例:

  • 1月= 1か月
  • 1月〜2月= 2か月
  • 11月-1月= 3か月

これは、数字がどこに行くのかを示すための複雑なコード例です。

4か月になるはずの2つのタイムスタンプを取りましょう

  • 2019年11月13日のタイムスタンプ:1573621200000
  • 2020年2月20日のタイムスタンプ:1582261140000

タイムゾーン/プルした時間によって多少異なる場合があります。日、分、秒は関係なく、タイムスタンプに含めることができますが、実際の計算では無視します。

ステップ1:タイムスタンプをJavaScriptの日付に変換する

let dateRangeStartConverted = new Date(1573621200000);
let dateRangeEndConverted = new Date(1582261140000);

ステップ2:月/年の整数値を取得する

let startingMonth = dateRangeStartConverted.getMonth();
let startingYear = dateRangeStartConverted.getFullYear();
let endingMonth = dateRangeEndConverted.getMonth();
let endingYear = dateRangeEndConverted.getFullYear();

これは私たちに与えます

  • 開始月:11
  • 開始年:2019
  • 終了月:2
  • 終了年:2020

ステップ3:(12 * (endYear - startYear)) + 1終了月に追加します。

  • これにより、開始月は11のままになります。
  • これにより、終了月は15になります。 2 + (12 * (2020 - 2019)) + 1 = 15

ステップ4:月を引く

15 - 11 = 4; 4か月の結果が得られます。

29か月の例の例

2019年11月から2022年3月までは29か月です。これらをExcelスプレッドシートに入れると、29行が表示されます。

  • 開始月は11です
  • 終了月は40です 3 + (12 * (2022-2019)) + 1

40-11 = 29


-2
anyVar = (((DisplayTo.getFullYear() * 12) + DisplayTo.getMonth()) - ((DisplayFrom.getFullYear() * 12) + DisplayFrom.getMonth()));

3
このコードスニペットが解決策となる可能性がありますが、説明を含めると、投稿の品質向上に役立ちます。あなたは将来の読者のための質問に答えていることを覚えておいてください、そしてそれらの人々はあなたのコード提案の理由を知らないかもしれません。
Eugene Podskal

解答で説明または定義されていない関数に依存する解答を投稿することはあまり役に立ちません。
RobG

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