常見需求:報表查詢、帳單週期、排程任務需確定「某月的起始 00:00:00」與「結束 23:59:59」。本文提供可直接複製的工具函數,支援任意日期字串輸入。
<?php
/**
* 取得指定日期所在月份的起始或結束日期時間
*
* @param string $date 日期字串,支援 strtotime() 所有格式 (如 '2023-05-15', 'next month', '-1 month')
* @param bool $first true 回傳月初 00:00:00,false 回傳月末 23:59:59
* @return string 格式化日期時間字串 'Y-m-d H:i:s'
*/
function getMonthRange($date, $first = true) {
$timestamp = strtotime($date);
if ($timestamp === false) {
throw new InvalidArgumentException("無效日期格式: $date");
}
if ($first) {
// 月初第一天 00:00:00
return date('Y-m-01 00:00:00', $timestamp);
} else {
// 月末最後一天 23:59:59
// date('t') 取得該月總天數
$lastDay = date('t', $timestamp);
return date("Y-m-{$lastDay} 23:59:59", $timestamp);
}
}
// 別名函數,語意更清晰
function getMonthStart($date) { return getMonthRange($date, true); }
function getMonthEnd($date) { return getMonthRange($date, false); }
?>
<?php
// 當前月
echo "本月開始: " . getMonthStart('now') . "\n"; // 2023-10-01 00:00:00
echo "本月結束: " . getMonthEnd('now') . "\n"; // 2023-10-31 23:59:59
// 指定日期
echo "2023-02-15 所在月開始: " . getMonthStart('2023-02-15') . "\n"; // 2023-02-01 00:00:00
echo "2023-02-15 所在月結束: " . getMonthEnd('2023-02-15') . "\n"; // 2023-02-28 23:59:59 (平年)
// 相對日期
echo "上個月開始: " . getMonthStart('-1 month') . "\n";
echo "下個月結束: " . getMonthEnd('+1 month') . "\n";
// 直接用於 SQL 查詢
$start = getMonthStart('2023-06-10');
$end = getMonthEnd('2023-06-10');
$sql = "SELECT * FROM orders WHERE created_at BETWEEN '$start' AND '$end'";
// 結果: WHERE created_at BETWEEN '2023-06-01 00:00:00' AND '2023-06-30 23:59:59'
?>
<?php
function getMonthRangeDateTime($date, $first = true) {
$dt = new DateTime($date);
if ($first) {
$dt->modify('first day of this month')->setTime(0, 0, 0);
} else {
$dt->modify('last day of this month')->setTime(23, 59, 59);
}
return $dt; // 回傳 DateTime 物件,可直接 format、diff、比較
}
// 使用
$start = getMonthRangeDateTime('2023-02-15', true);
$end = getMonthRangeDateTime('2023-02-15', false);
echo $start->format('Y-m-d H:i:s') . "\n"; // 2023-02-01 00:00:00
echo $end->format('Y-m-d H:i:s') . "\n"; // 2023-02-28 23:59:59
// 直接比較
if ($someDate >= $start && $someDate <= $end) { /* 在本月內 */ }
?>
| 輸入 | 月初輸出 | 月末輸出 | 說明 |
|---|---|---|---|
| 2024-02-29 (閏年) | 2024-02-01 00:00:00 | 2024-02-29 23:59:59 | 正確處理 2 月 29 天 |
| 2023-02-28 (平年) | 2023-02-01 00:00:00 | 2023-02-28 23:59:59 | 正確處理 2 月 28 天 |
| 2023-12-31 | 2023-12-01 00:00:00 | 2023-12-31 23:59:59 | 跨年無問題 |
| first day of January 2000 | 2000-01-01 00:00:00 | 2000-01-31 23:59:59 | 支援文字描述 |
date('Y-m-d', strtotime('last day of')) 在某些舊 PHP 版本不支援,建議用 date('t') 取得天數最穩健。BETWEEN 包含邊界,若欄位為 DATETIME 精度到秒,23:59:59 正確;若為 TIMESTAMP 或更高精度,建議用 < '2023-03-01 00:00:00' 開區間寫法。strtotime 使用預設時區 (date_default_timezone_set),跨時區應用建議統一用 UTC 存儲,顯示時轉換。