14
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHPにおける翌週、先週、翌月、先月の取得方法

Last updated at Posted at 2016-08-08

正直、オブジェクト指向で記述するのは結構大変。
当面の間は手続き型のみで記述した方が安全そう。

日の差分を出すだけならオブジェクト指向の方が楽なんだけどね。

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;

14
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?