PHP

PHPで日付をループする方法と罠

More than 1 year has passed since last update.

PHP の DatePeriod で日付をループする。

見慣れないし存在自体忘れそう&地味に面倒くさい仕様なのでメモ。


使い方

ループする期間の始点、終点(?)、間隔を指定する。

<?php

$start = new DateTime('2016-11-02'); // 16/11/02 から
$end = new DateTime('2016-11-08'); // 16/11/08 まで
$interval = new DateInterval('P2D'); // 2日間隔で(最初に P)

$period = new DatePeriod($start, $interval, $end); // 順番注意

foreach ($period as $date) {
echo $date->format('Y-m-d');
echo "\n";
}

// 出力(16/11/08 は出てこない)
/*
2016-11-02
2016-11-04
2016-11-06
*/

終点はループに含まれないので注意。わかりづら。


終点の日付も含める

DatePeriod という名前だけど突っ込んでるのもループしてるのも DateTime オブジェクトなので、時刻も見てる&持ってる。

終点の日付も含めたいなら、終点の時刻を始点より後に設定しちゃえばいい。

<?php

$start = new DateTime('2016-11-02'); // 16/11/02 00:00:00
$end = new DateTime('2016-11-08 00:00:01'); // 16/11/08 00:00:01
$interval = new DateInterval('P2D');

$period = new DatePeriod($start, $interval, $end);

foreach ($period as $datetime) {
echo $datetime->format('Y-m-d H:m:s');
echo "\n";
}

// 出力(16/11/08 も出てくる)
/*
2016-11-02 00:00:00
2016-11-04 00:00:00
2016-11-06 00:00:00
2016-11-08 00:00:00
*/

考えるの面倒くさいし始点には00:00:00、終点には23:59:59とでもつけちゃうのがいいとおもう。

ちなみに、既にある DateTime オブジェクトの時刻を書き換えるのはsetTime()

<?php

$today = new DateTime(null, new DateTimeZone('Asia/Tokyo')); // 2016-11-07 01:17:38
$today->setTime(12, 34, 56); // 2016-11-07 12:34:56

破壊的操作。


(11/13 追記)終点を表示させたい日の翌日にする

コメントにてアドバイスを頂いたので追記。

こちらでも思った通りの表示ができます。(詳しくはコメントのほうを)

$end = new DateTime('2016-11-09'); // 16/11/08 まで表示され、16/11/09 は表示されない。

ちなみに 1日後にするのはこう。(筆者による)

出たな DateInterval……!

$end = new DateTime('2016-11-08');

$end->add(new DateInterval('P1D')); // 16/11/09


時刻をループする(脱線)

ちなみに時刻でもループできる。

<?php

$start = new DateTime('2016-11-02 22:33:44');
$end = new DateTime('2016-11-08');
$interval = new DateInterval('P1DT2H3M45S'); // 1日と2時間3分45秒間隔で

$period = new DatePeriod($start, $interval, $end);

foreach ($period as $datetime) {
echo $datetime->format('Y-m-d H:i:s');
echo "\n";
}

// 出力
/*
2016-11-02 22:33:44
2016-11-04 00:37:29
2016-11-05 02:41:14
2016-11-06 04:44:59
2016-11-07 06:48:44
*/

DateInterval って他にどこで使うか知らないけどどうして最初にPつけるんだろう……。

単位は下表のとおり。複数並べるときは表中で上にあるものから。

単位
記号


Y


M


D

時間
H


M


S

まさかのMかぶってるっていう。

そのせいか時刻の前にはTをつけることになってる。

'P3M'だと3ヶ月、'PT3Mだと3分。ウケる。

例えば「1日と2時間」のつもりで'P1D2M'と書くと Fatal error 吐かれる。

正しくは'P1DT2M'。ウケる。

ていうかこれ DateTimeInterval, DateTimePeriodって呼ぶべきでは。長いからかな。