首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 獲取今天/本月/上月/今年起止時間戳的高效代碼

     編輯:PHP 綜合知識

核心實現:mktime 組合策略

<?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)

當前 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

現代化封裝:DateTime 版本 (PHP 5.2+)

<?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() 函數
  • 時區一致性:應用層、資料庫層、系統層統一使用 UTC 存儲,展示層轉換
  • 預計算常用周期:定時任務每日生成統計表,查詢直接讀取

擴展:任意周期計算工具類

<?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(),
        ];
    }
}

掌握時間邊界計算,是報表統計、定時任務、數據分片的基礎技能!

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved