読者です 読者をやめる 読者になる 読者になる

Nullppo

メモ帳的なにか

JavaScriptのsetMonthについて

JavaScriptで日付(主に月)の加算・減算をしたい人必見!!!

やり方をググると、色々なページで解説がありますね。
そして、殆どがsetMonthを使ってますね!

https://msdn.microsoft.com/ja-jp/library/tst8h9zw(v=vs.94).aspx
setMonth メソッド (Date) (JavaScript)

Date オブジェクトの日付の月の部分を現地時刻で設定します。

構文
dateObj. setMonth(numMonth[, dateVal])

パラメーター
dateObj必須。任意の Date オブジェクトを指定します。numMonth必須。設定する月を表す数値を指定します。1 月の値は 0 で、2 月以降の値はそれに続く連続した数字です。dateVal省略可能です。設定する月の日付と等しい数値を指定します。この値を省略した場合は、getDate メソッドにより返される値が使用されます。

解説
世界協定時刻 (UTC) を使用して月の値を設定するには、setUTCMonth メソッドを使用します。
numMonth に 11 を超える値 (1 月は 0) または負数を指定すると、値に応じて格納されている年の値が変更されます。たとえば、日付が "Jan 5, 1996" と格納されている場合に setMonth(14) メソッドを呼び出すと、日付は "Mar 5, 1997" に変更されます。
setFullYear メソッドを使用すると、年、月、および日を設定できます。

上記の説明を見ると行けそうな気がします。
しかし、、、コレちょっと危険なんです!!

1月末日に+1ヵ月して2月末日を出そうとした場合、期待通りにいかないはずです!

var date = new Date('2015/1/31');
date.setMonth(date.getMonth()+1);

こう書いて正解っぽく見えますが、、、、
結果は【2015/3/3】になってしまいます。

おそらくですが、
2月31日(あり得ない) - 2月28日(現実) = 3日
2月28日(現実) + 3日(あまった日数) = 2015/3/3(結果)
このような計算が行われていると思われます。
今回は加算でしたが、減算でも起こり得ます(検証済み)。

じゃあ何故このようなことになってしまったのか。。。
ヒントはwikiにありました。

JavaScriptという言葉は狭義にはMozillaが仕様を策定し実装しているスクリプト言語を指す。このスクリプト言語EcmaインターナショナルでECMAScript (ECMA-262) として標準化されており、多くのWebブラウザー等はこの標準化されたECMAScriptを実装している。
https://ja.wikipedia.org/wiki/JavaScript

上記の文にあるECMAScriptのリファレンスを読んでみると。。。。。

15.9.5.38 Date.prototype.setMonth (month [, date ] )

If date is not specified, this behaves as if date were specified with the value getDate().

Let t be the result of LocalTime(this time value).
Let m be ToNumber(month).
If date is not specified, then let dt be DateFromTime(t); otherwise, let dt be ToNumber(date).
Let newDate be MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t)).
Let u be TimeClip(UTC(newDate)).
Set the PrimitiveValue internal property of this Date object to u.
Return u.
The length property of the setMonth method is 2.
http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.5.38

ちゃんと書いてるっぽいですね?(英語がイマイチ。。。orz
きっと知らずに使っている方はいっぱいいらっしゃいます。
みなさん気をつけてくだせぇ!!!

ライブラリを使って解決したり、日付を月初でやったりと、
対策もたくさんあります!
一番良いのは何かを考えながら実装するのも楽しいですね!