simpledateformat非线程安全,多线程复用会导致结果错乱,应局部新建、加锁或改用datetimeformatter;parse()抛parseexception主因是字符串与模式不匹配,如时区缺失、月份超限、yy解析四位年份等;安全格式化需用局部变量指定模式及时区;datetimeformatter不可变、线程安全、api清晰,是java 8+推荐替代方案。

SimpleDateFormat 不是线程安全的,多线程环境下直接复用同一个实例会导致解析/格式化结果错乱——必须每次新建、局部使用,或加锁,或改用 DateTimeFormatter(推荐)。
为什么 SimpleDateFormat.parse() 会抛出 ParseException?
常见原因是传入字符串与模式不严格匹配,比如:
- 时区缺失但模式含
Z或z(如"yyyy-MM-dd HH:mm:ss Z"要求输入带+0800) - 月份写成
13却用了MM(它只接受 01–12) - 年份用
yy解析"2024"会当成 2020 年(yy只读两位) - 默认 lenient 模式开启时看似能解析,但关闭后(
setLenient(false))会立即报错
如何安全地格式化当前时间并输出为 "2024-05-21 14:30:45"?
用局部变量 + 明确模式,避免共享:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("GMT+8")); // 如需固定时区
String formatted = sdf.format(new Date());
注意:HH 是 24 小时制,hh 是 12 小时制;mm 是分钟,MM 是月份——大小写敏感,写错就出错。
替换方案:用 DateTimeFormatter 替代 SimpleDateFormat 的理由
DateTimeFormatter 是 Java 8+ 的标准替代,不可变、线程安全、API 更清晰:
- 预定义常量可直接用:
DateTimeFormatter.ISO_LOCAL_DATE_TIME - 自定义模式更直观:
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") - 时区支持更自然:
LocalDateTime.now().atZone(ZoneId.of("Asia/Shanghai")).format(...) - 不会因共享导致诡异 bug,也不需要手动同步
旧项目若无法升级到 Java 8,至少把 SimpleDateFormat 声明为方法内局部变量,别塞进 static 字段里。
真正容易被忽略的是:哪怕你只在单线程里用,只要这个 SimpleDateFormat 实例被多个方法共享(比如作为工具类的 static 成员),就可能在将来被无意引入并发场景——隐患藏得深,修复成本高。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











