SimpleDateFormat线程不安全且模式敏感,应避免static复用;推荐Java 8+的DateTimeFormatter,它线程安全、不可变、语义清晰。

SimpleDateFormat 线程不安全,别在多线程里复用同一个实例
SimpleDateFormat 不是线程安全的。如果多个线程共用一个 SimpleDateFormat 实例(比如定义为 static 字段),极大概率出现格式化错乱、抛出 java.lang.ArrayIndexOutOfBoundsException 或返回错误日期字符串。
- 每次使用都新建实例:开销小,最稳妥
- 用
ThreadLocal封装:适合高频调用且需复用模式的场景 - 避免
static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd")这类写法
模式字母大小写敏感,常见误写:小写 mm 当作分钟,实际是分钟,MM 才是月份
SimpleDateFormat 的模式字符串中,MM 表示月(01–12),mm 表示分(00–59)。把 "yyyy-mm-dd" 当作“年-月-日”用,结果会把当前分钟塞进“月”的位置,例如输出 "2024-42-15"(假设当前是 14:42)。
-
yyyy:4位年份 -
MM:两位月份(1月 →"01") -
dd:两位日期 -
HH:24小时制小时(00–23) -
hh:12小时制小时(01–12) -
mm:分钟(00–59) -
ss:秒(00–59)
解析字符串时,lenient 默认为 true,会导致奇怪的自动修正
默认情况下,SimpleDateFormat 的 lenient 属性为 true,它会尝试“理解”非法日期,比如把 "2024-02-30" 解析成 2024 年 3 月 1 日(2月只有29天),而不是报错。
- 业务上要求严格校验时,必须调用
sdf.setLenient(false) - 设为
false后,遇到无效日期(如"2024-02-30"或"2024-13-01")会抛出ParseException - 注意:格式化(date → string)不受
lenient影响,只影响解析(string → date)
替代方案:优先考虑 DateTimeFormatter(Java 8+)
SimpleDateFormat 是遗留 API,设计缺陷多、线程不安全、容错逻辑难控。Java 8 引入的 java.time.format.DateTimeFormatter 是不可变、线程安全、语义清晰的现代替代品。
立即学习“Java免费学习笔记(深入)”;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dt = LocalDateTime.now();
String text = dt.format(formatter); // "2024-06-15 14:23:45"
// 解析
LocalDateTime parsed = LocalDateTime.parse("2024-06-15 14:23:45", formatter);
-
DateTimeFormatter实例可安全共享、复用、甚至设为static final - 没有
lenient开关,但可通过ResolverStyle.STRICT显式控制解析严格性 - 与
LocalDateTime、ZonedDateTime等新时间类型配合自然,避免老Date和Calendar的隐式时区陷阱
SimpleDateFormat;新项目直接上 DateTimeFormatter,否则迟早被线程问题和解析偏差咬一口。










