この記事では、phpが用意しているCarbonを使って日時の操作を行う際にハマる罠を紹介します。
具体的には、addMonth()についてです。
月を追加する際によく使うと思いますが、使い方に気をつけないと思わぬところで意図せぬエラーやバグが発生します。
どういったケースで起こってしまうのか、それを回避するにはどうすれば良いかということをこの記事で紹介できればと思います。
この記事を読むメリット
- CarbonのaddMonth()を使う際にハマりがちなポイントを理解できる
- 月の追加には2パターンを使い分けることができるようになる
addMonth()を使う際のハマりポイント
まずはaddMonth()でどういった際にハマってしまうのか解説します。
それは「月末」の際に起こります。
1つ例を紹介します。
public function addMonthTest()
{
$date1 = Carbon::parse('2024-06-30');
$date1->addMonth();
$date2 = Carbon::parse('2024-01-31');
$date2->addMonth();
return view('addmonth')
->with('date1', $date1)
->with('date2', $date2);
}
上の例では、2つの日時「2024-06-30」、「2024-01-31」をそれぞれ$date1、$date2に格納しています。
その2つの日時に対して「addMonth()」を行い1ヶ月追加しています。
その結果が以下になります。
![addMonth()の結果](https://ensei1375.com/wp-content/uploads/2024/06/carbon-addmonth_date1-date2-addmonth-1.png)
「2024-06-30」の1ヶ月後が「2024-07-30」になるのは納得です。
しかし、「2024-01-31」の1ヶ月後は「2024-03-02」となっています。
これは想定外の方もいるのではないでしょうか。
私はてっきり「1/31」の1ヶ月後は「2/29」になると思っていました。
実際には、「2/31」が存在しないため、溢れた2日分を3月に回しているということらしいです。
つまり、月を追加して行った際に同じ日にちが存在しない際、溢れた日数は次の月に追加されるということです。
addMonth()を使っていると、月末になるようにしたい場合に思わぬ落とし穴にはまってしまいます。
うるう年が絡むとaddYear()でも同じ現象が起きる
addYear()でもそれが同じ現象が起こってしまうケースがあります。
うるう年です。
こういうイレギュラーは日時を扱う場合は注意が必要ですね。
$date3 = Carbon::parse('2024-02-29');
$date3->addYear();
このようにうるう年である2024年の「2/9」にaddYear()を使用すると以下の結果になります。
![うるう年のaddYear()](https://ensei1375.com/wp-content/uploads/2024/06/xcarbon-addmonth_date1-date2-uruudoshi.png.pagespeed.ic.wIaSZZsC_T.png)
addYear()を使って日付が次の月にずれてしまうのはこのパターンだけですが、考慮に入れておく必要があります。
addMonths()、addYears()でも同じ
さらに複数月、複数年を追加するメソッドでも同様です。
引数の月や年を追加した際に、同じ日にちが存在しないと次の月になってしまいます。
エンジニアにおすすめ書籍
エンジニアになりたて、これから勉強を深めていきたいという方におすすめの書籍はこちら!
addMonthNoOverFlow()を使って月末になるようにする
では、必ず月末になるようにするにはどうすれば良いか。
結論、「addMonthNoOverflow()」を利用すれば良いです。
addMonthNoOverflow()はaddMonth()とは異なり、追加後に同じ日にちが存在しない場合、その月の月末を返すメソッドです。
以下が例です。
public function addMonthTest()
{
$date1 = Carbon::parse('2024-06-30');
$date1->addMonthNoOverflow();
$date2 = Carbon::parse('2024-01-31');
$date2->addMonthNoOverflow();
return view('addmonth')
->with('date1', $date1)
->with('date2', $date2);
}
先ほどのコードから、addMonth()の部分をaddMonthNoOverflow()に置き換えました。
結果がこのようになります。
![addMonthNoOverflow()のサンプル](https://ensei1375.com/wp-content/uploads/2024/06/carbon-addmonth_date1-date2-addmonthNoOverFlow.png)
「addMonthNoOverflow()」を使った$date2は期待通り「2024/2/29」となり2月の月末になっています。
先ほど同様の事例として紹介したものについても同じように対処できます。
addYear()はaddYearNoOverFlow()でうるう年問題を解決できます。
複数月、複数年を追加する場合は「addMonthsNoOverflow()」、「addYearsNoOverFlow()」をそれぞれ使用すれば解決できます。
Carbonで月の追加する際は注意しよう
いかがだったでしょうか。
単に月の追加の際は「addMonth()」を使用すれば良いと思っていると、今回のような罠にハマってしまいます。
要件によってどちらの追加方法を採用するべきか異なるとは思います。
きちんとCarbonのメソッドがどのような処理になっているか理解できていると罠にハマる前にスマートに対応できると思います。
ぜひ使い分けができるようになりましょう。