以下代码打印带有时区偏移量的字符串中日期的输出。
String BERLIN_TIME_ZONE = "Europe/Berlin";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ssZ");
String dateTimeInString = formatter
.format(ZonedDateTime.of(LocalDateTime.now(), ZoneId.of(BERLIN_TIME_ZONE)));
System.out.println(dateTimeInString); // 2021-06-07T02:12:08+0200
这非常好用。现在,当我们有了dateTimeInString
时,我想使用parse
方法将它转换回LocalDateTime
对象。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ssZ");
System.out.println(LocalDateTime.parse(dateTimeInString,formatter));
但是这个解析抛出了一个异常。
Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-06-07T02:12:08+0200' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {SecondOfMinute=8, MinuteOfHour=12, HourOfAmPm=2, OffsetSeconds=7200, NanoOfSecond=0, MilliOfSecond=0, MicroOfSecond=0},ISO resolved to 2021-06-07 of type java.time.format.Parsed
at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
at de.finhome.A.main(A.java:19)
Caused by: java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: {SecondOfMinute=8, MinuteOfHour=12, HourOfAmPm=2, OffsetSeconds=7200, NanoOfSecond=0, MilliOfSecond=0, MicroOfSecond=0},ISO resolved to 2021-06-07 of type java.time.format.Parsed
at java.base/java.time.LocalDateTime.from(LocalDateTime.java:461)
at java.base/java.time.format.Parsed.query(Parsed.java:235)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
... 2 more
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {SecondOfMinute=8, MinuteOfHour=12, HourOfAmPm=2, OffsetSeconds=7200, NanoOfSecond=0, MilliOfSecond=0, MicroOfSecond=0},ISO resolved to 2021-06-07 of type java.time.format.Parsed
at java.base/java.time.LocalTime.from(LocalTime.java:431)
at java.base/java.time.LocalDateTime.from(LocalDateTime.java:457)
... 4 more
我检查了不同的资源,但找不出问题。
将小时标记从hh
更改为HH
。小写h
为0-12,即文档所称的上午至下午的时钟小时。大写H
为0-23,即文档所称的一天中的小时。
虽然格式化程序在输出日期时可以很乐意地执行,但当您尝试读取同一字符串时,会产生歧义。解析器不知道...T01:...
应该是1AM还是PM。由于它不能明确地解析,所以它失败了。
或者,在AM/PM的格式字符串中添加一些内容(可以使用a
(。然后,解析器将能够明确地解释一个小时,例如01。
似乎您还想将LocalDateTime.parse
更改为ZonedDateTime.parse
,这样您就不会放弃该区域。
这看起来不像是应该使用LocalDateTime
的情况。
有两种选择:ZonedDateTime
(您已经使用过(和OffsetDateTime
(您可能想要使用(。。。
如果您想提供一个区域,在该区域中获取当前时间,并在没有显式区域但带有该区域偏移的情况下打印结果,那么我建议在大部分时间内使用ZonedDateTime
。
这样做:
public static void main(String[] args) {
// provide a zone
String BERLIN_TIME_ZONE = "Europe/Berlin";
// use ZonedDateTime.now() directly and pass the zone
ZonedDateTime nowBerlin = ZonedDateTime.now(ZoneId.of(BERLIN_TIME_ZONE));
// then create a String that actually keeps the offset and omits the zone
String dateTimeInString = nowBerlin.format(
DateTimeFormatter.ISO_OFFSET_DATE_TIME
);
// print the result
System.out.println(dateTimeInString);
// if you now want to convert back, use an OffsetDateTime
OffsetDateTime nowPlus2h = OffsetDateTime.parse(dateTimeInString);
// and print the result
System.out.println(nowPlus2h.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
// if you want it to not just be a time of 2 hours offset, apply the zone again
ZonedDateTime nowAgainBerlin = nowPlus2h.atZoneSameInstant(
ZoneId.of(BERLIN_TIME_ZONE)
);
// check if that's the same as parsed in the beginning
if (nowAgainBerlin.equals(nowBerlin)) {
System.out.println("Same instant in Berlin");
} else {
System.out.println("Something went wrong in Berlin");
}
// and if you really want to get a LocalDateTime, you can get it like this
LocalDateTime localBerlin = nowBerlin.toLocalDateTime();
LocalDateTime localAgainBerlin = nowPlus2h.toLocalDateTime();
System.out.println(localBerlin + " == " + localAgainBerlin);
}
这只是输出
2021-06-07T15:16:47.259+02:00
2021-06-07T15:16:47.259+02:00
Same instant in Berlin
2021-06-07T15:16:47.259 == 2021-06-07T15:16:47.259
如果你想在输出中不包含millis,那么定义一个适合你需求的格式化程序,但仍然无法将区域或偏移解析为LocalDateTime
。