推荐使用 DateTimeFormatter 进行日期校验:先格式结构校验,再语义解析校验,线程安全且能识别“2023-02-30”等非法日期;遗留项目若用 SimpleDateFormat,必须设 setLenient(false) 并每次新建实例。

校验前端传来的日期格式参数,核心是既要检查字符串结构是否匹配(比如是不是“yyyy-MM-dd”),又要确认它代表一个真实存在的日期(比如不能是2023-02-30)。光靠正则或长度判断容易漏掉语义错误,推荐分两步走:先做格式结构校验,再做语义解析校验。
用 DateTimeFormatter 做强格式+语义校验(推荐 JDK8+)
这是目前最清晰、线程安全、且能同时兼顾格式和逻辑合法性的做法。它不会把“2023-02-30”当作有效日期,也不会把“2023-02-01 12:00”误判为“yyyy-MM-dd”格式合法。
- 创建固定格式的 DateTimeFormatter,并设为严格模式(默认就是)
- 调用 parse() 方法;成功说明格式对、日期真;抛 DateTimeParseException 就是非法
- 不需要手动 new 多个实例——
DateTimeFormatter是不可变且线程安全的,可复用
示例代码:
public static boolean isValidDate(String dateStr, String pattern) {
if (dateStr == null || dateStr.trim().isEmpty()) return false;
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
LocalDate.parse(dateStr.trim(), formatter); // 仅校验日期用 LocalDate
return true;
} catch (DateTimeParseException e) {
return false;
}
}
// 调用:isValidDate("2026-10-08", "yyyy-MM-dd") → true
// isValidDate("2026-13-01", "yyyy-MM-dd") → false
// isValidDate("2026-10-08 10:00", "yyyy-MM-dd") → false(格式不匹配,直接报错)
用 SimpleDateFormat(仅限遗留项目,JDK8 之前)
如果还在用老版本 JDK 或维护旧代码,SimpleDateFormat 仍可用,但必须注意两点:它不是线程安全的,且需显式调用 setLenient(false),否则会自动“纠正”错误日期(如把 2026-02-30 变成 2026-03-02)。
立即学习“Java免费学习笔记(深入)”;
- 每次校验都应新建
SimpleDateFormat实例,避免并发问题 - 必须设置
setLenient(false),否则校验失去意义 - 建议只用于过渡,新项目优先用
java.time
示例:
public static boolean isValidDateLegacy(String dateStr, String pattern) {
if (dateStr == null || dateStr.trim().isEmpty()) return false;
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
sdf.setLenient(false);
try {
sdf.parse(dateStr.trim());
return true;
} catch (ParseException e) {
return false;
}
}
结构先行:快速过滤明显错误(适合高频轻量校验)
当接口 QPS 很高、且前端约定极强(比如明确只接受 “dd/MM/yyyy”),可先用字符位置校验做快速拦截,避免进到解析层。这不替代语义校验,而是前置兜底。
- 检查长度是否为 10
- 检查索引 2 和 5 是否为 '/'
- 检查其余 8 位是否全为数字
- 通过后再交给
DateTimeFormatter做最终判定
例如:“15/09/2026” → 长度对、斜杠位置对、全是数字 → 进入下一步;“15-09-2026” → 第2位不是 '/' → 直接拒绝。
别踩这些坑
常见错误会悄悄放过非法输入:
- 用
==比较字符串或字符(应改用.equals()或直接==比 char) - 没设
setLenient(false),导致“2026-02-30”被接受 - 用正则只校验数字和分隔符,却不管月份范围、闰年、大小月(比如写成
\d{4}-\d{2}-\d{2}) - 忽略前后空格,导致 " 2026-10-08 " 校验失败


















