php验证日期需分两步:先用正则/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/粗筛格式,再调用checkdate()或datetime::createfromformat()校验逻辑合法性,避免strtotime自动纠错导致误判。

匹配常见日期格式(如 YYYY-MM-DD)用 preg_match
PHP 里最常用的是 preg_match 配合严格模式验证日期字符串。别直接写 /\d{4}-\d{2}-\d{2}/ —— 它能匹配 9999-99-99 这种非法日期,也拦不住 2023-02-30。
真正靠谱的做法是分两步:先用正则粗筛格式,再用 DateTime::createFromFormat 或 checkdate() 校验逻辑合法性。
- 推荐正则:
/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/,它限制月份 01–12、日 01–31,但依然不防2023-02-30 - 必须补校验:
checkdate((int)$month, (int)$day, (int)$year)才能确认 2 月有没有 30 号 - 注意开头的
^和结尾的$,否则"abc2023-01-01def"也会被误匹配
用 DateTime::createFromFormat 更安全地解析并验证
比起纯正则,DateTime::createFromFormat 是 PHP 原生支持日期语义验证的方式,一次到位,不用手动拆年月日。
- 示例:
$dt = DateTime::createFromFormat('Y-m-d', $input);,如果格式不对或日期非法(如2023-02-30),$dt会是false - 记得检查返回值:
if (!$dt || $dt->format('Y-m-d') !== $input) { /* 格式或逻辑错误 */ },因为createFromFormat在部分错位时可能静默修正(比如把2023-13-01当成2024-01-01) - 它对空格、多余字符敏感,
"2023-01-01 "会失败;需要预处理 trim,或改用DateTime::getLastErrors()查具体哪错了
匹配带时间的完整时间戳(如 YYYY-MM-DD HH:MM:SS)
加时间后正则复杂度上升,容易漏边界。建议仍以 createFromFormat 为主,正则只作前置过滤。
- 宽松匹配(仅格式):
/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])\s+(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/ - 但秒数允许
60(闰秒),而 PHP 的DateTime不支持闰秒,实际业务中应拒绝:60,正则里写成[0-5][0-9]更稳妥 - 时区部分(如
+0800或Z)不要硬塞进正则,交给DateTime::createFromFormat('Y-m-d H:i:s P', $str)处理更可靠
为什么不用 strtotime 做验证?
strtotime 看似简单,但它会自动“纠正”很多明显错误,反而掩盖问题。
-
strtotime('2023-02-30')返回2023-03-02的时间戳,不是 false —— 你无法区分用户输错了,还是真想表达“2月30号之后两天” -
strtotime('2023/13/01')会转成2024-01-01,和预期严重不符 - 它还接受大量模糊输入(如
'next Monday'、'+1 month'),在表单校验场景下属于副作用,不该依赖
日期格式校验的关键在于“拒绝非法输入”,而不是“尽力猜你想干啥”。这点上 createFromFormat + 显式错误检查才是稳解。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











