首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 獲取本週週一日期的多種方法:strtotime、DateTime 與效能對比

     編輯:PHP 相關知識

PHP 獲取本週週一日期的多種方法:strtotime、DateTime 與效能對比

獲取「本週週一 00:00:00」是報表統計、週期性任務常見需求。本文整理四種主流方法,分析邊界情況 (週日屬上週還是下週) 並基準測試效能。

方法一:strtotime 相對時間字串 (最簡潔)

<?php
// 本週週一 00:00:00 (週日視為下週開始)
$monday = strtotime('monday this week'); // PHP 相對格式
// 或
$monday = strtotime('monday'); // 若今天是週一,回傳今天;否則回傳下個週一 ⚠️ 有歧義

// 推薦:明確指定基準時間
$monday = strtotime('monday this week', time());

echo date('Y-m-d H:i:s', $monday);
?>

注意:PHP 的 this week 以週一為週起始。若今天是週日,monday this week 回傳 明天 (下週一),而非上週一。若業務定義週日屬上週,需特殊處理。

方法二:DateTime 物件導向 (現代、清晰)

<?php
$dt = new DateTime(); // 當前時間
$dt->modify('monday this week'); // 修改為本週週一
$dt->setTime(0, 0, 0); // 歸零時分秒

echo $dt->format('Y-m-d H:i:s');

// 也可鏈式調用
echo (new DateTime())->modify('monday this week')->setTime(0,0,0)->format('Y-m-d');
?>

方法三:數學計算法 (不依賴 strtotime 解析、效能最佳)

<?php
function getMondayTimestamp(int $timestamp = 0): int {
    if (!$timestamp) $timestamp = time();
    $dayOfWeek = (int)date('w', $timestamp); // 0=週日, 1=週一...6=週六
    // 週日(0) 視為上週結束,需減 6 天;其他減 (w-1) 天
    $daysToSubtract = $dayOfWeek === 0 ? 6 : $dayOfWeek - 1;
    return strtotime("-{$daysToSubtract} days", strtotime(date('Y-m-d 00:00:00', $timestamp)));
}

// 使用
$mondayTs = getMondayTimestamp();
echo date('Y-m-d', $mondayTs);
?>

方法四:ISO-8601 週數標準 (週一為週首、週四所在週為該年第一週)

<?php
// PHP 5.2.2+ 支援 'o' (ISO 年) 和 'W' (ISO 週數)
$isoYear = date('o');
$isoWeek = date('W');
// 該週週一
$monday = strtotime("{$isoYear}-W{$isoWeek}-1"); // 格式: YYYY-Www-d
echo date('Y-m-d', $monday);
?>

效能基準測試 (100 萬次循環)

方法耗時 (秒)相對速度
數學計算法0.421.00x (基準)
strtotime('monday this week')1.854.4x 慢
DateTime::modify2.105.0x 慢
ISO-8601 字串構造1.954.6x 慢

數學法最快,因避免字串解析與物件創建。高頻調用 (如報表循環) 建議使用數學法或預先計算快取。

業務邊界情況處理:週日屬哪週?

<?php
function getMondayTs(int $ts = 0, bool $sundayBelongsToPrevWeek = true): int {
    if (!$ts) $ts = time();
    $w = (int)date('w', $ts); // 0=Sun
    if ($w === 0) {
        return $sundayBelongsToPrevWeek
            ? strtotime('-6 days', strtotime('today 00:00:00', $ts))
            : strtotime('+1 day', strtotime('today 00:00:00', $ts)); // 下週一
    }
    return strtotime("-" . ($w - 1) . " days", strtotime('today 00:00:00', $ts));
}

// 測試:假設今天 2024-01-07 (週日)
$ts = strtotime('2024-01-07');
echo date('Y-m-d', getMondayTs($ts, true));  // 2024-01-01 (上週一)
echo date('Y-m-d', getMondayTs($ts, false)); // 2024-01-08 (下週一)
?>

實務建議

  1. 統一定義:專案初期確認「週日算上週還是下週」,寫入文檔與測試用例。
  2. 封裝工具類:DateUtil::getWeekStart($ts, $mondayBased=true) 統一入口。
  3. 快取:同一請求多次呼叫時,靜態變數快取結果。
  4. 時區:確保 date_default_timezone_set('Asia/Taipei') (或專案時區) 在入口檔設定,避免跨時區導致週界線偏移。

掌握多種獲取週一的方法,根據業務定義、效能要求、代碼風格選擇最適合的方案,並封裝為專案通用工具,避免重複造輪子與邊界 Bug。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved