核心函數實現
取得週範圍(週一至週日)
function getWeekRange($date) {
$ret = [];
$timestamp = strtotime($date);
$w = (int)strftime('%u', $timestamp); // 1=週一 ... 7=週日 (ISO-8601)
$ret['sdate'] = date('Y-m-d 00:00:00', $timestamp - ($w - 1) * 86400); // 週一 00:00
$ret['edate'] = date('Y-m-d 23:59:59', $timestamp + (7 - $w) * 86400); // 週日 23:59
return $ret;
}
取得月範圍
function getMonthRange($date) {
$ret = [];
$timestamp = strtotime($date);
$mdays = (int)date('t', $timestamp); // 當月總天數
$ret['sdate'] = date('Y-m-01 00:00:00', $timestamp); // 1號 00:00
$ret['edate'] = date("Y-m-{$mdays} 23:59:59", $timestamp); // 最後一天 23:59
return $ret;
}
綜合應用:常用日期區間快速取得
function getFilter($type) {
$ret = [];
$today = date('Y-m-d');
switch ($type) {
case 1: // 昨天
$ret['sdate'] = date('Y-m-d 00:00:00', strtotime('-1 day', strtotime($today)));
$ret['edate'] = date('Y-m-d 23:59:59', strtotime('-1 day', strtotime($today)));
break;
case 2: // 本週
$ret = getWeekRange($today);
break;
case 3: // 上週
$ret = getWeekRange(date('Y-m-d', strtotime('-1 week', strtotime($today))));
break;
case 4: // 上上週
$ret = getWeekRange(date('Y-m-d', strtotime('-2 week', strtotime($today))));
break;
case 5: // 本月
$ret = getMonthRange($today);
break;
case 6: // 上月
$ret = getMonthRange(date('Y-m-d', strtotime('-1 month', strtotime($today))));
break;
}
return $ret;
}
使用範例
// 本週範圍
print_r(getFilter(2));
/*
Array
(
[sdate] => 2024-12-23 00:00:00
[edate] => 2024-12-29 23:59:59
)
*/
// 上月範圍
print_r(getFilter(6));
/*
Array
(
[sdate] => 2024-11-01 00:00:00
[edate] => 2024-11-30 23:59:59
)
*/
關鍵技術點解析
| 函數/常數 | 說明 |
strftime('%u') | ISO-8601 週幾數字:1=週一 ... 7=週日,跨平台一致 |
date('t') | 取得指定月份總天數(自動處理閏年) |
86400 | 一天秒數 (24*60*60),用於日期加減運算 |
strtotime('-1 week') | 相對時間字串解析,支援 'monday this week' 等自然語言 |
進階改良版(支援自定義週起始日)
function getWeekRangeEx($date, $weekStart = 1) {
// $weekStart: 1=週一, 0=週日 (美式)
$ts = strtotime($date);
$w = (int)date('w', $ts); // 0=週日 ... 6=週六
// 轉換為 1=週一 基準
$w = $w === 0 ? 7 : $w;
$diff = $w - $weekStart;
if ($diff < 0) $diff += 7;
$start = date('Y-m-d 00:00:00', $ts - $diff * 86400);
$end = date('Y-m-d 23:59:59', $ts + (6 - $diff) * 86400);
return compact('start', 'end');
}
常見陷阱與注意事項
- 時區一致性:確保
date_default_timezone_set() 與資料庫/業務時區一致,否則跨天邊界計算會偏移
- strtotime 相對語法:
'-1 month' 在 3/31 會回到 2/28/29,非固定 30 天,月份邏輯以 date('t') 為準
strftime('%u') 需 PHP 編譯支援:極少數精簡版 PHP 可能缺失,可改用 date('N') (PHP 5.1+)
- 效能優化:大量日期計算建議改用
DateTime / DatePeriod 物件導向 API,避免重複 strtotime 解析開銷
DateTime 物件導向重寫(推薦 PHP 5.3+)
function getWeekRangeDT($date) {
$dt = new DateTime($date);
$dt->modify('monday this week')->setTime(0,0,0);
$start = clone $dt;
$end = clone $dt->modify('sunday this week')->setTime(23,59,59);
return ['sdate' => $start->format('Y-m-d H:i:s'), 'edate' => $end->format('Y-m-d H:i:s')];
}
function getMonthRangeDT($date) {
$dt = new DateTime($date);
$start = clone $dt->modify('first day of this month')->setTime(0,0,0);
$end = clone $dt->modify('last day of this month')->setTime(23,59,59);
return ['sdate' => $start->format('Y-m-d H:i:s'), 'edate' => $end->format('Y-m-d H:i:s')];
}