最稳方法是用date_create()和date_modify()循环生成指定年月全部日期:从当月1号起每日+1,直到月份变更;需确保$month为两位格式,datetime类可自动处理闰年但初始化日期必须合法。

PHP生成指定年月的全部日期数组
直接用 date_create() 和 date_modify() 循环最稳,别碰 range() 加 strtotime() 那套——跨月时容易错乱,尤其遇到 2 月或时区切换。
核心思路:从当月第一天开始,每天加 1,直到下个月第一天为止。边界清晰,不依赖月份天数预判。
- 用
date_create("{$year}-{$month}-01")初始化起始日 - 循环中用
date_modify($date, '+1 day')推进,比strtotime('+1 day', $ts)更可靠 - 终止条件是
date_format($date, 'm') !== $month,不是比较天数(避免 31→1 跳变干扰) - 注意传入的
$month必须是两位格式(如'02'),否则date_create()可能解析失败
处理2月和闰年的坑
PHP 的 DateTime 类本身能正确识别闰年,但前提是初始化时日期合法。如果传了 '2023-02-30',它会自动转成 2023-03-02, silently 错位。
- 永远不要手动计算当月天数再用
for ($i = 1; $i —— <code>cal_days_in_month()返回的是理论最大值,不是实际可用范围 - 验证输入:用
checkdate($month, 1, $year)确保年月合法,避免0000或13这类无效组合 - 时区敏感:
date_default_timezone_set('Asia/Shanghai')最好显式设一次,否则date_create()可能按 UTC 解析,导致首日偏移
返回格式要对齐业务场景
返回纯数字数组(如 [1,2,3,...,31])看似简洁,但丢失了年月上下文,后续做日历渲染或数据库写入时反而要反复拼接。
立即学习“PHP免费学习笔记(深入)”;
- 推荐返回标准 ISO 格式字符串数组:
['2024-02-01', '2024-02-02', ...] - 如果需要时间戳,用
date_timestamp_get($date),别用strtotime()再转换——多一次解析,且受时区影响更大 - 避免返回
DateTime对象数组:内存占用高,JSON 编码时还得额外处理,除非真需要调用对象方法
性能足够,但别在循环里做重操作
生成一个月份最多 31 次迭代,耗时在微秒级,性能不是瓶颈。真正拖慢的是循环体内做了不该做的事。
- 不要在每次循环里查数据库、读文件或调用外部 API
- 避免重复创建
DateTimeZone实例,初始化一次复用即可 - 如果只是要「是否在当月」的布尔判断,别生成全量数组——直接用
date('Y-m', $ts) === '2024-02'更轻量
最常被忽略的是输入校验和时区设置,这两点一漏,测试环境跑得通,上线后跨时区就出错——而且错得毫无征兆。











