<?php
$t = time(); // 當前時間戳
// 起始時間 (00:00:00)
$todayStart = mktime(0, 0, 0, date('m', $t), date('d', $t), date('Y', $t));
$monthStart = mktime(0, 0, 0, date('m', $t), 1, date('Y', $t));
$lastMonthStart = mktime(0, 0, 0, date('m', $t) - 1, 1, date('Y', $t));
$yearStart = mktime(0, 0, 0, 1, 1, date('Y', $t));
// 結束時間 (23:59:59)
$todayEnd = mktime(23, 59, 59, date('m', $t), date('d', $t), date('Y', $t));
$monthEnd = mktime(23, 59, 59, date('m', $t), date('t', $t), date('Y', $t));
// 上月結束需用上月時間戳計算天數
$lastMonthEnd = mktime(23, 59, 59, date('m', $t) - 1, date('t', $lastMonthStart), date('Y', $t));
$yearEnd = mktime(23, 59, 59, 12, 31, date('Y', $t));
| 函數 | 用途 | 關鍵參數 |
|---|---|---|
date('t', $ts) | 獲取月份天數 | 自動處理閏年、大小月 |
mktime(h,i,s,m,d,Y) | 構造時間戳 | 月份可超出 1-12 自動進位 |
date('m', $ts) - 1 | 上月月份 | 1月會變為 0,mktime 自動處理為上年 12月 |
當前 2011-05-24 15:42:55 1306222975 今天起點 2011-05-24 00:00:00 1306166400 今月起點 2011-05-01 00:00:00 1304179200 上月起點 2011-04-01 00:00:00 1301587200 今年起點 2011-01-01 00:00:00 1293811200 今天終點 2011-05-24 23:59:59 1306252799 今月終點 2011-05-31 23:59:59 1306857599 上月終點 2011-04-30 23:59:59 1304179199 今年終點 2011-12-31 23:59:59 1325347199
<?php
function getPeriodBounds(string $period = 'today', ?DateTimeZone $tz = null): array
{
$now = new DateTime('now', $tz ?? new DateTimeZone('Asia/Shanghai'));
return match ($period) {
'today' => [
'start' => (clone $now)->setTime(0, 0, 0),
'end' => (clone $now)->setTime(23, 59, 59),
],
'month' => [
'start' => (clone $now)->modify('first day of this month')->setTime(0, 0, 0),
'end' => (clone $now)->modify('last day of this month')->setTime(23, 59, 59),
],
'last_month' => [
'start' => (clone $now)->modify('first day of last month')->setTime(0, 0, 0),
'end' => (clone $now)->modify('last day of last month')->setTime(23, 59, 59),
],
'year' => [
'start' => (clone $now)->modify('first day of January')->setTime(0, 0, 0),
'end' => (clone $now)->modify('last day of December')->setTime(23, 59, 59),
],
default => throw new InvalidArgumentException("未知周期: $period"),
};
}
// 使用
$bounds = getPeriodBounds('month');
echo "本月開始: " . $bounds['start']->format('Y-m-d H:i:s') . "\n";
echo "本月結束: " . $bounds['end']->format('Y-m-d H:i:s') . "\n";
echo "時間戳: " . $bounds['start']->getTimestamp() . " ~ " . $bounds['end']->getTimestamp() . "\n";
<?php
// MySQL 查詢今天數據
$todayStart = mktime(0,0,0, date('m'), date('d'), date('Y'));
$todayEnd = mktime(23,59,59, date('m'), date('d'), date('Y'));
$sql = "SELECT * FROM orders
WHERE created_at BETWEEN FROM_UNIXTIME($todayStart) AND FROM_UNIXTIME($todayEnd)";
// 或使用 DATE() 函數 (利用索引需建立函數索引)
$sql = "SELECT * FROM orders WHERE DATE(created_at) = CURDATE()";
// PDO 參數綁定
$stmt = $pdo->prepare("SELECT * FROM logs WHERE created_at BETWEEN ? AND ?");
$stmt->execute([$todayStart, $todayEnd]);
$todayStart = $_SERVER['REQUEST_TIME'] - ($_SERVER['REQUEST_TIME'] % 86400);created_at >= ? AND created_at < ? 範圍查詢,而非 DATE() 函數<?php
class DatePeriodHelper
{
public static function getBounds(string $period, ?DateTime $base = null, ?DateTimeZone $tz = null): array
{
$base = $base ?? new DateTime('now', $tz ?? new DateTimeZone('UTC'));
$tz = $tz ?? $base->getTimezone();
$start = clone $base;
$end = clone $base;
switch ($period) {
case 'today':
$start->setTime(0,0,0);
$end->setTime(23,59,59);
break;
case 'yesterday':
$start->modify('-1 day')->setTime(0,0,0);
$end->modify('-1 day')->setTime(23,59,59);
break;
case 'week':
$start->modify('monday this week')->setTime(0,0,0);
$end->modify('sunday this week')->setTime(23,59,59);
break;
case 'last_week':
$start->modify('monday last week')->setTime(0,0,0);
$end->modify('sunday last week')->setTime(23,59,59);
break;
case 'month':
$start->modify('first day of this month')->setTime(0,0,0);
$end->modify('last day of this month')->setTime(23,59,59);
break;
case 'last_month':
$start->modify('first day of last month')->setTime(0,0,0);
$end->modify('last day of last month')->setTime(23,59,59);
break;
case 'quarter':
$month = (int)$base->format('n');
$qStart = (int)(ceil($month/3)*3 - 2);
$start->setDate($base->format('Y'), $qStart, 1)->setTime(0,0,0);
$end->setDate($base->format('Y'), $qStart+2, (int)date('t', mktime(0,0,0,$qStart+2,1,$base->format('Y'))))->setTime(23,59,59);
break;
case 'year':
$start->setDate($base->format('Y'), 1, 1)->setTime(0,0,0);
$end->setDate($base->format('Y'), 12, 31)->setTime(23,59,59);
break;
default:
throw new InvalidArgumentException("Unsupported period: $period");
}
return [
'start' => $start,
'end' => $end,
'start_ts' => $start->getTimestamp(),
'end_ts' => $end->getTimestamp(),
];
}
}
掌握時間邊界計算,是報表統計、定時任務、數據分片的基礎技能!