DateTimeFormatter是Java 8+线程安全的日期时间格式化工具,关键在选对创建方式(预定义常量/本地化/ofPattern)、写准模式字符串(注意H/h、MM/M、E/EEEE等区别)、匹配类型与格式(如ZonedDateTime需完整时区信息),并复用static final实例。

DateTimeFormatter 是 Java 8+ 中处理日期时间格式化与解析的核心工具,它线程安全、表达力强,且天然适配 LocalDate、LocalDateTime、ZonedDateTime 等新时间类型。用好它,关键在三点:选对创建方式、写对模式字符串、注意类型与格式的匹配。
三种创建方式各司其职
不用硬记所有 API,按场景选最合适的:
-
标准化输出(如日志、API 响应):直接用预定义常量,比如
DateTimeFormatter.ISO_LOCAL_DATE_TIME输出2026-05-06T20:34:12,或DateTimeFormatter.ISO_OFFSET_DATE_TIME处理带时区偏移的时间串。 -
中文界面或本地化需求:用
ofLocalizedDateTime(FormatStyle.LONG),自动适配系统 Locale —— 在中文环境输出“2026年5月6日星期三下午8:34:12”,在英文环境则为“Wednesday, May 6, 2026 at 8:34:12 PM”。 -
定制化展示(如报表标题、提示文案):用
ofPattern("yyyy年M月d日 E a h:mm"),灵活组合符号,输出“2026年5月6日 星期三 下午 8:34”。
模式字母必须严丝合缝
格式化失败或解析报错,八成是模式与实际数据不一致。重点注意几组易混淆符号:
-
H vs h:24 小时制用
H(0–23),12 小时制用h(1–12),且必须配合a(AM/PM)使用;单独写h:mm a解析"3:45 PM"没问题,但写成H:mm去解析就会失败。 -
MM vs M,dd vs d:
MM要求月份两位(如"05"),M接受单数("5");同理dd要求补零,d不强制。解析"2026-5-6"必须用"yyyy-M-d",否则抛异常。 -
E vs EE vs EEEE:
E输出简写(如“Wed”),EEEE输出全称(“Wednesday”)。中文环境下,EEEE才能正确输出“星期三”,仅写E可能得“周三”或空值,取决于 Locale 和实现。
ZonedDateTime 解析需带完整时区信息
普通 LocalDateTime 解析只要日期时间部分,但 ZonedDateTime 必须含时区标识,否则 parse() 直接抛 DateTimeParseException:
- ✅ 正确示例:
"2026-05-06T20:34:12+08:00[Asia/Shanghai]"或"2026-05-06T12:34:12Z",可用ISO_ZONED_DATE_TIME解析。 - ❌ 错误示例:
"2026-05-06T20:34:12"缺少时区,即使你传入ZonedDateTime.parse(...)也会失败。若原始字符串无时区,需先解析为 LocalDateTime,再用atZone(ZoneId.systemDefault())显式指定。
解析时务必复用 formatter 实例
DateTimeFormatter 是不可变且线程安全的,建议声明为 static final 字段,避免每次调用都新建对象:
- ✅ 推荐写法:
private static final DateTimeFormatter CN_FORMAT = DateTimeFormatter.ofPattern("yyyy年M月d日 HH:mm"); - ❌ 避免写法:
LocalDateTime.parse(s, DateTimeFormatter.ofPattern("yyyy年M月d日 HH:mm"))—— 每次都构造新实例,浪费资源,也增加出错可能。










