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

PHP 取得年度每週起始與結束日期:ISO-8601 週編號標準實作

     編輯:PHP 相關知識

需求背景

周報系統、考勤統計、財務結算常需「第 N 週的起迄日期」。PHP date('W') 遵循 ISO-8601:週一為週首日,首週包含該年第一個週四。

標準實作函式

<?php
/**
 * 取得指定年份每週的起始(週一)與結束(週日)日期
 *
 * @param int $year 年份,如 2024
 * @return array 索引 1~52/53,值為 ['start'=>'Y-m-d', 'end'=>'Y-m-d']
 */
function getYearWeeks(int $year): array
{
    // 1. 找出該年第一個週一
    $firstDayOfYear = new DateTime("$year-01-01");
    $firstMonday = clone $firstDayOfYear;
    $firstMonday->modify('monday this week'); // 若 1/1 是週一則不動,否則往前推到上週一
    
    // 修正:ISO-8601 首週定義 = 包含第一個週四的那一週
    // 簡化做法:若 1/1 是週五/六/日,則第一週實際從下週一開始
    $dow = (int)$firstDayOfYear->format('N'); // 1=週一 ... 7=週日
    if ($dow > 4) { // 週五、六、日
        $firstMonday->modify('next monday');
    }
    
    // 2. 找出該年最後一個週日
    $lastDayOfYear = new DateTime("$year-12-31");
    $lastSunday = clone $lastDayOfYear;
    $lastSunday->modify('sunday this week'); // 若 12/31 是週日則不動,否則往後推到本週日
    
    $dowEnd = (int)$lastDayOfYear->format('N');
    if ($dowEnd < 7) { // 週一~週六
        $lastSunday->modify('next sunday');
    }
    
    // 3. 計算總週數
    $totalWeeks = (int)$lastSunday->format('W');
    if ($totalWeeks === 0) $totalWeeks = 1; // 邊界情況
    
    // 4. 產生每週區間
    $weeks = [];
    for ($i = 1; $i <= $totalWeeks; $i++) {
        $start = clone $firstMonday;
        $start->modify("+".($i-1)." weeks");
        
        $end = clone $start;
        $end->modify('+6 days');
        
        // 不超過該年最後一天
        if ($end > $lastDayOfYear) {
            $end = clone $lastDayOfYear;
        }
        
        $weeks[$i] = [
            'start' => $start->format('Y-m-d'),
            'end'   => $end->format('Y-m-d'),
            'label' => "第 {$i} 週",
        ];
    }
    
    return $weeks;
}

// === 使用範例 ===
$weeks2024 = getYearWeeks(2024);

echo "2024 年週曆:\n";
foreach ($weeks2024 as $num => $week) {
    printf("第 %2d 週: %s ~ %s\n", $num, $week['start'], $week['end']);
}

// 取得特定週
$week18 = $weeks2024[18] ?? null;
if ($week18) {
    echo "\n第 18 週: {$week18['start']} ~ {$week18['end']}";
}

輸出範例(2024 年)

2024 年週曆:
第  1 週: 2024-01-01 ~ 2024-01-07
第  2 週: 2024-01-08 ~ 2024-01-14
...
第 18 週: 2024-04-29 ~ 2024-05-05
...
第 52 週: 2024-12-23 ~ 2024-12-29
第 53 週: 2024-12-30 ~ 2024-12-31

ISO-8601 週編號規則速記

  • 週一為週首日(N=1),週日為週尾日(N=7)。
  • 每年第一週 = 包含該年第一個週四的那一週(等價:1 月 4 日所在週)。
  • 一年有 52 或 53 週。
  • 跨年週屬於「包含多數天數的那一年」。

替代方案:strtotime 字串解析(簡潔但依賴字串)

function getWeekRangeStr(int $year, int $week): ?array
{
    if ($week < 1 || $week > 53) return null;
    
    $monday = strtotime("{$year}-W" . str_pad($week, 2, '0', STR_PAD_LEFT) . '-1');
    $sunday = strtotime("+6 days", $monday);
    
    // 驗證是否仍在該年內(跨年週處理)
    $mondayYear = (int)date('Y', $monday);
    if ($mondayYear !== $year && $week !== 1) return null;
    
    return [
        'start' => date('Y-m-d', $monday),
        'end'   => date('Y-m-d', $sunday),
    ];
}

// 使用
var_dump(getWeekRangeStr(2024, 18));
// ['start'=>'2024-04-29', 'end'=>'2024-05-05']

進階:支援自訂週首日(如美國週日制)

function getWeeksCustom(int $year, int $weekStart = 1): array // 1=週一, 0=週日
{
    $weeks = [];
    $date = new DateTime("$year-01-01");
    
    // 找第一個符合週首日的日期
    while ((int)$date->format('w') !== $weekStart) {
        $date->modify('+1 day');
    }
    
    $endOfYear = new DateTime("$year-12-31");
    $weekNum = 1;
    
    while ($date <= $endOfYear) {
        $start = clone $date;
        $end = clone $date;
        $end->modify('+6 days');
        if ($end > $endOfYear) $end = clone $endOfYear;
        
        $weeks[$weekNum++] = [
            'start' => $start->format('Y-m-d'),
            'end'   => $end->format('Y-m-d'),
        ];
        $date->modify('+7 days');
    }
    return $weeks;
}

總結

  • 推薦使用 DateTime 物件導向寫法,型別安全、可讀性高、自動處理閏年/時區。
  • ISO-8601 為國際標準,符合多數商業系統需求;若業務需週日制,使用自訂版本。
  • 回傳結構化陣列(含 start/end/label),方便前端直接渲染表格或下拉選單。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved