Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
30
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

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

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って呼ぶべきでは。長いからかな。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
30
Help us understand the problem. What are the problem?