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

PHP 計算指定日期區間內的週與月範圍:DateRange 工具類

     編輯:PHP 相關知識

PHP 計算指定日期區間內的週與月範圍

報表、統計、排程常需將日期區間按**自然週 (週一~週日)** 或**自然月 (1號~月末)** 切分。封裝可復用工具類,處理邊界、閏年、跨年等細節。

DateRange 工具類

<?php
class DateRange {
    /**
     * 取得日期所屬自然週範圍 (週一 00:00:00 ~ 週日 23:59:59)
     * @param string $date 'Y-m-d'
     * @return array ['start' => 'Y-m-d', 'end' => 'Y-m-d']
     */
    public static function weekRange(string $date): array {
        $ts = strtotime($date);
        if ($ts === false) throw new InvalidArgumentException("Invalid date: $date");
        // ISO-8601: 1=週一 ... 7=週日
        $dow = (int)date('N', $ts);
        $start = date('Y-m-d', $ts - ($dow - 1) * 86400);
        $end = date('Y-m-d', $ts + (7 - $dow) * 86400);
        return ['start' => $start, 'end' => $end];
    }

    /**
     * 取得日期所屬自然月範圍 (1號 00:00:00 ~ 月末 23:59:59)
     */
    public static function monthRange(string $date): array {
        $ts = strtotime($date);
        if ($ts === false) throw new InvalidArgumentException("Invalid date: $date");
        $start = date('Y-m-01', $ts);
        $end = date('Y-m-t', $ts); // 't' = 月份天數
        return ['start' => $start, 'end' => $end];
    }

    /**
     * 取得區間內所有自然週 (不重疊、連續覆蓋)
     * @param string $startDate 'Y-m-d'
     * @param string $endDate   'Y-m-d'
     * @return array [[start,end], ...]
     */
    public static function weeksInRange(string $startDate, string $endDate): array {
        $startTs = strtotime($startDate);
        $endTs = strtotime($endDate);
        if ($startTs > $endTs) throw new InvalidArgumentException('Start date after end date');

        $weeks = [];
        $current = $startDate;
        while (true) {
            $range = self::weekRange($current);
            $weeks[] = $range;
            if ($range['end'] >= $endDate) break;
            // 移至下週一
            $current = date('Y-m-d', strtotime($range['end'] . ' +1 day'));
        }
        return $weeks;
    }

    /**
     * 取得區間內所有自然月
     */
    public static function monthsInRange(string $startDate, string $endDate): array {
        $startTs = strtotime($startDate);
        $endTs = strtotime($endDate);
        if ($startTs > $endTs) throw new InvalidArgumentException('Start date after end date');

        $months = [];
        $current = $startDate;
        while (true) {
            $range = self::monthRange($current);
            $months[] = $range;
            if ($range['end'] >= $endDate) break;
            // 移至下月 1 號
            $current = date('Y-m-d', strtotime($range['start'] . ' +1 month'));
        }
        return $months;
    }

    /** 格式化輸出 "m-d ~ m-d" */
    public static function formatRange(array $range): string {
        return date('m-d', strtotime($range['start'])) . ' ~ ' . date('m-d', strtotime($range['end']));
    }
}
?>

使用範例

<?php
require 'DateRange.php';

// 1. 單一日期查詢
$week = DateRange::weekRange('2024-11-05');
echo "Week: " . DateRange::formatRange($week) . "\n"; // 11-04 ~ 11-10

$month = DateRange::monthRange('2024-02-15');
echo "Month: " . DateRange::formatRange($month) . "\n"; // 02-01 ~ 02-29 (閏年)

// 2. 區間查詢
$weeks = DateRange::weeksInRange('2024-11-01', '2024-11-30');
echo "November weeks:\n";
foreach ($weeks as $w) {
    echo "  " . DateRange::formatRange($w) . "\n";
}
// 輸出:
//   10-28 ~ 11-03
//   11-04 ~ 11-10
//   11-11 ~ 11-17
//   11-18 ~ 11-24
//   11-25 ~ 12-01 (跨月週正確包含)

$months = DateRange::monthsInRange('2024-01-15', '2024-03-20');
echo "Months:\n";
foreach ($months as $m) {
    echo "  " . DateRange::formatRange($m) . "\n";
}
// 01-01 ~ 01-31
// 02-01 ~ 02-29
// 03-01 ~ 03-31
?>

關鍵實作細節

  • 自然週定義:採用 ISO-8601 (週一起始),`date('N')` 回傳 1-7。若業務需週日起始,調整 `$dow` 計算邏輯。
  • 邊界包含性**:`weeksInRange` 回傳的週範圍**完整覆蓋**輸入區間,首尾週可能超出原始開始/結束日期 (見範例 11 月底跨到 12/1),符合「自然週」語意。
  • 月份跨年**:`strtotime('+1 month')` 自動處理 12 月 → 翌年 1 月。
  • 效能**:純日期運算,無資料庫查詢,極快。大區間 (如 10 年) 迴圈次數約 520 週 / 120 月,毫秒級完成。
  • 時區**:預設使用腳本預設時區 (`date_default_timezone_set()`)。跨時區應用建議統一 UTC 存儲、顯示時轉換。

擴充:輸出 DatePeriod 物件 (PHP 5.3+)

// 產生週期間迭代器 (每週一)
$period = new DatePeriod(
    new DateTime('2024-11-01'),
    new DateInterval('P1W'), // 1 週
    (new DateTime('2024-11-30'))->modify('+1 day') // 結束開區間
);
foreach ($period as $dt) {
    echo $dt->format('Y-m-d') . "\n"; // 每週一日期
}

此工具類解決「日期區間按週/月切分」的通用需求,代碼精簡、無依賴、易測試,可直接納入專案共用庫。

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