DateTimeFormatter 是线程安全、不可变的日期格式化工具,必须通过静态工厂方法创建;其 pattern 必须与 temporal 类型严格匹配,否则抛异常。

DateTimeFormatter 是 Java 8+ 中线程安全、不可变的日期格式化工具,直接用它转换比老式 SimpleDateFormat 更可靠,也更不容易出错。
为什么不能直接 new DateTimeFormatter()?
DateTimeFormatter 没有 public 构造方法,必须通过静态工厂方法创建。硬写 new DateTimeFormatter() 会编译失败。
- 用
DateTimeFormatter.ofPattern("yyyy-MM-dd")自定义格式 - 用
DateTimeFormatter.ISO_LOCAL_DATE等预设常量(推荐用于标准格式) - 用
DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)适配本地化习惯
预设常量(如 ISO_LOCAL_DATE_TIME)自带时区/偏移处理逻辑,而自定义 pattern 默认不带时区信息,解析含 Z 或 +0800 的字符串时会抛 DateTimeParseException。
LocalDateTime 转字符串:pattern 必须匹配类型
LocalDateTime 没有时区,所以 pattern 里不能含 Z、z、X、x 这类时区符号,否则运行时报 UnsupportedTemporalTypeException。
- ✅ 正确:
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") - ❌ 错误:
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z")(Z 不被LocalDateTime支持) - 若需输出带时区的时间,改用
ZonedDateTime或OffsetDateTime
示例:
LocalDateTime now = LocalDateTime.now();
String s = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); // 输出:2024-05-21 14:23:05
字符串转 LocalDateTime:输入必须严格匹配 pattern
哪怕多一个空格、少一位年份,都会触发 DateTimeParseException,错误信息里会明确指出「Text '2024-5-1' could not be parsed at index 5」——index 就是解析失败的位置。
- 输入
"2024-05-01"却用 pattern"yyyy-M-d":可能成功(取决于 lenient 模式) - 但输入
"2024-5-1"用"yyyy-MM-dd":必然失败,因为月份和日期位数不一致 - 解决办法:统一输入规范,或用
DateTimeFormatterBuilder构建可选解析规则
示例(严格匹配):
String input = "2024-05-21 14:23:05";
LocalDateTime dt = LocalDateTime.parse(input, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
跨时区转换时,别漏掉 ZoneId 或 Offset
仅靠 DateTimeFormatter 无法完成时区转换。它只负责“字面格式”,不参与时区计算。
- 想把
"2024-05-21T14:23:05+0800"解析为东八区时间 → 用OffsetDateTime.parse()+ 对应 formatter - 想转成 UTC 时间 → 先 parse 成
OffsetDateTime,再调withOffsetSameInstant(ZoneOffset.UTC) - 想转成系统默认时区的
ZonedDateTime→ 用withZoneSameInstant(ZoneId.systemDefault())
常见陷阱:用 LocalDateTime.parse() 去解析带时区的字符串,结果时区信息被静默丢弃,后续转换全错。
真正容易被忽略的是:formatter 和 temporal 类型的契约关系——不是所有 pattern 都适用于所有类型,也不是所有字符串都能靠改 pattern 强行塞进去。匹配失败往往不是 formatter 写得不对,而是选错了 temporal 类型。










