PHP中无内置函数直接返回某年某月第一个周一,但可用strtotime("first monday of Y-m")两行搞定,需补零月份、不省略年份,并设置正确时区。

用 date() 和 strtotime() 快速定位某月第一个周一
直接结论:PHP 里没有现成函数一步返回“某年某月第一个周一”,但用 strtotime() 配合日期字符串描述,两行代码就能搞定,且兼容 PHP 5.2+。
原理是让 PHP 解析类似 "first monday of 2024-03" 这样的自然语言格式——它底层调用 GNU date parser,只要时区设置正确,结果稳定。
-
strtotime("first monday of Y-m")是最简方案,比如strtotime("first monday of 2024-03")返回 2024-03-04 的时间戳 - 注意月份必须补零(
"2024-3"会失败),年份不能省略("first monday of 03"会被当成今年 3 月) - 如果系统 locale 或时区不一致(如服务器设为 UTC,但业务按北京时间),可能偏移一天;建议开头加
date_default_timezone_set("Asia/Shanghai")
手动计算法:避免 strtotime() 的模糊解析风险
当项目要求逻辑完全可控(比如嵌入定时任务、或需复现相同行为于 JS 端),手动算更稳妥。核心思路是:取当月 1 号,再根据当天星期几推到最近的周一(若 1 号是周一就用它,否则往后推)。
关键点在于 PHP 的 date("w"):周日=0,周一=1,……周六=6。所以“第一个周一” = 1 号 + (1 − w + 7) % 7 天。
立即学习“PHP免费学习笔记(深入)”;
- 示例:2024-03-01 是周五,
date("w", $ts)返回 5 → 偏移 = (1 − 5 + 7) % 7 = 3 → 3 月 4 日 - 注意:不能直接用
wkday或N(ISO 标准周一=1,周日=7),因为"w"更通用,且和strtotime("first monday")行为对齐 - 月份天数不用提前查,
date("t", $ts)可动态获取,但本场景不需要——我们只算第一个,不会超界
常见错误:为什么 strtotime("monday this month") 不可靠
这个写法看似合理,实际行为取决于当前日期。比如今天是 3 月 15 日,"monday this month" 会返回 3 月 11 日(最近一个周一),而非“第一个”。它本质是相对当前时间的“最近”,不是“当月起始方向”的“第一个”。
- 错误现象:
strtotime("monday this month")在 3 月 1–7 日之间可能返回上个月的周一(如 3 月 1 日是周六,则返回 2 月 26 日) - 对比验证:
strtotime("first monday of 2024-03")永远返回 2024-03-04;而"monday this month"在 3 月 1 日执行,结果是 2024-02-26 - 同理,
"next monday"是从当前时间起算,也不满足“某月首个”语义
输出格式与时区陷阱
拿到时间戳后,用 date("Y-m-d", $ts) 输出字符串最常用,但要注意:如果原始时间戳来自 UTC,而显示需求是本地时间,直接 date() 会按默认时区转换——可能出错。
- 推荐统一处理路径:先设时区(
date_default_timezone_set("Asia/Shanghai")),再用strtotime()解析,最后date()输出 - 避免混用:不要一边用
new DateTime()(默认用当前时区),一边用strtotime()(受时区设置影响),否则同一时间戳输出不同 - 调试技巧:打印
date("Y-m-d H:i:s T", $ts)查看带时区的结果,比只看"Y-m-d"更容易发现偏移
真正容易被忽略的是跨月边界情况——比如 2025 年 1 月 1 日是周三,那么“2025-01 第一个周一”是 1 月 6 日;但如果你误用“本月第一个周一”逻辑去算 2024-12,就可能漏掉 12 月 30 日这个周一。明确“某年某月”这个限定,才能避开这类隐性错误。



















