Java DateTimeFormatter 类

DateTimeFormatter 是 Java 8 引入的日期时间 API (java.time 包) 中的一个重要类,它用于格式化和解析日期时间对象。这个类提供了强大的功能来处理日期时间的显示和转换。

简单来说,DateTimeFormatter 主要有两个作用:

  • 格式化:将日期时间对象(如 LocalDate, LocalDateTime)转换为特定格式的字符串
  • 解析:将符合格式的字符串转换为日期时间对象

为什么需要 DateTimeFormatter

在 Java 8 之前,我们使用 SimpleDateFormat 来处理日期格式化和解析,但它有几个缺点:

  • 不是线程安全的
  • 设计较为陈旧
  • 错误处理不够友好

DateTimeFormatter 解决了这些问题:

  • 线程安全:可以安全地在多线程环境中共享实例
  • 不可变:一旦创建就不能被修改
  • 更丰富的预定义格式:提供了大量内置格式
  • 更好的错误处理:解析失败时会提供更详细的错误信息

基本使用方法

预定义的格式化器

DateTimeFormatter 提供了许多预定义的格式化常量:

实例

LocalDateTime now = LocalDateTime.now();

// 使用预定义的格式化器
System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE));     // 2023-11-15
System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_TIME));     // 14:30:45.123
System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); // 2023-11-15T14:30:45.123

自定义模式

你可以使用模式字符串创建自定义的格式化器:

实例

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = now.format(formatter);  // 格式化
System.out.println(formattedDateTime);             // 2023-11-15 14:30:45

// 解析
LocalDateTime parsedDateTime = LocalDateTime.parse("2023-11-15 14:30:45", formatter);

// 常用中文日期格式
DateTimeFormatter chineseFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
String formattedDate = today.format(chineseFormatter);
System.out.println("中文格式日期: " + formattedDate);

// 解析中文日期字符串
String chineseDateStr = "2023年05月20日";
LocalDate parsedDate = LocalDate.parse(chineseDateStr, chineseFormatter);
System.out.println("解析后的日期: " + parsedDate);

// 其他常用格式
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MM/dd/yyyy");
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 EEEE", Locale.CHINA);

System.out.println("格式1: " + today.format(formatter1));
System.out.println("格式2: " + today.format(formatter2));
System.out.println("格式3(带星期): " + today.format(formatter3));

本地化格式

可以根据不同的地区创建格式化器:

实例

DateTimeFormatter frenchFormatter =
    DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)
                     .withLocale(Locale.FRENCH);
String frenchDate = now.format(frenchFormatter);
System.out.println(frenchDate);  // 15 novembre 2023

模式字母说明

创建自定义格式时,需要使用特定的模式字母:

字母 含义 示例
y yyyy → 2023
M MM → 11
d dd → 15
H 小时(0-23) HH → 14
h 小时(1-12) hh → 02
m 分钟 mm → 30
s ss → 45
S 毫秒 SSS → 123
E 星期几 E → 周三
a 上午/下午 a → 下午

最佳实践

重用格式化器

由于 DateTimeFormatter 是线程安全的,建议将常用的格式化器定义为常量:

实例

public class DateUtils {
    public static final DateTimeFormatter STANDARD_FORMATTER =
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
   
    // 使用方式
    String formatted = LocalDateTime.now().format(STANDARD_FORMATTER);
}

综合实例:

实例

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

public class RunoobTest {

    public static void main(String[] args) {
        // 1. LocalDate 示例
        LocalDate currentDate = LocalDate.now();
        System.out.println("当前日期: " + currentDate);
       
        LocalDate specificDate = LocalDate.of(2023, 5, 20);
        System.out.println("特定日期: " + specificDate);

        // 2. LocalTime 示例
        LocalTime currentTime = LocalTime.now();
        System.out.println("当前时间: " + currentTime);
       
        LocalTime specificTime = LocalTime.of(14, 30, 15);
        System.out.println("特定时间: " + specificTime);

        // 3. LocalDateTime 示例
        LocalDateTime currentDateTime = LocalDateTime.now();
        System.out.println("当前日期时间: " + currentDateTime);
       
        LocalDateTime specificDateTime = LocalDateTime.of(2023, 5, 20, 14, 30, 15);
        System.out.println("特定日期时间: " + specificDateTime);

        // 4. DateTimeFormatter 示例
        // 基本格式化
        DateTimeFormatter basicFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        System.out.println("基本格式化: " + currentDate.format(basicFormatter));

        // 中文格式化
        DateTimeFormatter chineseFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日", Locale.CHINA);
        System.out.println("中文日期: " + currentDate.format(chineseFormatter));

        // 带星期的中文格式化
        DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 EEEE", Locale.CHINA);
        System.out.println("带星期的中文日期: " + currentDate.format(weekFormatter));

        // 时间格式化
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH时mm分ss秒");
        System.out.println("中文时间: " + currentTime.format(timeFormatter));

        // 日期时间格式化
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println("标准日期时间: " + currentDateTime.format(dateTimeFormatter));

        // 解析日期
        String dateStr = "2023-05-20";
        LocalDate parsedDate = LocalDate.parse(dateStr, basicFormatter);
        System.out.println("解析后的日期: " + parsedDate);

        // 解析中文日期
        String chineseDateStr = "2023年05月20日";
        LocalDate parsedChineseDate = LocalDate.parse(chineseDateStr, chineseFormatter);
        System.out.println("解析后的中文日期: " + parsedChineseDate);
    }
}

输出结果为:

当前日期: 2025-05-01
特定日期: 2023-05-20
当前时间: 10:46:38.591747
特定时间: 14:30:15
当前日期时间: 2025-05-01T10:46:38.592002
特定日期时间: 2023-05-20T14:30:15
基本格式化: 2025-05-01
中文日期: 2025年05月01日
带星期的中文日期: 2025年05月01日 星期四
中文时间: 10时46分38秒
标准日期时间: 2025-05-01 10:46:38
解析后的日期: 2023-05-20
解析后的中文日期: 2023-05-20

处理解析异常

解析字符串时应该处理可能的异常:

实例

try {
    LocalDateTime dateTime = LocalDateTime.parse("2023-11-15", formatter);
} catch (DateTimeParseException e) {
    System.err.println("无法解析日期时间: " + e.getMessage());
}

考虑时区

如果需要处理时区,可以使用 ZonedDateTime 和特定的时区模式:

实例

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime.format(formatter));  // 2023-11-15 14:30:45 CST

总结

DateTimeFormatter 是 Java 8 日期时间 API 中处理格式化和解析的强大工具。相比旧的 SimpleDateFormat,它更加安全、灵活和易用。掌握 DateTimeFormatter 的使用可以让你更高效地处理各种日期时间格式需求。

记住关键点:

  • 使用预定义的格式化器处理常见格式
  • 使用 ofPattern() 创建自定义格式
  • 考虑本地化和时区需求
  • 重用线程安全的格式化器实例
  • 正确处理解析异常