根據 ISO-8601 標準,一年有 52 或 53 週,週一為每週第一天。需求:獲取指定年份總週數、指定週的起止日期、當前日期所屬週範圍。
date('W') + strtotime(簡潔實用)function getYearWeeks($year) {
// 12 月 28 日必在該年第 52 或 53 週
return (int)date('W', strtotime("$year-12-28"));
}
function getWeekRange($year, $week) {
$weeks = getYearWeeks($year);
if ($week < 1 || $week > $weeks) $week = 1;
$week = str_pad($week, 2, '0', STR_PAD_LEFT);
// ISO 週日期格式:YYYY-Www
$start = strtotime("$year-W$week"); // 週一 00:00:00
$end = strtotime("+6 days", $start); // 週日 23:59:59
return [
'start_ts' => $start,
'end_ts' => $end,
'start' => date('Y-m-d', $start),
'end' => date('Y-m-d', $end),
];
}
// 示例
echo "2023 年共 " . getYearWeeks(2023) . " 週\n"; // 52
print_r(getWeekRange(2023, 1));
/* Array(
[start_ts] => 1672502400
[end_ts] => 1673020799
[start] => 2023-01-02
[end] => 2023-01-08
) */
DateTime 面向對象(更健壯、支持時區)function getIsoWeeksInYear($year) {
$dt = new DateTime();
$dt->setISODate($year, 53); // 嘗試設置第 53 週
return $dt->format('W') === '53' ? 53 : 52;
}
function getWeekRangeDT($year, $week, $timezone = 'Asia/Shanghai') {
$dt = new DateTime(null, new DateTimeZone($timezone));
$dt->setISODate($year, $week); // 自動校正週數
$dt->setTime(0, 0, 0);
$start = clone $dt;
$end = clone $dt;
$end->modify('+6 days')->setTime(23, 59, 59);
return [
'start' => $start->format('Y-m-d'),
'end' => $end->format('Y-m-d'),
'start_ts' => $start->getTimestamp(),
'end_ts' => $end->getTimestamp(),
];
}
// 獲取當前日期所屬週範圍
function getCurrentWeekRange($timezone = 'Asia/Shanghai') {
$dt = new DateTime(null, new DateTimeZone($timezone));
$year = (int)$dt->format('o'); // ISO 年份
$week = (int)$dt->format('W');
return getWeekRangeDT($year, $week, $timezone);
}
| 特性 | date/strtotime | DateTime |
|---|---|---|
| 時區處理 | 依賴 date_default_timezone_set | 對象級時區,互不干擾 |
| 跨年週處理 | 需手動邏輯 | setISODate 自動處理 |
| 性能 | 極快 | 略慢(對象開銷) |
| 可讀性 | 字符串魔法 | 語義清晰 |
| 推薦場景 | 簡單腳本、高頻調用 | 框架項目、多時區、國際化 |
class WeekHelper {
public static function weeksInYear($year) {
$dt = new DateTime();
$dt->setISODate($year, 53);
return $dt->format('W') === '53' ? 53 : 52;
}
public static function range($year, $week, $tz = 'Asia/Shanghai') {
$dt = new DateTime(null, new DateTimeZone($tz));
$dt->setISODate($year, $week);
$dt->setTime(0,0,0);
$s = clone $dt;
$e = clone $dt;
$e->modify('+6 days')->setTime(23,59,59);
return [
'year' => $year, 'week' => $week,
'start' => $s->format('Y-m-d'), 'end' => $e->format('Y-m-d'),
'start_ts' => $s->getTimestamp(), 'end_ts' => $e->getTimestamp(),
];
}
public static function current($tz = 'Asia/Shanghai') {
$dt = new DateTime(null, new DateTimeZone($tz));
return self::range((int)$dt->format('o'), (int)$dt->format('W'), $tz);
}
}
// 使用
print_r(WeekHelper::current());
print_r(WeekHelper::range(2024, 1));