Carbon使用時の注意点
こんにちは!Booost株式会社Webエンジニアのramcursweです。
昔、日付や時間を扱うライブラリであるCarbon
を使って実装した際、ちょっとした罠にハマってしまったので、その備忘および共有としてまとめたいと思います。
注意点
実際のコードで見た方が分かりやすいですので、さっそくですが例を挙げます。
まず、以下のように記述します。
use Carbon\Carbon;
$now = Carbon::now();
// 以下のようなCarbonオブジェクトが返却される
// Carbon\Carbon @1759042601 {#10972
// date: 2025-09-28 15:56:41.519474 Asia/Tokyo (+09:00),
// }
これはごく普通の動きなので問題ないですね!
次に上記で定義した$now
を使い、時間を加算します。
$afterFiveHours = $now->addHours(5);
// $nowの結果に5時間加算される
// Carbon\Carbon @1759060601 {#10972
// date: 2025-09-28 20:56:41.519474 Asia/Tokyo (+09:00),
// }
これも問題ないと思います。
ただ5時間加算されただけですね。
それでは、今度は$now
に対して別の時間を加算してみます。
$afterTenHours = $now->addHours(10);
// $nowの結果に10時間加算される...?
// Carbon\Carbon @1759096601 {#10972
// date: 2025-09-29 06:56:41.519474 Asia/Tokyo (+09:00),
// }
おかしいですね…
上記の例において、元々$now
は2025-09-28 15:56:41.519474
という日時であるので、「10時間加算すると15時の10時間後である1時になるはずでは?」と当時の私は考えていました(そんな訳ないのですが…)。
このズレは、2番目の処理で$now
に5時間加算された時点で元のオブジェクトが更新され、15→20時に上書きされることで発生します(破壊的操作)。
これが実装者の意図通りであるならば何の問題もありません。
しかし、$now
を元々の定義から変更したくないというケースでは、どのようにすべきなのでしょうか?
解決方法はとてもシンプルです!
Carbon
ではなく、CarbonImmutable
を使いましょう!
改めて$now
を定義し、時間を加算していきます。
use Carbon\CarbonImmutable;
$now = CarbonImmutable::now();
// Carbon\CarbonImmutable @1759045481 {#10983
// date: 2025-09-28 16:44:41.728274 Asia/Tokyo (+09:00),
// }
$afterFiveHours = $now->addHours(5);
// Carbon\CarbonImmutable @1759063481 {#10970
// date: 2025-09-28 21:44:41.728274 Asia/Tokyo (+09:00),
// }
$afterTenHours = $now->addHours(10);
// 元々の$nowの結果に10時間加算される
// Carbon\CarbonImmutable @1759081481 {#11020
// date: 2025-09-29 02:44:41.728274 Asia/Tokyo (+09:00),
// }
Carbon
使用時と違い、元々の$now
の結果を変えることなく、初めの日時に対して10時間後を求めることができました。
元のオブジェクトの値を保持して使い回したい場合は、CarbonImmutable
にすべきです。
学び
当時は「日時関係の処理=Carbonを使えばいい」と安直に考えていたのですが、破壊的操作は予期せぬエラーの原因となり得るので、できるだけ使用は控えるべきです(自戒の意味を込めて…)。
Discussion