将ZonedDateTime转换为时区为LocalDateTime

54

我有一个ZonedDateTime对象,它是这样构造的

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

我该如何将它转换成瑞士时区的LocalDateTime?预期结果应为2018年4月16日 13:30


1
顺便提一下,向 LocalDate.now() 传递一个 ZoneId 可以获得可预测的结果。在全球各地,日期永远不会相同。 - Ole V.V.
5个回答

87

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

您可以将UTC的ZonedDateTime转换为具有瑞士时区的ZonedDateTime,但保持相同的时间点,然后从中获取LocalDateTime,如果需要的话。不过,除非您因某种其他原因需要它作为LocalDateTime,否则我建议将其保留为ZonedDateTime

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();

26

理解 LocalDateTimeZonedDateTime 之间的区别很有帮助。你实际上需要的是一个 ZonedDateTime。如果你想要从字符串表示中删除时区信息,那么你需要将其转换为 LocalDateTime

你要找的是:ZonedDateTime swissZonedDateTime = withZoneSameInstant(ZoneId.of("Europe/Zurich"));

LocalDateTime - 这基本上是 DateTime 的一个炫耀的字符串表示形式;它是无时区的,这意味着它不代表时间轴上的任何时间点

Instant - 这是自 EPOCH 以来经过的毫秒表示的时间。它代表时间轴上特定的时间点

ZonedDateTime - 这也代表时间轴上的一个时间点,但是它表示为具有TimeZoneDateTime

下面的代码演示了如何使用这三个类。

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()); // 2018-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]
如果您比较上述两个ZonedDateTimeInstant值,它们将是等价的,因为它们都指向同一时刻。在格林威治的某处(UTC时区),现在是10月25日中午;同时,在纽约,现在是上午8点(美国/纽约时区)。

5

试试这个。将 US/Central 替换为你所在的时区。

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

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

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

另一个选择似乎更加直观,即将带有时区的日期转换为瞬时时间,然后使用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);

我更喜欢使用ofInstant而不是withZoneSameInstant,因为后者的解决方案比较难以理解 - 你得到了一个必须处于特定内部状态(正确的时区)的ZonedDateTime。使用ofInstant可以用于任何时区中的任何ZonedDateTime。

2

有很多方法可以实现你想要的目标。以下是其中一些:

  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"));

在线演示

  1. 使用 ZonedDateTime#withZoneSameInstant 将给定的 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();

在线演示

  1. 将给定的ZonedDateTime转换为可以使用Instant#atZone转换为ZonedDateTimeInstant,然后从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();

在线演示

  1. 使用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)));

在线演示

教程:日期时间了解更多关于现代化日期时间API的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接