PHP,JavaScriptでの月の加減算での落とし穴
- 書いた人:
- tanippa!
- カテゴリ:
- javascript PHP
- 13,692 views
翌月や昨月の年月を取得なんて処理は結構出てくるのですが、PHPのDateTimeクラス、JavaScriptのDateクラス共に同じ落とし穴があります。結構有名な落とし穴なのですが、知っていないとテスト漏れで不具合を出したりしてしまいますので、今回はその落とし穴と対処法をご紹介したいと思います。
翌月や昨月の年月を取得なんて処理は結構出てくるのですが、PHPのDateTimeクラス、JavaScriptのDateクラス共に同じ落とし穴があります。
結構有名な落とし穴なのですが、知っていないとテスト漏れで不具合を出したりしてしまいますので、今回はその落とし穴と対処法をご紹介したいと思います。
月の加減算の落とし穴
「2015年1月31日の翌月の年月日を取得して出力」なんて処理を書く場合、以下のようになるかと思います。
<?php // PHP $dat = new DateTime('2015/01/31', new DateTimeZone('Asia/Tokyo')); echo $dat->add(new DateInterval('P1M'))->format('Y/m/d');
// JavaScript var dat = new Date(2015, 0, 31); dat.setMonth(dat.getMonth()+1); console.log(dat.toLocaleString());
この結果は、両方共「2015年3月3日」となります。イメージとしては「2015年2月28日」が帰ってきそうなのでかなり違和感がある結果ですよね?
理由
これは、
「1月31日に1月足す」→「2月31日?」→「でも2月は28日までやから3日オーバーしてんな…」→「よっしゃ気を利かして3月3日にしといたろ!」
という処理を中でしているためこのような結果となってしまっています。
確かに処理として間違っていないと言えば間違っていないのですが、大体こういう場合クラスを使用している側として欲しい答えは「2月28日」ですよね。
対処法
必要なのが「年月」のみで日付まで必要でないのであれば、以下の方法で対処が可能です。
対処法の概要
今回の問題は「1月31日」のように、月によって存在しない日付を元に加減算している所が原因となっています。
そのため、毎月必ず存在する日付(例えば「1日」は毎月ありますよね)に変えてから加減算するようにすれば問題は起こりません。
PHPでの例
<?php $dat = new DateTime('2015/01/31', new DateTimeZone('Asia/Tokyo')); echo $dat->modify('first day of')->add(new DateInterval('P1M'))->format('Y/m');
JavaScriptでの例
var dat = new Date(2015, 0, 31); var datFirstDay = new Date(dat.getFullYear(), dat.getMonth(), 1); datFirstDay.setMonth(datFirstDay.getMonth()+1); console.log(datFirstDay.toLocaleString());
これでPHP,JavaScript共に「2015年2月」を指すようになります。
以上
日付関連のクラスには落とし穴が結構多いので、たかが日付と侮らず注意して扱いましょう!
以上、たにっぱでした〜