本文详解如何用 Java 8+ 的 LocalDate 和 DateTimeFormatter 安全、准确地完成日期字符串的解析(如 "2018-04-16")与格式化(如 "16-Apr-2018"),避免 DateTimeParseException,并强调输入/输出格式分离的核心原则。
本文详解如何用 java 8+ 的 `localdate` 和 `datetimeformatter` 安全、准确地完成日期字符串的解析(如 "2018-04-16")与格式化(如 "16-apr-2018"),避免 `datetimeparseexception`,并强调输入/输出格式分离的核心原则。
在使用 LocalDate.parse() 时,一个常见误区是混淆
解析格式(input pattern)
与
格式化模式(output pattern)
。你提供的代码中:
此处 formatter 的模式 "dd-MMM-yyyy"(例如 "16-Apr-2018")描述的是
期望输出的样式
,但它被错误地用于
解析输入字符串 "2018-04-16"
—— 而该字符串实际遵循的是 yyyy-MM-dd 格式。LocalDate.parse() 要求传入的 DateTimeFormatter 必须严格匹配待解析字符串的结构。当解析器在索引 2(即第一个 '-' 后)尝试匹配 'M'(月份缩写)却遇到 '0' 时,便抛出 DateTimeParseException: Text '2018-04-16' could not be parsed at index 2。
✅ 正确做法是:
为解析和格式化分别定义专用的 DateTimeFormatter
:
? 提示:对于 ISO 标准格式(如 "2018-04-16"),可直接使用内置常量简化解析,无需显式指定模式:
⚠️ 注意事项:
Locale.US 在 MMM 模式中至关重要——它确保月份缩写为英文(如 "Apr"),而非系统默认语言(如中文环境可能输出 "4月");
切勿复用同一 DateTimeFormatter 实例既做 parse() 又做 format(),除非其模式恰好同时兼容输入与输出结构(极少见);
SimpleDateFormat 已过时(线程不安全、设计陈旧),应始终优先使用 java.time 体系。
总结:日期转换本质是两步操作——
先按源格式“读懂”字符串,再按目标格式“说出”结果
。明确区分 inputFormatter 与 outputFormatter,是避免 DateTimeParseException 并写出健壮时间处理代码的关键。
String date = "2018-04-16";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", Locale.US);
LocalDate localDate = LocalDate.parse(date, formatter); // ❌ 报错!// Step 1: 使用匹配输入格式的 formatter 解析字符串
String inputDate = "2018-04-16";
DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate localDate = LocalDate.parse(inputDate, inputFormatter);
// Step 2: 使用目标输出格式的 formatter 进行格式化
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", Locale.US);
String outputDate = localDate.format(outputFormatter);
System.out.println(outputDate); // 输出:16-Apr-2018LocalDate localDate = LocalDate.parse("2018-04-16"); // ✅ 默认支持 ISO_LOCAL_DATE