LocalDateTime
总是标识本地日期和时间,要表示一个带时区的日期和时间,我们就需要ZonnedDateTime
。
可以简单的把ZonedDateTime理解成LocalDatetime加ZoneId。ZoneId
是java.time
引入的新的时区类,注意和旧的java.util.TimeZone
区别。
要创建一个ZonedDateTime
对象,有以下几种方法,一种是通过now()
方法返回当前时间:
ZonedDateTime zonedDateTime = ZonedDateTime.now(); // 默认时区
ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("America/New_York")); // 指定时区
System.out.println(zonedDateTime); // 2023-08-26T17:48:47.378072+08:00[Asia/Shanghai]
System.out.println(zonedDateTime1); // 2023-08-26T05:48:47.378924-04:00[America/New_York]
通过观察打印的两个ZonedDateTime,发现它们时区不同,但表示的时间都是同一时刻(毫秒数不同是执行语句时的时间差)。
另一种方式是通过给一个LocalDateTime附加一个ZoneId,就可以变成ZonedDateTime。
LocalDateTime localDateTime = LocalDateTime.of(2015, 5, 10, 11, 22, 33);
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
ZonedDateTime zonedDateTime2 = localDateTime.atZone(ZoneId.of("Europe/London"));
System.out.println(zonedDateTime); // 2015-05-10T11:22:33+08:00[Asia/Shanghai]
System.out.println(zonedDateTime2); // 2015-05-10T11:22:33+01:00[Europe/London]
以这种方式创建的ZonedDateTime,它的日期和时间与LocalDateTime相同,但附加的时区不同,因此是两个不同的时刻。
时区转换
要转换时区,首先我们需要有一个ZonedDateTime
对象,然后,通过withZoneSameInstant()
将关联时区转换到另一个时区,转换后日期和时间都会相应调整。
// 以中国时区获取当前时间:
ZonedDateTime zbj = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
// 转换为纽约时间:
ZonedDateTime zny = zbj.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(zbj); // 2023-08-26T17:55:47.001301+08:00[Asia/Shanghai]
System.out.println(zny); // 2023-08-26T05:56:02.208144-04:00[America/New_York]
要特别注意,时区转换的时候,由于夏令时的存在,不同的日期转换的结果很可能是不同的。这是北京时间9月15日的转换结果:
2019-09-15T21:05:50.187697+08:00[Asia/Shanghai]
2019-09-15T09:05:50.187697-04:00[America/New_York]
这是北京时间11月15日的转换结果:
2019-11-15T21:05:50.187697+08:00[Asia/Shanghai]
2019-11-15T08:05:50.187697-05:00[America/New_York]
两次转换后的纽约时间有1小时的夏令时时差。
有了ZonedDateTime
,将其转换为本地时间就非常简单:
ZonedDateTime zdt = ...
LocalDateTime ldt = zdt.toLocalDateTime();
转换为LocalDateTime
时,直接丢弃了时区信息。