10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JavaScriptの日付計算は月末考慮しないとハマる

Posted at

JavaScriptでn年後の同月の月末を求める処理が必要になり、Dateオブジェクトを使って日付の加減算を行ったのだが、思わぬ罠が潜んでいたので共有することにした。

Dateオブジェクトで日付の加減算

DateオブジェクトにはgetMonthsetMonthなど、年月日の数字を取得/設定できるメソッドが用意されているため、これを使うのが一般的だろう。

var date = new Date("2020/4/11");
date.setMonth(date.getMonth() + 1);
console.log(date.toLocaleDateString()); // 2020/5/11
date.setFullYear(date.getFullYear() - 2);
console.log(date.toLocaleDateString()); // 2018/5/11

月末を求める場合はsetDate(0)

月末を求める場合は、Dateオブジェクトを求めたい月の翌月に設定し、setDate(0)を実行する。

var date = new Date("2020/4/11");
date.setMonth(date.getMonth() + 1);
date.setDate(0);
console.log(date.toLocaleDateString()); // 2020/4/30

月末を考慮していないとハマる罠

たとえば、2020/1/31を基準に、Nヶ月後の月末日を求めたい時は以下のようにするだろう。

var date = new Date("2020/1/31");
var n = 1; //翌月の月末日(2020/2/29)を求めるために1を設定
date.setMonth(date.getMonth() + n + 1); // 2020/3/31 に設定する
date.setDate(0);
console.log(date.toLocaleDateString()); // 2020/2/29 になる

ところが、これを以下のように月計算を分割すると正しい結果が得られない。

var date = new Date("2020/1/31");
var n = 1; //翌月の月末日(2020/2/29)を求めるために1を設定
date.setMonth(date.getMonth() + n);  // 2020/3/2に設定されてしまう
date.setMonth(date.getMonth() + 1);  // 2020/4/2に設定されてしまう
date.setDate(0);
console.log(date.toLocaleDateString()); // 2020/3/31 になってしまう

しかも、この現象は基準日が2020/1/29以前であれば発生しないという厄介なものだ。

月末への対策

加減算を行う前に日付を1日に設定するのが簡単だろう。

var date = new Date("2020/1/31");
date.setDate(1); // 2020/1/1に設定する
date.setMonth(date.getMonth() + 1);  // 2020/2/1に設定される
date.setMonth(date.getMonth() + 1);  // 2020/3/1に設定される
date.setDate(0);
console.log(date.toLocaleDateString()); // 2020/2/29 になってくれる

さいごに

まとめてみると簡単なことだが、コードレビューでこれを発見するのは困難ではなかろうか。
特に、日付演算を不用意に関数化して分割しているとなおさらだろう。

テスト工程で見つける前提とするなら、観点として月末という境界値チェックが必要となることは覚えておきたい。

10
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?