CakePHP(v3.x)、ChronosによるimmutableなDateとmutableなDate

CakePHPでは日付時刻を扱うライブラリとしてChronosが採用されています。 標準的なのPHPのdateメッソドの場合、2019/1/31に対して1ヶ月加算したい場合に以下のような処理を実行すると、

date('Y-m-d', strtotime('2020-01-31 +1 month'));

// 2020-03-02

と出力されてしまいます。 しかし、一般的に1月加算する処理として期待する出力は2020/2/29だったりします。

Chronosの場合はaddMonthメッソドを用いると、

$date = new Date("2020/1/31");
$date->addMonth();

// 2020-02-29

便利ですね。

このChronsonには、さらにDateをmutableに取り扱うDateクラスと、Immutableに取り扱うFrozenDateクラスが存在します。

use Cake\I18n\Date;

$m_date= new Date("2020/1/31"); // mutable
$m_date->addMonth();
$this->log($m_date); // 2020/02/29


use Cake\I18n\FrozenDate;

$im_date = new FrozenDate("2020/1/31"); // immutable
$im_date->addMonth();
$this->log($im_date); // 2020/01/31

それぞれaddMonthをメソッドを実行した後の変化をみると明らかです。 (Time型にも同様にImmutableなFrozenTime型が存在します。)

mutableなものはバグのきっかけをを生んでしまう可能性が高いので、処理を向上させるなどの特別な理由がなければimmutableなFrozenDate型を使う方が良さそうです。