Java 8 引入了全新的日期和时间 API (java.time 包),旨在替代老旧的 java.util.Date、java.util.Calendar 和 java.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 提供了更具表达性的类名和方法,使得代码更加易于理解。
- 更好的时区支持:
ZonedDateTime和ZoneId类大大简化了处理时区的复杂性。
总结
Java 8 的日期和时间 API(java.time 包)为日期和时间处理带来了更强大的功能,尤其在时区处理、日期计算和格式化等方面提供了更为直观、易用且线程安全的方案。它弥补了旧有 java.util.Date 和 java.util.Calendar 类的不足,成为处理日期和时间的标准工具。