在时区将 ZonedDateTime 转换为 LocalDateTime

Posted

技术标签:

【中文标题】在时区将 ZonedDateTime 转换为 LocalDateTime【英文标题】:Convert ZonedDateTime to LocalDateTime at time zone 【发布时间】:2018-09-25 23:56:43 【问题描述】:

我有一个像这样构造的 ZonedDateTime 对象

ZonedDateTime z = ZonedDateTime.of(LocalDate.now().atTime(11, 30), ZoneOffset.UTC);

如何将其转换为瑞士时区的LocalDateTime?预期结果应该是16 april 2018 13:30

【问题讨论】:

顺便说一句,也将ZoneId 传递给LocalDate.now() 以获得可预测的结果。世界各地的日期永远不会相同。 【参考方案1】:

有很多方法可以实现您想要的。其中一些如下:

    将给定的ZonedDateTime 转换为Instant 并从Instant 派生LocalDateTime
ZonedDateTime zdtUtc = ZonedDateTime.of(LocalDate.now().atTime(11, 30), ZoneOffset.UTC);

Instant instant = zdtUtc.toInstant();

LocalDateTime ldtSwitzerland = LocalDateTime.ofInstant(instant, ZoneId.of("Europe/Zurich"));

ONLINE DEMO

    使用ZonedDateTime#withZoneSameInstant将给定的ZonedDateTime转换为所需时区的ZonedDateTime,然后从ZonedDateTime获取LocalDateTime
ZonedDateTime zdtUtc = ZonedDateTime.of(LocalDate.now().atTime(11, 30), ZoneOffset.UTC);

ZonedDateTime zdtSwitzerland = zdtUtc.withZoneSameInstant(ZoneId.of("Europe/Zurich"));

LocalDateTime ldtSwitzerland = zdtSwitzerland.toLocalDateTime();

ONLINE DEMO

    将给定的ZonedDateTime 转换为Instant 可以使用Instant#atZone 转换为ZonedDateTime,然后从ZonedDateTime 中获取LocalDateTime
ZonedDateTime zdtUtc = ZonedDateTime.of(LocalDate.now().atTime(11, 30), ZoneOffset.UTC);

Instant instant = zdtUtc.toInstant();

ZonedDateTime zdtSwitzerland = instant.atZone(ZoneId.of("Europe/Zurich"));

LocalDateTime ldtSwitzerland = zdtSwitzerland.toLocalDateTime();

ONLINE DEMO

    使用DateTimeFormatter 将给定的ZonedDateTime 格式化为与所需时区相关的日期时间字符串,然后通过解析获得的日期时间字符串导出LocalDateTime注意:此方法仅用于您的学习目的;您应该在生产代码中实现第一种方式(最顶层)。
ZonedDateTime zdtUtc = ZonedDateTime.of(LocalDate.now().atTime(11, 30), ZoneOffset.UTC);

DateTimeFormatter dtfSwitzerland = DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(ZoneId.of("Europe/Zurich"));
String strZdtSwitzerland = dtfSwitzerland.format(zdtUtc);

LocalDateTime ldt = LocalDateTime
        .from(DateTimeFormatter.ISO_LOCAL_DATE_TIME.parse(strZdtSwitzerland, new ParsePosition(0)));

ONLINE DEMO

Trail: Date Time 了解有关现代日期时间 API 的更多信息。

【讨论】:

【参考方案2】:

另一个看起来更直观的选项是将分区日期转换为瞬间,然后使用 LocalDateTime.ofInstant:

ZonedDateTime zdt = ZonedDateTime.of(LocalDate.now().atTime(11, 30), ZoneOffset.UTC);
ZoneId zId = ZoneId.of("US/Central");
LocalDateTime l = LocalDateTime.ofInstant(zdt.toInstant(), zId);

比起withZoneSameInstant,我更喜欢这个解决方案,因为该解决方案更加不透明——您得到的 ZonedDateTime 必须处于特定的内部状态(正确的时区)。使用ofInstant 可以在任何时区的任何 ZonedDateTime 上使用。

【讨论】:

【参考方案3】:

这有助于理解 LocalDateTime 和 ZonedDateTime 之间的区别。你真正想要的是ZonedDateTime。如果您想从字符串表示中删除时区,请将其转换为 LocalDateTime

您正在寻找的是: ZonedDateTime swissZonedDateTime = withZoneSameInstant(ZoneId.of("Europe/Zurich"));

LocalDateTime - 这基本上是DateTime 的美化字符串表示;它与时区无关,这意味着它不代表时间线上的任何时间点

即时 - 这是自 EPOCH 以来经过的时间的毫秒表示。这表示时间轴上的特定时刻

ZonedDateTime - 这也表示时间轴上的某个时刻,它表示为 DateTime 以及 TimeZone

下面的代码说明了如何使用所有 3。

LocalDateTime localDateTime = LocalDateTime.of(2018, 10, 25, 12, 00, 00);  //October 25th at 12:00pm
ZonedDateTime zonedDateTimeInUTC = localDateTime.atZone(ZoneId.of("UTC")); 
ZonedDateTime zonedDateTimeInEST = zonedDateTimeInUTC.withZoneSameInstant(ZoneId.of("America/New_York")); 
    
System.out.println(localDateTime.toString()); // 018-10-25T12:00
System.out.println(zonedDateTimeInUTC.toString()); // 2018-10-25T12:00Z[UTC]
System.out.println(zonedDateTimeInEST.toString()); // 2018-10-25T08:00-04:00[America/New_York]

如果您从上面比较两个ZonedDateTimesInstant 值,它们将是等价的,因为它们都指向同一时刻。在格林威治的某个地方(UTC 时区),是 10 月 25 日中午;同时,在纽约,应该是早上 8 点(美国/纽约时区)。

【讨论】:

【参考方案4】:

如何将其转换为瑞士时区的 LocalDateTime?

如果需要,您可以将 UTC ZonedDateTime 转换为具有瑞士时区的 ZonedDateTime,但保持同一时刻,然后从中取出 LocalDateTime。我很想将它保留为ZonedDateTime,除非您出于其他原因需要它作为LocalDateTime

ZonedDateTime utcZoned = ZonedDateTime.of(LocalDate.now().atTime(11, 30), ZoneOffset.UTC);
ZoneId swissZone = ZoneId.of("Europe/Zurich");
ZonedDateTime swissZoned = utcZoned.withZoneSameInstant(swissZone);
LocalDateTime swissLocal = swissZoned.toLocalDateTime();

【讨论】:

【参考方案5】:

试试这个。用您的时区替换 US/Central。

ZonedDateTime z = ZonedDateTime.of(LocalDate.now().atTime(11, 30), ZoneOffset.UTC);

System.out.println(z.withZoneSameInstant(ZoneId.of("US/Central")));

【讨论】:

以上是关于在时区将 ZonedDateTime 转换为 LocalDateTime的主要内容,如果未能解决你的问题,请参考以下文章

Java ZonedDateTime转换成 LocalDateTime方法代码及之间区别

如何从 org.joda.time.DateTime 转换为 java.time.ZonedDateTime

Java不通过JVM设置时区时间

如何在 Java 中将 ZonedDateTime 转换为毫秒?

杰克逊:使用时区 id 解析 ZonedDateTime

如何使用 ZonedDateTime 或 Java 8 将任何日期时间转换为 UTC