SimpleDateFormat线程不安全,禁用静态复用;pattern大小写敏感(如yyyy≠YYYY、mm≠MM);务必设setLenient(false)并捕获ParseException;新项目优先用线程安全的DateTimeFormatter。
这是最常踩的坑:把 SimpleDateFormat 声明为静态变量或单例,在并发环境下解析或格式化会返回错误时间,甚至抛出 java.lang.NumberFormatException 或乱序结果。
Calendar 实例和字符缓冲区,没有同步保护DateTimeFormatter)synchronized 锁住整个操作,但性能差,不推荐比如年份写成 "YYYY" 和 "yyyy" 行为完全不同:YYYY 是“基于周的年”,可能跨年;yyyy 才是日历年。月份 "MM"(数字)和 "MMM"(缩写,如 Jan)也容易混淆。
"HH" 是 24 小时制(00–23),"hh" 是 12 小时制(01–12),漏掉一个字母就出错"mm"(小写),大写 "MM" 是月份 —— 这个错配导致解析失败很常见"ss",毫秒是 "SSS"(三个 S),少一个 S 会截断或补零SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timeStr = sdf.format(new Date()); // 输出类似 "2025-06-15 14:23:05"
SimpleDateFormat.parse() 默认开启宽松解析(lenient = true),比如把 "2025-13-01" 自动转成 2025 年 1 月 1 日,掩盖真实输入错误。
sdf.setLenient(false),这样非法日期
ParseException
ParseException,不能只 catch Exception —— 否则 IDE 可能提示未处理受检异常"2025-06-15T14:23:05+0800")而 pattern 没写时区部分("Z" 或 "X"),会解析失败除非维护老项目,否则不要在新代码里用 SimpleDateFormat。它设计陈旧、不可变性差、API 不直观。
DateTimeFormatter 是不可变、线程安全的,可直接静态复用DateTimeFormatter.ISO_LOCAL_DATE_TIME
ZonedDateTime + withZoneSameInstant() 比 SimpleDateFormat.setTimeZone() 少出错DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = LocalDateTime.now().format(formatter);
LocalDateTime parsed = LocalDateTime.parse("2025-06-15 14:23:05", formatter);
时区、模式字符串大小写、线程安全这三点,只要漏掉一个,线上就容易出难以复现的时间错乱问题。