strtotime() 是 PHP 中最強大也最容易誤用的日期時間解析函數。本文從底層實現原理出發,深度剖析其解析機制,重點解釋為什麼 strtotime("-1 month") 在月末會「失效」,並提供避坑指南。
| 關鍵字/語法 | 含義 | 示例輸出(基準 2011-02-01) |
|---|---|---|
jan / January | 指定月份的今天,無則順延下月 | strtotime("feb", strtotime("2011-03-31")) → 2011-03-03 |
first day | 當月第一天 | strtotime("first day", $time) → 2011-02-01 |
last day | 當月最後一天 | strtotime("last day", strtotime("2000-02-01")) → 2000-02-29 |
first/last sunday | 本月第一/最後一個周日 | 配合 first/last + 星期關鍵字 |
previous/next monday | 上一個/下一個周一 | strtotime("previous sunday", "2011-02-01") → 2011-01-30 |
back/front of 10 | 10點後 15分 / 10點前 45分 | back of 24 → 翌日 00:15 |
strtotime() 位於 ext/date/lib/parse_date.re,使用 re2c 詞法分析器 生成解析器。核心流程:
reltextunit、relnumber)分解為 Tokentimelib_time 結構體y,m,d,h,i,s(日期時間)、relative(相對調整量)、have_relative 標志以 yesterday 為例,對應動作:
// parse_date.re 片段
'yesterday' {
TIMELIB_INIT;
TIMELIB_HAVE_RELATIVE();
s->time->relative.d = -1; // 相對天數 -1
return TIMELIB_RELATIVE;
}
strtotime("-1 month") 失效的根本原因當解析 -1 month 時:
relnumber = -1、reltextunit = monthTIMELIB_MONTH 動作:s->time->relative.m += -1(月份相對值 -1)2011-03-31 月份 -1 → 2011-02-312011-03-03這不是 Bug,是設計決策:
strtotime僅做字段級相對運算,不承擔「業務語義上的上個月同一天」邏輯。開發者需自行處理月末邊界。
mktime() 或 DateTime:mktime(0,0,0, date("n")-1, date("j"), date("Y")) 配合 date("t") 判斷天數first day of last month、last day of -1 month 等 PHP 5.3+ 支持的明確語法strtotime("-1 month"):getLastMonthSameDay($time) 統一處理邊界date_default_timezone_set() 與服務器/數據庫時區一致strtotime() 解析開銷較大(詞法分析+正則匹配),高頻調用(如循環中)建議緩存結果或改用 mktime()