CommentOut

PHPのstrtotimeを使った日付(Date)の計算がおかしい PHPのstrtotimeを使った日付(Date)の計算がおかしい

PHPのstrtotimeを使った日付(Date)の計算がおかしい

公開日:  最終更新日:

PHPでstrtotimeで前月・翌月の日付を取得する時、なんか取得結果がおかしいことないですか?
これはPHPの仕様が関係します。
詳しく見ていきましょう。

strtotime関数で日付の計算結果がおかしくなる条件

どんな時にstrtotimeの取得結果がおかしくなるか
月末頃に前月・翌月を取得した時、前月・翌月が31日無い時におかしくなりがちです。

以下の実行結果を見てください。

<?php
echo date("Y-m-d", strtotime("2024-01-31 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-02-29 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-03-31 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-04-30 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-05-31 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-06-30 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-07-31 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-08-31 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-09-30 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-10-31 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-11-30 -1 month"))."<br>";
echo date("Y-m-d", strtotime("2024-12-31 -1 month"))."<br>";
// 表示結果
2023-12-31
2024-01-29
2024-03-02
2024-03-30
2024-05-01
2024-05-30
2024-07-01
2024-07-31
2024-08-30
2024-10-01
2024-10-30
2024-12-01

-1 monthで前月を取得する処理をしているのですが、echoする時点では1月~12月まで綺麗に並んでいるのに、表示結果を見ると2月・4月・9月・11月が飛ばされ、3月・5月・7月・10月が2つずつ表示されています。

上記の処理では『前月』を取得しているので、取得データがおかしくなっている月を見ると
3月末の-1 monthが3月2日になっている→3月の前月(2月)が29日までしかない
5月末の-1 monthが5月1日になっている→5月の前月(4月)が30日までしかない
7月末の-1 monthが7月1日になっている→7月の前月(6月)が30日までしかない
10月末の-1 monthが10月1日になっている→10月の前月(9月)が30日までしかない
12月末の-1 monthが12月1日になっている→12月の前月(11月)が30日までしかない
おかしくなっている月は、全て31日無いんです。

strtotime関数で日付がずれる時、どういう処理になっている?

strtotime関数で-1 month, +1 monthした時、PHP内部では指定通り日付は変わらず、月だけが変更されています。
ただし、-1 monthした時に現在の日付が31日で、前月が31日無い時(例えば、現在7月31日だと前月の6月は30日までしかない)、日付をそのままに月だけ変えると、太陽暦上存在しない日付になります。
これを回避するために「はみ出た日数分、翌月にはみ出した」と考えるわけですね。

7月31日から-1 monthすると6月31日だけど、6月に31日はないから1日はみ出した分、翌月にはみ出ちゃってると捉えて、7月1日を返す。
だから、さっきの表示の通り、7月31日の-1 monthは7月1日になるんです。

これは+1 monthして翌月を取得した時でも同じことが起きます。

月がおかしくならないように、前月や翌月を取得する方法

パターン1:1日で計算する

日付は一旦置いといて、strtotime(‘Y-m-01 -1 month’)で計算するという方法
1日はどの月にも等しく存在しているので、1日だけ固定にして、月を計算して出す方法が使えます。
ただし、もっと明示的に計算する方法もあります。

パターン2:first day of previous month, first day of next month

first day of previous monthなどを使うことで、現在の日付を意識することなく、前月の1日や翌月の1日を取得することが出来ます。

<?php
echo date("Y-m-d", strtotime("2024-01-31 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-02-29 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-03-31 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-04-30 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-05-31 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-06-30 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-07-31 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-08-31 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-09-30 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-10-31 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-11-30 first day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-12-31 first day of previous month"))."<br>";
// 表示結果
2023-12-01
2024-01-01
2024-02-01
2024-03-01
2024-04-01
2024-05-01
2024-06-01
2024-07-01
2024-08-01
2024-09-01
2024-10-01
2024-11-01

元の日付はそれぞれ月末にしているのですが、表示結果では1日になっていますし、ちゃんと月が順番通り並んでいるのがわかります。

パターン3:last day of previous month, last day of next month

実は月の最終日で計算する時、この方法ならちゃんと末日を取得することができます。

<?php
echo date("Y-m-d", strtotime("2024-01-31 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-02-29 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-03-31 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-04-30 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-05-31 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-06-30 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-07-31 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-08-31 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-09-30 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-10-31 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-11-30 last day of previous month"))."<br>";
echo date("Y-m-d", strtotime("2024-12-31 last day of previous month"))."<br>";
// 表示結果
2023-12-31
2024-01-31
2024-02-29
2024-03-31
2024-04-30
2024-05-31
2024-06-30
2024-07-31
2024-08-31
2024-09-30
2024-10-31
2024-11-30

このように、なかなか気づきにくいですが、月末だけ処理がおかしくなるとしたら、このような日付の処理がおかしいのかもしれません。

宣伝
WordPressサイトのテンプレート編集やトラブル対応、バグ修正、簡単なJavascriptの作成(カルーセルやバリデーション等)など、小規模なスポット対応を受け付けております。
もしお困りごとがありましたら、お問い合わせフォームよりご相談ください。

この記事を書いた人

uilou

uilou

プログラマー

基本的に、自分自身の備忘録のつもりでブログを書いています。 自分と同じ所で詰まった人の助けになれば良いかなと思います。 システムのリファクタリングを得意としており、バックエンド、フロントエンド、アプリケーション、SQLなど幅広い知識と経験があります。 広いだけでなく、知識をもっと深堀りしていきたいですね。