一文搞懂Java8新特性的日期API!

314 阅读5分钟

Java 8 引入了全新的日期和时间 API (java.time 包),旨在替代老旧的 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 类,这些类存在许多设计上的缺陷,尤其在处理日期和时间的运算、时区、格式化等方面不够直观和易用。

新的日期和时间 API 受到了 Joda-Time 库的影响,提供了更加清晰、不可变、线程安全和符合 ISO 标准的类。Java 8 的 java.time 包包括了许多有用的类,下面是对它们的详细介绍。

1. 主要类介绍

1.1 LocalDate(不带时间的日期)

LocalDate 表示一个日期(年、月、日),不包含时间、时区等信息。它常用于表示没有时区或时间的日期(如生日、节假日)。

LocalDate date = LocalDate.of(2024, 11, 6);  // 创建特定日期
System.out.println(date);  // 输出:2024-11-06

LocalDate today = LocalDate.now();  // 获取当前日期
System.out.println(today);  // 输出:当前日期,例如 2024-11-06

LocalDate parsedDate = LocalDate.parse("2024-11-06");  // 通过字符串解析日期
System.out.println(parsedDate);  // 输出:2024-11-06

1.2 LocalTime(不带日期的时间)

LocalTime 表示一个时间(小时、分钟、秒、纳秒),不带日期和时区。常用于表示时间(如下午3点,或者某个事件的持续时间)。


LocalTime time = LocalTime.of(14, 30);  // 创建特定时间
System.out.println(time);  // 输出:14:30

LocalTime now = LocalTime.now();  // 获取当前时间
System.out.println(now);  // 输出:当前时间,例如 15:30:45.987654321

LocalTime parsedTime = LocalTime.parse("14:30:00");  // 通过字符串解析时间
System.out.println(parsedTime);  // 输出:14:30

1.3 LocalDateTime(日期和时间)

LocalDateTime 表示一个日期-时间组合(年、月、日、小时、分钟、秒、纳秒),不带时区。它可以用于大多数不涉及时区的日期时间计算。


LocalDateTime dateTime = LocalDateTime.of(2024, 11, 6, 14, 30);  // 创建特定的日期时间
System.out.println(dateTime);  // 输出:2024-11-06T14:30

LocalDateTime nowDateTime = LocalDateTime.now();  // 获取当前日期时间
System.out.println(nowDateTime);  // 输出:当前日期时间,例如 2024-11-06T15:30:45.987

LocalDateTime parsedDateTime = LocalDateTime.parse("2024-11-06T14:30:00");  // 通过字符串解析
System.out.println(parsedDateTime);  // 输出:2024-11-06T14:30

1.4 ZonedDateTime(带时区的日期时间)

ZonedDateTime 表示一个带有时区的日期-时间组合。它能够处理时区转换,适用于全球应用中需要时区支持的场景。


ZonedDateTime zonedDateTime = ZonedDateTime.of(2024, 11, 6, 14, 30, 0, 0, ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime);  // 输出:2024-11-06T14:30+08:00[Asia/Shanghai]

ZonedDateTime nowZoned = ZonedDateTime.now();  // 获取当前时区的日期时间
System.out.println(nowZoned);  // 输出:当前带时区的日期时间,例如 2024-11-06T15:30:45.987+08:00[Asia/Shanghai]

ZonedDateTime parsedZonedDateTime = ZonedDateTime.parse("2024-11-06T14:30:00+08:00[Asia/Shanghai]");  // 通过字符串解析
System.out.println(parsedZonedDateTime);  // 输出:2024-11-06T14:30+08:00[Asia/Shanghai]

1.5 Instant(时间戳)

Instant 是 Java 8 中的时间戳类,表示自1970年1月1日(UTC)以来的秒数。它通常用于表示机器时间戳,精确到纳秒级。


Instant instant = Instant.now();  // 获取当前时间戳
System.out.println(instant);  // 输出:时间戳,例如 2024-11-06T07:30:45.987654Z

Instant parsedInstant = Instant.parse("2024-11-06T07:30:45.987654Z");  // 通过字符串解析时间戳
System.out.println(parsedInstant);  // 输出:2024-11-06T07:30:45.987654Z

1.6 Duration(时间持续时长)

Duration 表示时间的持续时长,精确到秒和纳秒。它用于表示两个时间点之间的差异。


Duration duration = Duration.ofHours(5);  // 创建持续时长 5 小时
System.out.println(duration);  // 输出:PT5H

Duration durationBetween = Duration.between(LocalTime.of(14, 0), LocalTime.of(16, 30));  // 计算时间差
System.out.println(durationBetween);  // 输出:PT2H30M

1.7 Period(日期差)

Period 表示日期之间的差异,通常用于计算两个日期之间的年、月、日差。


Period period = Period.of(1, 2, 15);  // 表示 1 年 2 个月 15 天
System.out.println(period);  // 输出:P1Y2M15D

LocalDate startDate = LocalDate.of(2024, 1, 1);
LocalDate endDate = LocalDate.of(2024, 11, 6);
Period periodBetween = Period.between(startDate, endDate);  // 计算日期差
System.out.println(periodBetween);  // 输出:P10M5D

2. 时区( ZoneId ZoneOffset

ZoneId 表示时区ID,例如 "America/New_York""Asia/Shanghai",而 ZoneOffset 是与 UTC 的时差(例如 +08:00)的具体表示。

示例:


ZoneId zoneId = ZoneId.of("America/New_York");
ZonedDateTime zonedDateTimeInNY = ZonedDateTime.now(zoneId);
System.out.println(zonedDateTimeInNY);  // 输出:2024-11-06T07:30-05:00[America/New_York]

ZoneOffset zoneOffset = ZoneOffset.of("+02:00");
ZonedDateTime zonedDateTimeWithOffset = ZonedDateTime.now(zoneOffset);
System.out.println(zonedDateTimeWithOffset);  // 输出:2024-11-06T14:30+02:00

3. 日期时间 API 的格式化与解析

Java 8 提供了 DateTimeFormatter 类来处理日期时间的格式化和解析,它提供了灵活的格式化选项,可以将日期时间对象转换为字符串,或者从字符串中解析日期时间对象。

示例:


DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
String formattedDateTime = now.format(formatter);
System.out.println(formattedDateTime);  // 输出:2024-11-06 14:30:45

String dateStr = "2024-11-06 14:30:45";
LocalDateTime parsedDateTime = LocalDateTime.parse(dateStr, formatter);
System.out.println(parsedDateTime);  // 输出:2024-11-06T14:30:45

4. API 设计特点

  • 不可变性:所有的日期时间类(如 LocalDate, LocalTime, LocalDateTime 等)都是不可变的。这意味着这些类的实例在创建后不能被修改,避免了多线程环境下的同步问题。
  • 线程安全:由于不可变性,Java 8 的日期时间类是线程安全的,不需要显式的同步。
  • 清晰的命名:新的日期时间 API 提供了更具表达性的类名和方法,使得代码更加易于理解。
  • 更好的时区支持ZonedDateTimeZoneId 类大大简化了处理时区的复杂性。

总结

Java 8 的日期和时间 API(java.time 包)为日期和时间处理带来了更强大的功能,尤其在时区处理、日期计算和格式化等方面提供了更为直观、易用且线程安全的方案。它弥补了旧有 java.util.Datejava.util.Calendar 类的不足,成为处理日期和时间的标准工具。