如何在 Java 中使用现代日期时间 API 处理多种格式的日期字符串输入

本文介绍如何使用 `java.time` 包中的 `datetimeformatter` 灵活解析并统一格式化不同结构的日期时间字符串(如 "12-1-2012 t 10:23:34" 和 "20-10-2012 t 10:34:22"),避免过时且线程不安全的 `simpledateformat`。

在 Java 中处理多格式日期输入时,关键在于分离解析(parsing)与格式化(formatting)逻辑。原始代码中试图用单一 SimpleDateFormat("dd-MM-yyyy T HH:mm:ss") 同时匹配 "12-1-2012"(单数字月/日)和 "20-10-2012"(双数字月/日),这必然失败——因为 dd 和 MM 要求两位补零,而 "12-1-2012" 中的 1 不满足 MM 的严格匹配。

现代解决方案是采用 java.time API(Java 8+),它提供线程安全、不可变且语义清晰的 DateTimeFormatter。核心思路是:

  • ✅ 使用宽松模式解析:用 d-M-uuuu 'T' HH:mm:ss ——
    d(日)和 M(月)支持 1~31 / 1~12 的单/多位输入;
    uuuu 表示四位年份(推荐替代 yyyy,对“周历年”更鲁棒);
    'T' 是字面量引号,确保空格与字母 T 精确匹配。

  • ✅ 使用严格模式格式化:用 dd-MM-uuuu 'T' HH:mm:ss ——
    输出始终为两位补零的 dd 和 MM,达成统一目标格式。

以下是完整可运行示例:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class DateTimeMultiFormat {
    public static void main(String[] args) {
        // 解析器:容忍单/双位日、月
        DateTimeFormatter parser = DateTimeFormatter.ofPattern("d-M-uuuu 'T' HH:mm:ss", Locale.ENGLISH);
        // 格式化器:强制输出两位补零
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-uuuu 'T' HH:mm:ss", Locale.ENGLISH);

        String[] inputs = { "12-1-2012 T 10:23:34", "20-10-2012 T 10:34:22" };

        

for (String input : inputs) { LocalDateTime parsed = LocalDateTime.parse(input, parser); String normalized = parsed.format(formatter); System.out.println(normalized); // 输出:12-01-2012 T 10:23:34 / 20-10-2012 T 10:34:22 } } }

⚠️ 注意事项:

  • 勿混用 y 与 u:u(year of era)在跨世纪或特殊日历场景下比 y(year)更可靠,尤其涉及 WeekFields 或时区计算时;
  • 显式指定 Locale:避免因 JVM 默认区域设置导致解析失败(如月份缩写);
  • 异常处理:生产环境应包裹 try-catch (DateTimeParseException e) 并提供有意义的错误提示;
  • 性能优化:DateTimeFormatter 是线程安全的,建议声明为 static final 复用,而非每次创建。

总结:摒弃 SimpleDateFormat,拥抱 java.time —— 通过组合多个专用 DateTimeFormatter 实例,即可优雅、健壮、高效地应对多格式日期输入场景。