はじめに

phpで日付関連のこと調べると、手続き型の方法が検索上位に来てあまり手続き型で書きたくないなーと思ったので、DateTimeクラスを使った日付関連のことを個人メモ的にまとめた。

サンプル

現在日時を作成

$date = new DateTime();
echo $date->format('Y-m-d H:i:s'); // 2014-08-06 21:15:49

任意の日時を作成

// 文字列から
$date = new DateTime('2014-08-01 23:01:05');
echo $date->format('Y-m-d H:i:s'); // 2014-08-01 23:01:05

// 数値から
$date = new DateTime();
$date->setDate(2014,8,1);
echo $date->format('Y-m-d H:i:s'); // 2014-08-01 21:04:25

$date = new DateTime();
$date->setDate(2014,8,1)->setTime(1,10,13);
echo $date->format('Y-m-d H:i:s'); // 2014-08-01 01:10:13

任意の日時を作成(その2)

インスタンス作成時に日時を文字列で渡しても作れるけど、
yyyy-mm-dd とか yyyy/mm/ddOK
yyyy年mm月dd日NG
みたいに、決まった書式で渡さないとダメ

柔軟にいろんな文字列で日時指定をしたいときはこっちを使う。

$format = 'Y年m月d日 H時i分s秒';
$date = DateTime::createFromFormat($format, '2014年02月05日 23時11分24秒');
echo $date->format('Y-m-d H:i:s');

timezoneの取得 & 設定

$date = new DateTime();
$timezone = $date->getTimezone();
echo $timezone->getName();            //現在のtimezone:Asia/Tokyo
echo $date->format('Y-m-d H:i:s');    // 2014-08-06 21:09:59

// timezone変更
$date->setTimezone(new DateTimeZone('Europe/London'));
echo $date->format('Y-m-d H:i:s');    // 2014-08-06 13:09:59

// 最初っからtimezoneを指定
$date = new DateTime(null,new DateTimeZone('Europe/London'));
echo $date->format('Y-m-d H:i:s');    // 2014-08-06 13:09:59

いろいろな出力形式

詳しくはformat パラメータ文字列定義済み定数参照

$date = new DateTime();
echo $date->format('Y-m-d h:i:s a'); // 2014-08-06 9:23:46 pm
echo $date->format('y-F-d D');       // 14-August-06 Wed
echo $date->format('t');             // 31

// 定義済み書式
echo $date->format(DateTime::ATOM);  // 2014-08-06T21:28:50+09:00
echo $date->format(DateTime::COOKIE);// Wednesday, 06-Aug-14 21:28:50 JST
echo $date->format(DateTime::RSS);   // Wed, 06 Aug 2014 21:28:50 +0900
echo $date->format(DateTime::W3C);   // 2014-08-06T21:28:50+09:00

日付を足したり、引いたり、相対的な日時を求める

modifyで認識できる書式は、サポートする日付と時刻の書式を参照

$date = new DateTime('2014-08-05');
echo $date->modify('+1 days')->format('Y-m-d H:i:s');//1日後

$date = new DateTime('2014-08-05');
echo $date->modify('-1 days')->format('Y-m-d H:i:s');//1日前

// その他いろいろ
$date->modify('+6 hours');                     // 6時間後
$date->modify('+1 weeks');                     // 1週間後
$date->modify('+1 months + 2 days + 3 hours'); // 1ヶ月2日3時間後
$date->modify('noon');                         // 正午に
$date->modify('first day of this months');     // 当月1日
$date->modify('last day of this months');      // 当月末尾
$date->modify('first day of next months');     // 来月1日
$date->modify('first day of last months');     // 先月1日
$date->modify('sunday');                       // 次の日曜日
$date->modify('monday this week');             // 今週の月曜日
$date->modify('third sunday of this months')   // 第三日曜日

日付の差を計算

戻り値としてDateIntervalを返す

$date1 = new DateTIme('2014-05-04');
$date2 = new DateTime('2014-05-07');
$diff = $date1->diff($date2);
echo $diff->format('%R%a');                        // +3
echo $date2->diff($date1)->format('%R%a');         // -3
echo $date2->diff($date1, true)->format('%R%a');   // +3 (常に正)

$date1 = new DateTime('2013-05-04 23:34:14');
$date2 = new DateTime('2014-07-01 10:11:13');
$diff = $date1->diff($date2);
echo $diff->format('%R %y年 %mヶ月 %d日 %h時間 %i分 %s秒 ズレ');
// + 1年 1ヶ月 26日 10時間 36分 59秒 ズレ

タイムスタンプ取得

$date = new DateTime();
echo $date->getTimestamp();

getTimestampのバグ

DateTime::getTimestamp()すると日付が変わる件
によると、modifyした後、getTimesampを実行すると、意図せず日付が変わってしまうことがあるみたい。
その場合は、format('U')でタイムスタンプを取得すれば発生しないっぽい。

$date = new DateTime('2014/01/01 00:00:00');
$date->modify('first day of -1 second');
var_dump($date->format('Y-m-d H:i:s'));

//var_dump($date->getTimestamp()); ← こっちだと日付が変わる
var_dump($date->format('U'));   // ← こうすれば変わらないみたい

var_dump($date->format('Y-m-d H:i:s')); 

DateTime と DateTimeImmutable

DateTimeImmutable

このクラスの挙動は DateTime とほぼ同じですが、 自分自身は変更せずに新しいオブジェクトを返すという点だけが異なります。

5.5以上が使えるのなら、こっちのほうが良さそう。
(my環境は、5.4なので試してないけど)

$date = new DateTIme();
$date->modify('+1 days');
echo $date->format('Y-m-d H:i:s');

$date = new DateTimeImmutable();
$tommorow = $date->modify('+1 days');
echo $tommorow->format('Y-m-d H:i:s');

あとがき

間違いとか、他にもこれはよく使うってのがあったら指摘してくださいm(_ _)m