2014年01月31日に、ユーザーさんからカレンダー入力画面の次月ボタンを押したら3月のカレンダーが表示されたとの報告を頂いた。
次月ボタンを連続で押してしまったのでは?と確認すると、上長の方も現象を確認したとのことで調査することになった。
このシステムは何年も前から運用されており、私は数年前から改善作業を引き継いでいる。
プログラムはレガシーASP + Javascriptで作成され、カレンダー入力機能も自前で当初から作成したものである。
調査自体は、2月に入ってから行った。
カレンダー表示後、一旦01月31日を指定してから次月ボタンを押下しても、正常に2月のカレンダーが表示された。
指定してからは正常であるため、初期表示時が怪しいと睨んだ。
そこで、初期表示に当日(DBのシステム日付)をパラメータを渡している箇所を突き止め、2014年01月31日がセットされるように修正してカレンダーを表示させた。
そして次月ボタンを押下すると、報告された現象通りに3月のカレンダーが表示されたのである。
原因箇所を探してみると、下記の通りJavascriptの次月を求める処理で、月は+1加算して年と日は当日(31日)のものをそのまま使用し新たな日付を生成していた。
result = new Date(2014, 2, 31);
どうもJavascriptでは、存在しないような不正な入力に対してはType Errorが投げられるわけではなく、よきに計らった(おせっかいな?)値を返してくれる。
今回のように2月31日が無い場合は、次月の3月31日を返すようになっている。他にも1月32日を指定すると2月1日を返してきたりします。
不具合対応としては、当日ではなく初日(1日)を指定するように修正を行った。
ちなみに、RubyやPythonやPHPでは、2月31日を指定すると3月3日(閏年時は3月2日)を返すようになっている。
1ヶ月後を求める場合にも気を付ける必要がありそうです。
DateTimeクラスの落とし穴と対策 : PHP Advent Calendar jp 2011 Day 7
http://scriptworks.jp/blog/2011/12/how_to_avoid_pitfall_of_php_datetime/