核心函式
<?php
/**
* 取得日期區間列表 (含起迄日)
* @param string|DateTime $start 開始日期
* @param string|DateTime $end 結束日期
* @return array ['dates'=>[], 'weeks'=>[], 'timestamps'=>[]]
*/
function getDateRange($start, $end): array {
$start = $start instanceof DateTime ? $start : new DateTime($start);
$end = $end instanceof DateTime ? $end : new DateTime($end);
if ($end < $start) throw new InvalidArgumentException('End date must >= start date');
// 結束日需 +1 天才會被 DatePeriod 包含
$end->modify('+1 day');
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
$dates = [];
$weeks = [];
$stamps = [];
foreach ($period as $dt) {
$dates[] = $dt->format('Y-m-d');
$weeks[] = ['日','一','二','三','四','五','六'][$dt->format('w')];
$stamps[] = $dt->getTimestamp();
}
return compact('dates', 'weeks', 'stamps');
}
// 使用
$range = getDateRange('2024-01-01', '2024-01-10');
/*
$range['dates'] = ['2024-01-01','2024-01-02',...,'2024-01-10']
$range['weeks'] = ['一','二','三','四','五','六','日','一','二','三']
$range['stamps'] = [1704038400, 1704124800, ...]
*/
直接輸出 HTML 表格 (行事曆樣式)
function renderCalendarTable(string $start, string $end): string {
$range = getDateRange($start, $end);
$html = '| 日期 | 星期 | 時間戳 |
';
foreach ($range['dates'] as $i => $date) {
$html .= "| $date | {$range['weeks'][$i]} | {$range['stamps'][$i]} |
";
}
$html .= '
';
return $html;
}
echo renderCalendarTable('2024-01-01', '2024-01-31');
應用:行事曆事件標記
// 假設資料庫有 events 表:event_date, title
$events = $pdo->query("SELECT event_date, title FROM events
WHERE event_date BETWEEN '$start' AND '$end'")->fetchAll(PDO::FETCH_KEY_PAIR);
$html = '';
foreach ($period as $dt) {
$dateStr = $dt->format('Y-m-d');
$eventHtml = isset($events[$dateStr]) ? "{$events[$dateStr]}" : '';
$html .= "| $dateStr ($week) $eventHtml | ";
}
$html .= '
';
進階:自定間隔 (每週、每月)
// 每週一
$period = new DatePeriod($start, new DateInterval('P1W'), $end);
// 每月 1 號
$period = new DatePeriod($start, new DateInterval('P1M'), $end);
// 自定義:每 3 天
$period = new DatePeriod($start, new DateInterval('P3D'), $end);
注意事項
DatePeriod 不包含結束日,需 modify('+1 day')
- 跨時區/夏令時間正確性:使用
DateTimeZone 明確指定
- 大區間 (如 10 年) 記憶體較大,可改用 Generator 逐個產出