正直、オブジェクト指向で記述するのは結構大変。
当面の間は手続き型のみで記述した方が安全そう。
日の差分を出すだけならオブジェクト指向の方が楽なんだけどね。
PHPでの無難な日付操作一覧
用途 | コード | 結果 |
---|---|---|
基準日の設定 実際の使用シーンでは $ts = time(); や $ts = $_SERVER['REQUEST_TIME']; が使用されるはず |
$base_datetime = '2016-08-11 13:00:00'; | 2016-08-11 13:00:00 |
基準となるタイムスタンプの作成 | $ts = strtotime($base_datetime); | 1470888000 |
当日開始時 | date('Y-m-d 00:00:00', $ts); | 2016-08-11 00:00:00 |
当日終了時 | date('Y-m-d 23:59:59', $ts); | 2016-08-11 23:59:59 |
月初 | date('Y-m-01 00:00:00', $ts); | 2016-08-01 00:00:00 |
月末 | date('Y-m-t 23:59:59', $ts); | 2016-08-31 23:59:59 |
先月初 | date('Y-m-01 00:00:00', strtotime(date('Y-m-01 00:00:00', $ts)) - 1); | 2016-07-01 00:00:00 |
先月末 | date('Y-m-t 23:59:59', strtotime(date('Y-m-01 00:00:00', $ts)) - 1); | 2016-07-31 23:59:59 |
翌月初 | date('Y-m-01 00:00:00', strtotime(date('Y-m-t 23:59:59', $ts)) + 1); | 2016-09-01 00:00:00 |
翌月末 | date('Y-m-t 23:59:59', strtotime(date('Y-m-t 23:59:59', $ts)) + 1); | 2016-09-30 23:59:59 |
週頭(日) | date('Y-m-d 00:00:00', strtotime(sprintf('-%s day', date('w', $ts)), $ts)); | 2016-08-07 00:00:00 |
週末(土) | date('Y-m-d 23:59:59', strtotime(sprintf('+%s day', 6 - date('w', $ts)), $ts)); | 2016-08-13 23:59:59 |
先週頭(日) | date('Y-m-d 00:00:00', strtotime(sprintf('-%s day', date('w', $ts) + 7), $ts)); | 2016-07-31 00:00:00 |
先週末(土) | date('Y-m-d 23:59:59', strtotime(sprintf('+%s day', 6 - date('w', $ts) - 7), $ts)); | 2016-08-06 23:59:59 |
翌週頭(日) | date('Y-m-d 00:00:00', strtotime(sprintf('-%s day', date('w', $ts) - 7), $ts)); | 2016-08-14 00:00:00 |
翌週末(土) | date('Y-m-d 23:59:59', strtotime(sprintf('+%s day', 6 - date('w', $ts) + 7), $ts)); | 2016-08-20 23:59:59 |
表構築機
<?php
$message = [
[
'基準日の設定(実際の使用シーンでは$ts = time();や$ts = $_SERVER[\'REQUEST_TIME\'];が使用されるはず)',
'$base_datetime = \'2016-08-11 13:00:00\';',
$base_datetime = '2016-08-11 13:00:00',
],
[
'基準となるタイムスタンプの作成',
'$ts = strtotime($base_datetime);',
$ts = strtotime($base_datetime),
],
[
'当日開始時',
'date(\'Y-m-d 00:00:00\', $ts);',
date('Y-m-d 00:00:00', $ts),
],
[
'当日終了時',
'date(\'Y-m-d 23:59:59\', $ts);',
date('Y-m-d 23:59:59', $ts),
],
[
'月初',
'date(\'Y-m-01 00:00:00\', $ts);',
date('Y-m-01 00:00:00', $ts),
],
[
'月末',
'date(\'Y-m-t 23:59:59\', $ts);',
date('Y-m-t 23:59:59', $ts),
],
[
'先月初',
'date(\'Y-m-01 00:00:00\', strtotime(date(\'Y-m-01 00:00:00\', $ts)) - 1);',
date('Y-m-01 00:00:00', strtotime(date('Y-m-01 00:00:00', $ts)) - 1),
],
[
'先月末',
'date(\'Y-m-t 23:59:59\', strtotime(date(\'Y-m-01 00:00:00\', $ts)) - 1);',
date('Y-m-t 23:59:59', strtotime(date('Y-m-01 00:00:00', $ts)) - 1),
],
[
'翌月初',
'date(\'Y-m-01 00:00:00\', strtotime(date(\'Y-m-t 23:59:59\', $ts)) + 1);',
date('Y-m-01 00:00:00', strtotime(date('Y-m-t 23:59:59', $ts)) + 1),
],
[
'翌月末',
'date(\'Y-m-t 23:59:59\', strtotime(date(\'Y-m-t 23:59:59\', $ts)) + 1);',
date('Y-m-t 23:59:59', strtotime(date('Y-m-t 23:59:59', $ts)) + 1),
],
[
'週頭(日)',
'date(\'Y-m-d 00:00:00\', strtotime(sprintf(\'-%s day\', date(\'w\', $ts)), $ts));',
date('Y-m-d 00:00:00', strtotime(sprintf('-%s day', date('w', $ts)), $ts)),
],
[
'週末(土)',
'date(\'Y-m-d 23:59:59\', strtotime(sprintf(\'+%s day\', 6 - date(\'w\', $ts)), $ts));',
date('Y-m-d 23:59:59', strtotime(sprintf('+%s day', 6 - date('w', $ts)), $ts)),
],
[
'先週頭(日)',
'date(\'Y-m-d 00:00:00\', strtotime(sprintf(\'-%s day\', date(\'w\', $ts) + 7), $ts));',
date('Y-m-d 00:00:00', strtotime(sprintf('-%s day', date('w', $ts) + 7), $ts)),
],
[
'先週末(土)',
'date(\'Y-m-d 23:59:59\', strtotime(sprintf(\'+%s day\', 6 - date(\'w\', $ts) - 7), $ts));',
date('Y-m-d 23:59:59', strtotime(sprintf('+%s day', 6 - date('w', $ts) - 7), $ts)),
],
[
'翌週頭(日)',
'date(\'Y-m-d 00:00:00\', strtotime(sprintf(\'-%s day\', date(\'w\', $ts) - 7), $ts));',
date('Y-m-d 00:00:00', strtotime(sprintf('-%s day', date('w', $ts) - 7), $ts)),
],
[
'翌週末(土)',
'date(\'Y-m-d 23:59:59\', strtotime(sprintf(\'+%s day\', 6 - date(\'w\', $ts) + 7), $ts));',
date('Y-m-d 23:59:59', strtotime(sprintf('+%s day', 6 - date('w', $ts) + 7), $ts)),
],
];
printf('|用途 |コード |結果 |%s', \PHP_EOL);
printf('|----|----|----|%s', \PHP_EOL);
foreach ($message as $row) {
printf('|%s |%s |%s |%s', $row[0], $row[1], $row[2], \PHP_EOL);
}
オブジェクト指向で実現する場合
<?php
// 基準となるDateTimeオブジェクトの作成
$dateTime = new DateTime($base_datetime);
// 復帰用タイムスタンプ
$ts = $dateTime->getTimestamp();
// 当日開始時
echo $dateTime->format('Y-m-d 00:00:00'), \PHP_EOL;
// 当日終了時
echo $dateTime->format('Y-m-d 23:59:59'), \PHP_EOL;
// 月初
echo $dateTime->format('Y-m-01 00:00:00'), \PHP_EOL;
// 月末
echo $dateTime->format('Y-m-t 00:00:00'), \PHP_EOL;
// 週頭(日)
$dateTime->setTimestamp($ts);
echo $dateTime->sub(new DateInterval(sprintf('P%sD', $dateTime->format('w'))))->format('Y-m-d 00:00:00'), \PHP_EOL;
// 週末(土)
$dateTime->setTimestamp($ts);
echo $dateTime->add(new DateInterval(sprintf('P%sD', 6 - $dateTime->format('w'))))->format('Y-m-d 23:59:59'), \PHP_EOL;
// 週頭(月:月曜スタートの場合)
$dateTime->setTimestamp($ts);
echo $dateTime->sub(new DateInterval(sprintf('P%sD', $dateTime->format('w') - 1)))->format('Y-m-d 00:00:00'), \PHP_EOL;
// 週末(日:月曜スタートの場合)
$dateTime->setTimestamp($ts);
echo $dateTime->add(new DateInterval(sprintf('P%sD', 7 - $dateTime->format('w'))))->format('Y-m-d 23:59:59'), \PHP_EOL;
手続き型とオブジェクト指向型のパフォーマンス差異
単純ループ(オブジェクト指向側不利)
手続き型 | オブジェクト指向型 |
---|---|
0.20067310333252 | 0.26106715202332 |
<?php
// 基準日の設定(実際の使用シーンでは$ts = time();や$ts = $_SERVER[\'REQUEST_TIME\'];が使用されるはず)',
$base_datetime = '2016-08-11 13:00:00';
// 1万回回す
$range = 10000;
$mts = microtime(true);
for ($i = 0; $i < $range; $i++) {
// 基準となるタイムスタンプの作成
$ts = strtotime($base_datetime);
// 当日開始時
date('Y-m-d 00:00:00', $ts);
// 当日終了時
date('Y-m-d 23:59:59', $ts);
// 月初
date('Y-m-01 00:00:00', $ts);
// 月末
date('Y-m-t 23:59:59', $ts);
// 週頭(日)
date('Y-m-d 00:00:00', strtotime(sprintf('-%s day', date('w', $ts)), $ts));
// 週末(土)
date('Y-m-d 23:59:59', strtotime(sprintf('+%s day', 6 - date('w', $ts)), $ts));
}
echo microtime(true) - $mts, \PHP_EOL;
$mts = microtime(true);
for ($i = 0; $i < $range; $i++) {
// 基準となるDateTimeオブジェクトの作成
$dateTime = new DateTime($base_datetime);
// 復帰用タイムスタンプ
$ts = $dateTime->getTimestamp();
// 当日開始時
$dateTime->format('Y-m-d 00:00:00');
// 当日終了時
$dateTime->format('Y-m-d 23:59:59');
// 月初
$dateTime->format('Y-m-01 00:00:00');
// 月末
$dateTime->format('Y-m-t 00:00:00');
// 週頭(日)
$dateTime->setTimestamp($ts);
$dateTime->sub(new DateInterval(sprintf('P%sD', $dateTime->format('w'))))->format('Y-m-d 00:00:00');
// 週末(土)
$dateTime->setTimestamp($ts);
$dateTime->add(new DateInterval(sprintf('P%sD', 6 - $dateTime->format('w'))))->format('Y-m-d 23:59:59');
}
echo microtime(true) - $mts, \PHP_EOL;
単純ループ(オブジェクト指向側少しチューン)
DateTimeオブジェクトを使いまわすようにした。
手続き型 | オブジェクト指向型 |
---|---|
0.19268608093262 | 0.21537804603577 |
<?php
// 基準日の設定(実際の使用シーンでは$ts = time();や$ts = $_SERVER[\'REQUEST_TIME\'];が使用されるはず)',
$base_datetime = '2016-08-11 13:00:00';
// 1万回回す
$range = 10000;
$mts = microtime(true);
for ($i = 0; $i < $range; $i++) {
// 基準となるタイムスタンプの作成
$ts = strtotime($base_datetime);
// 当日開始時
date('Y-m-d 00:00:00', $ts);
// 当日終了時
date('Y-m-d 23:59:59', $ts);
// 月初
date('Y-m-01 00:00:00', $ts);
// 月末
date('Y-m-t 23:59:59', $ts);
// 週頭(日)
date('Y-m-d 00:00:00', strtotime(sprintf('-%s day', date('w', $ts)), $ts));
// 週末(土)
date('Y-m-d 23:59:59', strtotime(sprintf('+%s day', 6 - date('w', $ts)), $ts));
}
echo microtime(true) - $mts, \PHP_EOL;
$mts = microtime(true);
// 基準となるDateTimeオブジェクトの作成
$dateTime = new DateTime($base_datetime);
for ($i = 0; $i < $range; $i++) {
// ループ対応のため初期化
$dateTime->setTimestamp($ts);
// 復帰用タイムスタンプ
$ts = $dateTime->getTimestamp();
// 当日開始時
$dateTime->format('Y-m-d 00:00:00');
// 当日終了時
$dateTime->format('Y-m-d 23:59:59');
// 月初
$dateTime->format('Y-m-01 00:00:00');
// 月末
$dateTime->format('Y-m-t 00:00:00');
// 週頭(日)
$dateTime->setTimestamp($ts);
$dateTime->sub(new DateInterval(sprintf('P%sD', $dateTime->format('w'))))->format('Y-m-d 00:00:00');
// 週末(土)
$dateTime->setTimestamp($ts);
$dateTime->add(new DateInterval(sprintf('P%sD', 6 - $dateTime->format('w'))))->format('Y-m-d 23:59:59');
}
echo microtime(true) - $mts, \PHP_EOL;
単純ループ(全体的に最適化)
DateTimeオブジェクト、DateIntervalオブジェクトを使いまわすようにした。
その他変数を出来るだけ定数化。
手続き型 | オブジェクト指向型 |
---|---|
0.16357707977295 | 0.23438286781311 |
<?php
// 基準日の設定(実際の使用シーンではTIME_STAMP = time();やTIME_STAMP = $_SERVER[\'REQUEST_TIME\'];が使用されるはず)',
define('BASE_DATETIME', '2016-08-11 13:00:00');
// 基準となるタイムスタンプの作成
define('TIME_STAMP', strtotime(BASE_DATETIME));
// フォーマット
define('DATE_FORMAT_DAY_START', 'Y-m-d 00:00:00');
define('DATE_FORMAT_DAY_END', 'Y-m-d 23:59:59');
define('DATE_FORMAT_MONTH_START', 'Y-m-01 00:00:00');
define('DATE_FORMAT_MONTH_END', 'Y-m-t 23:59:59');
// 1万回回す
$range = 10000;
$mts = microtime(true);
for ($i = 0; $i < $range; $i++) {
// 当日開始時
date(DATE_FORMAT_DAY_START, TIME_STAMP);
// 当日終了時
date(DATE_FORMAT_DAY_END, TIME_STAMP);
// 月初
date(DATE_FORMAT_MONTH_START, TIME_STAMP);
// 月末
date(DATE_FORMAT_MONTH_END, TIME_STAMP);
// 週頭(日)
date(DATE_FORMAT_DAY_START, strtotime(sprintf('-%s day', date('w', TIME_STAMP)), TIME_STAMP));
// 週末(土)
date(DATE_FORMAT_DAY_END, strtotime(sprintf('+%s day', 6 - date('w', TIME_STAMP)), TIME_STAMP));
}
echo microtime(true) - $mts, \PHP_EOL;
$mts = microtime(true);
$dateTime = new DateTime(BASE_DATETIME);
$dateInterval = new DateInterval('P0D');
for ($i = 0; $i < $range; $i++) {
// ループ対応のため初期化
$dateTime->setTimestamp(TIME_STAMP);
// 当日開始時
$dateTime->format(DATE_FORMAT_DAY_START);
// 当日終了時
$dateTime->format(DATE_FORMAT_DAY_END);
// 月初
$dateTime->format(DATE_FORMAT_MONTH_START);
// 月末
$dateTime->format(DATE_FORMAT_MONTH_END);
// 週頭(日)
$dateTime->setTimestamp(TIME_STAMP);
$dateTime->add($dateInterval->createFromDateString(sprintf('-%s day', date('w', TIME_STAMP))))->format(DATE_FORMAT_DAY_START);
// 週末(土)
$dateTime->setTimestamp(TIME_STAMP);
$dateTime->add($dateInterval->createFromDateString(sprintf('+%s day', 6 - date('w', TIME_STAMP))))->format(DATE_FORMAT_DAY_END);
}
echo microtime(true) - $mts, \PHP_EOL;