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

PHP strtotime() 函數深度解析:用法、原理與「-1 month」陷阱

     編輯:PHP 相關知識

strtotime() 是 PHP 核心日期時間處理函數,能將英文文本日期解析為 Unix 時間戳。但其「相對月份計算」行為常讓開發者踩坑——特別是 strtotime('-1 month') 在月底日期會產生非預期結果。本文從源碼層面剖析原理,並給出最佳實踐。

常用相對時間語法速查

語法說明示例輸出(基準 2011-03-31)
feb / February指定月份的今天,不存在則順延2011-03-03(2月無31日,順延至3月3日)
first sunday當月第一個星期日2011-01-02
previous sunday指定日期前最近的星期日2011-01-30(基準 2011-02-01)
last day當月最後一天2000-02-29(閏年)
back of 24指定小時後 15 分(24 視為翌日凌晨)2011-02-02 00:15:00
front of 0指定小時前 45 分(0 視為前日 23:45)2011-01-31 23:45:00

源碼級原理:ext/date/lib/parse_date.re

PHP 使用 re2c 詞法分析器解析日期字符串。核心結構體:

  • timelib_time:存儲年月日時分秒、時區、相對偏移量(relative 字段)。
  • timelib_rel_time:相對時間偏移(年/月/日/時/分/秒、星期行為、first/last 標記等)。

解析 yesterday 時,匹配規則執行:

'yesterday' { TIMELIB_INIT; TIMELIB_HAVE_RELATIVE(); s->time->relative.d = -1; return TIMELIB_RELATIVE; }

最終由 timelib_fill_holes() 填充缺失字段,timelib_update_ts() 計算最終時間戳。

「-1 month」失效根因

當輸入 -1 month,解析器識別 relnumber = -1、reltextunit = month,執行:

case TIMELIB_MONTH: s->time->relative.m += amount * multiplier; break; // m = -1

關鍵點:此處僅修改「相對月份偏移量」,不觸碰日字段。後續計算時間戳時,若基準日為 31 號、目標月無 31 日,PHP 採用「順延到下月對應日期」策略(如 3 月 31 日 -1 月 → 2 月 31 日 → 3 月 3 日)。這符合數學定義,但違背業務直覺(「上個月同一天」)。

正確獲取「上個月同一天」的方案

// 方案 1:先取上月 1 號,再加 (當前日-1) 天
$firstDayThisMonth = strtotime('first day of this month');
$firstDayLastMonth = strtotime('-1 month', $firstDayThisMonth);
$targetDay = min(date('j'), date('t', $firstDayLastMonth)); // 避免 31→30/28/29
$result = strtotime("+{$targetDay} days", $firstDayLastMonth);

// 方案 2:DateTime 類(推薦,PHP 5.3+)
$dt = new DateTime('2011-03-31');
$dt->modify('first day of last month');
$dt->modify('+' . (min($dt->format('j'), $dt->format('t')) - 1) . ' days');
echo $dt->format('Y-m-d'); // 2011-02-28

總結

strtotime() 的相對月份計算是「月份偏移優先,日期順延」,而非「日曆月份倒推」。業務邏輯涉及「上個月同一天」、「下個月同一天」時,**請改用 DateTime::modify() 配合 first day of 策略**,或封裝工具函數統一處理,避免月底日期產生邏輯錯誤。

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