Java8中使用 Timezone 格式化 LocalDateTime

我有一个简单的密码:

DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss.SSSSSS Z");
LocalDateTime.now().format(FORMATTER)

那么我会得到以下例外:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds
at java.time.LocalDate.get0(LocalDate.java:680)
at java.time.LocalDate.getLong(LocalDate.java:659)
at java.time.LocalDateTime.getLong(LocalDateTime.java:720)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
at java.time.format.DateTimeFormatterBuilder$OffsetIdPrinterParser.format(DateTimeFormatterBuilder.java:3315)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1745)
at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1719)
at java.time.LocalDateTime.format(LocalDateTime.java:1746)

如何解决这个问题?

175554 次浏览

LocalDateTime 是一个没有时区的日期时间。您在格式中指定了时区偏移量格式符号,但是,LocalDateTime没有这样的信息。这就是错误发生的原因。

如果需要时区信息,应该使用 ZonedDateTime

DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss.SSSSSS Z");
ZonedDateTime.now().format(FORMATTER);
=> "20140829 14:12:22.122000 +09"

JSR-310中的前缀“ Local”(在 Java-8中又名 java.time-package)并不表示该类的内部状态中有一个时区信息(这里是 LocalDateTime)。尽管像 ABC0或 LocalTime没有时区信息或偏移量这样的类的名字常常具有误导性。

您尝试使用偏移量信息(由模式符号 Z 表示)来格式化这种时态类型(它不包含任何偏移量)。因此,格式化程序将尝试访问不可用的信息,并且必须抛出所观察到的异常。

解决方案:

使用具有这种偏移量或时区信息的类型。在 JSR-310中,它是 OffsetDateTime(包含偏移量但不包含 DST 规则的时区)或 ZonedDateTime。您可以通过查找方法 IsSupport (颞字段)。来查看这种类型的所有受支持字段。字段 OffsetSecondsOffsetDateTimeZonedDateTime中受支持,但在 LocalDateTime中不受支持。

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss.SSSSSS Z");
String s = ZonedDateTime.now().format(formatter);

现有的答案是正确的,但遗漏了一些关键信息。

  1. 虽然 Z只表示时区偏移量,但是 V表示时区 ID,它为 ZonedDateTime提供标识。从 DateTimeFormatter 文件了解更多关于它的信息。虽然一个地方的时区 ID 是固定的,但是如果该地方观察到 DST,时区偏移量就会发生变化(例如,欧洲/伦敦夏天偏移量为 + 01:00,冬天偏移量为 + 00:00)。
  2. 在使用日期时间解析/格式化 API 时,应始终使用 Locale,因为它们对 Locale敏感。查看 不要在没有语言环境的情况下使用 Date-Time 格式化/解析 API以了解更多信息。
  3. 因为 LocalDateTime不包含任何关于时区的信息,所以它的格式应该不包含任何表示时区相关信息的字母。很明显,LocalDateTime的格式化程序总是可以用来格式化 ZonedDateTime,但反过来可能会失败(如果它包含与时区相关的字符)。如果需要,表示系统时区的 ZonedDateTime可以从 LocalDateTime派生出来。
  4. 我也是 比起你,我更喜欢你DateTimeFormatter

演示 :

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;


public class Main {
public static void main(String[] args) {
DateTimeFormatter ldtFormatter = DateTimeFormatter.ofPattern("uuuuMMdd HH:mm:ss.SSSSSS", Locale.ENGLISH);
System.out.println(LocalDateTime.now().format(ldtFormatter));


// ZZZZZ can be replaced with XXX
DateTimeFormatter zdtFormatter = DateTimeFormatter.ofPattern("uuuuMMdd HH:mm:ss.SSSSSS VV ZZZZZ",
Locale.ENGLISH);
System.out.println(ZonedDateTime.now().format(zdtFormatter));
System.out.println(ZonedDateTime.now().getZone());


// Deriving ZonedDateTime from LocalDateTime using system's time zone
LocalDateTime ldt = LocalDateTime.of(LocalDate.of(2022, 12, 15), LocalTime.of(10, 20, 30));
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
System.out.println(zdt.format(zdtFormatter));
}
}

产出 :

20221013 20:55:13.466830
20221013 20:55:13.468847 Europe/London +01:00
Europe/London
20221215 10:20:30.000000 Europe/London Z

Rel = “ nofollow noReferrer”> Trail: Date Time 学习更多关于 现代日期时间 API的知识。