推荐使用正则/^(\d{4})[-\/\.年](\d{1,2})[-\/\.月](\d{1,2})[日]?$/u配合checkdate((int)$2,(int)$3,$1)二次校验,兼顾多分隔符匹配与日期合法性验证。

用 preg_match 匹配带分隔符的日期,别硬写三套正则
直接用一个正则覆盖 2023-04-01、2023/04/01、2023.04.01 甚至 2023年04月01日,关键不是“怎么写”,而是“怎么写得安全又不漏”。[-\/\.年月日] 看似简单,但容易误匹配 2023-13-01 或 2023/00/99。真正要做的,是先限定分隔符类型,再校验数值合法性。
- 推荐模式:
/^(\d{4})[-\/\.年](\d{1,2})[-\/\.月](\d{1,2})[日]?$/u——u修饰符必须加,否则中文“年月日”会乱码或不匹配 - 捕获组
$1、$2、$3分别对应年、月、日,后续可用checkdate($2, $3, $1)做二次验证(比如排除 2 月 30 日) - 别用
\d{2}强制两位数:用户可能输2023-4-1,\d{1,2}更现实 - 中文分隔符后不加空格?那就别在正则里硬塞
\s?——实际输入基本没空格,加了反而干扰匹配
checkdate() 是必须的,不是可选的
正则只负责“像日期”,checkdate() 才负责“真是日期”。光靠正则无法判断 2023-02-30 合法与否,PHP 的 checkdate() 是最轻量可靠的兜底手段。
- 调用前确保
$month和$day是整数:字符串如"00"或"0"传进去会返回false,建议用(int)$month显式转换 - 注意月份范围是 1–12,日是 1–31,
checkdate(0, 1, 2023)直接返回false,不用额外判断 - 闰年、大小月全由
checkdate()内部处理,不用自己写逻辑
中文日期“2023年04月01日”要小心编码和边界
如果用户真会输中文分隔符,重点不是正则怎么写,而是输入源是否 UTF-8。非 UTF-8 环境下,年 字可能被截成乱码,导致正则完全失效。
- 确认输入已转为 UTF-8:用
mb_convert_encoding($input, 'UTF-8', 'auto')预处理,比硬扛编码更稳妥 - 中文分隔符后可能有空格(如
2023年 4月 1日),可在正则中加\s*,但别滥用——多数场景无空格,加了反而慢 - 避免用
.*匹配中间内容,例如/\d{4}年.*\d{1,2}月.*\d{1,2}日/,可能跨行或吞掉关键字符,严格按结构写更可靠
别忽略时区和格式化输出的衔接
匹配成功后,别急着存字符串。用户输的是 2023/04/01,你存进数据库最好统一为 Y-m-d 格式,否则排序、查询都麻烦。
- 用
mktime(0,0,0,$month,$day,$year)转时间戳再格式化,比拼字符串更健壮(自动归一化2023-4-1→2023-04-01) - 注意
mktime对无效日期会回绕(如2023-13-01变成2024-01-01),所以必须先过checkdate() - 如果后续要给前端返回标准格式,直接
date('Y-m-d', $timestamp),别自己 sprintf 拼接
checkdate() 和明确的类型转换。中文支持不难,难在默认假设输入是 UTF-8 —— 实际上线前,一定要用真实用户输入样本测一遍编码 fallback。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











