一、ZonedDateTime 和 LocalDateTime 与 Date的区别
ZonedDateTime 和 LocalDateTime 与 Date 是 Java 中用于处理日期和时间的类,但它们之间存在显著差异。下面是它们的主要区别:
1. 引入时间
Date: 属于 java.util 包,是 Java 早期版本中用于表示日期和时间的类,最早在 JDK 1.0 中引入。设计简单但存在诸多缺陷,如不直接支持时区、难以进行日期和时间操作等。
ZonedDateTime 和 LocalDateTime: 属于 java.time 包,是 Java 8 中引入的新日期和时间 API 的一部分。新 API 提供了更强大、灵活的日期和时间处理功能,解决了 Date 类的许多问题。
2. 时区支持
Date: 实际上是一个时间戳,表示从 1970 年 1 月 1 日 00:00:00 GMT(UTC)以来的毫秒数。Date 对象本身不包含时区信息,默认使用系统时区来解释其值。
ZonedDateTime: 明确支持时区信息,包含了日期、时间和时区,可以准确地表示全球各地的时间。
LocalDateTime: 不包含时区信息,仅表示本地的日期和时间,与时区无关。
3. 不可变性
Date: 是可变的,即 Date 对象在创建后其值可以被修改。这容易导致线程安全问题。
ZonedDateTime 和 LocalDateTime: 是不可变的,创建后不能修改。这种设计使得它们更加安全且适用于多线程环境。
4. 表示的内容
Date: 实际上只是一个时间戳,并没有真正表示“日期”。通过 Date 对象可以提取日期和时间,但这些操作往往依赖于过时的 Calendar 类。
ZonedDateTime: 表示带有时区的完整日期和时间,包括年、月、日、小时、分钟、秒、纳秒以及时区信息。
LocalDateTime: 表示不带时区的日期和时间,包括年、月、日、小时、分钟、秒和纳秒。
5. 常用操作
Date: 提供的操作有限,通常需要借助 Calendar 类进行日期运算,如加减天数、月份等。
ZonedDateTime 和 LocalDateTime: 提供了丰富的操作方法,如日期加减、时间比较、日期计算、格式化等。
6. 格式化与解析
Date: 格式化和解析通常通过 SimpleDateFormat 完成,这个类是线程不安全的,使用时需要特别注意。
ZonedDateTime 和 LocalDateTime: 使用 DateTimeFormatter 进行格式化和解析。DateTimeFormatter 是线程安全的,并提供了更简洁和灵活的日期时间格式化支持。
7. 示例代码对比
Date 示例:
Date date = new Date();
System.out.println("当前时间 (Date): " + date);
ZonedDateTime 示例:
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println("当前时间 (ZonedDateTime): " + zonedDateTime);
LocalDateTime 示例:
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("当前时间 (LocalDateTime): " + localDateTime);
8. 兼容性
Date: 是旧版 API,在许多现有的 Java 库中仍然被广泛使用。为了兼容性,有时需要将新 API(ZonedDateTime、LocalDateTime 等)与 Date 互相转换。
ZonedDateTime 和 LocalDateTime: 是 Java 8 中引入的新 API,推荐在新项目中使用。它们提供了与 Date 的转换方法,如 Date.from(Instant) 和 ZonedDateTime.toInstant()。
9. 性能
Date: 较为简单,性能开销较小,但由于其功能有限,使用起来不够灵活。
ZonedDateTime 和 LocalDateTime: 功能强大,支持的操作更多,因此在某些复杂操作中可能略有性能开销,但通常这在现代应用中可以忽略不计。
10. 总结:
Date 是一个旧版的时间类,功能有限且不便于使用,尤其是对时区的处理。
ZonedDateTime 和 LocalDateTime 是 Java 8 引入的新时间 API,提供了更强大和灵活的日期和时间处理功能,推荐在新开发中使用。ZonedDateTime 特别适用于涉及全球不同时区的应用,
而 LocalDateTime 适用于仅关心本地时间的应用。
二、ZonedDateTime和Instant代码案例
国际化开发推荐使用JDK 8新版本api ZonedDateTime,Instant,
废弃JDK 1.0 旧版本的Date类、Calender类
demo 展示场景
1:获取指定时区时间、指定时区时间转时间戳、时间戳转指定时区时间、时间操作(加减天数等)
2:通过常见的24个时区验证代码能否正常运行
import net.dreamlu.mica.core.utils.$;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.stream.Stream;
public class ZoneDateTimeTest {
public static void main(String[] args) {
Stream<Integer> integerStream = Stream.of(-11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11);
integerStream.forEach(zone -> {
String zoneStr = zone.toString();
System.out.println("时区=" + zone.toString());
calcZoneAndTimestamp(zoneStr);
System.out.println(" ");
});
}
/*
* 国际化开发推荐使用JDK 8新版本api ZonedDateTime,Instant,
* 废弃JDK 1.0 旧版本的Date类、Calender类
* demo 展示场景
* 1:获取指定时区时间、指定时区时间转时间戳、时间戳转指定时区时间、时间操作(加减天数等)
* 2:通过常见的24个时区验证代码能否正常运行
*
**/
static public void calcZoneAndTimestamp(String zone) {
if ($.isNotEqual("UTC", zone) && !zone.startsWith("-") && !zone.startsWith("+")) {
zone = "+".concat(zone);
}
// 指定时区,例如 +9
ZoneId zoneId = ZoneId.of(zone);
// 获取指定时区的当前时间
ZonedDateTime zonedDateTime1 = ZonedDateTime.now(zoneId);
System.out.println("当前时间 (指定时区): " + zonedDateTime1);
// 获取当前时间到第二天凌晨的时间
ZonedDateTime zonedDateTime2 = zonedDateTime1.truncatedTo(ChronoUnit.DAYS).plusDays(1);
System.out.println("第二天凌晨时间 (指定时区): " + zonedDateTime2);
System.out.println("--------------------------------------------");
// 将ZonedDateTime转换为时间戳(秒数)
long timestamp1 = zonedDateTime1.toInstant().toEpochMilli();
long timestamp2 = zonedDateTime2.toInstant().toEpochMilli();
// 输出时间戳
System.out.println("当前时间的时间戳 (毫秒): " + timestamp1);
System.out.println("第二天凌晨时间的时间戳 (毫秒): " + timestamp2);
System.out.println("--------------------------------------------");
// 将时间戳转换为Instant
Instant instant1 = Instant.ofEpochMilli(timestamp1);
// 将Instant转换为指定时区的ZonedDateTime
ZonedDateTime zonedDateTime11 = instant1.atZone(zoneId);
// 将时间戳转换为Instant
Instant instant2 = Instant.ofEpochMilli(timestamp2);
// 将Instant转换为指定时区的ZonedDateTime
ZonedDateTime zonedDateTime22 = instant2.atZone(zoneId);
// 输出指定时区的时间
// 指定格式化输出
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format11 = zonedDateTime11.format(formatter);
System.out.println("(指定输出格式) 当前时间的时间戳 (毫秒) 转换为时间 (指定时区): " + format11);
String format22 = zonedDateTime22.format(formatter);
System.out.println("(指定输出格式) 第二天凌晨时间的时间戳 (毫秒) 转换为时间 (指定时区): " + format22);
System.out.println("--------------------------------------------");
}
}