Java 8 - ZonedDateTime 的 DateTimeFormatter 和 ISO_INSTANT 问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25612129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java 8 - DateTimeFormatter and ISO_INSTANT issues with ZonedDateTime
提问by asieira
So I would expect this code to work under the new Java 8 date/time package since all it does is to convert a given ZonedDateTime to string and back using the same built-in DateTimeFormatter instance (ISO_INSTANT):
所以我希望这段代码可以在新的 Java 8 日期/时间包下工作,因为它所做的只是使用相同的内置 DateTimeFormatter 实例 (ISO_INSTANT) 将给定的 ZonedDateTime 转换为字符串并返回:
ZonedDateTime now = ZonedDateTime.now();
System.out.println(ZonedDateTime.parse(
now.format(DateTimeFormatter.ISO_INSTANT),
DateTimeFormatter.ISO_INSTANT));
But apparently it doesn't:
但显然它没有:
Exception in thread "main" java.time.format.DateTimeParseException: Text '2014-09-01T19:37:48.549Z' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {MilliOfSecond=549, NanoOfSecond=549000000, MicroOfSecond=549000, InstantSeconds=1409600268},ISO of type java.time.format.Parsed
at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1918)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1853)
at java.time.ZonedDateTime.parse(ZonedDateTime.java:597)
I have seen this entry already, but it didn't help me because a need a ZonedDateTime object and not a local one and also because I already have 8u20 installed: Unable to obtain ZonedDateTime from TemporalAccessor using DateTimeFormatter and ZonedDateTime in Java 8
我已经看过这个条目,但它对我没有帮助,因为需要一个 ZonedDateTime 对象而不是本地对象,还因为我已经安装了 8u20:无法使用 Java 8 中的 DateTimeFormatter 和 ZonedDateTime 从 TemporalAccessor 获取 ZonedDateTime
Anyone have any idea what's happening here?
有人知道这里发生了什么吗?
采纳答案by JodaStephen
The ISO_INSTANT
formatter is documented here- "This is a special case formatter intended to allow a human readable form of an Instant". As such, this formatter is intended for use with an Instant
not a ZonedDateTime
.
该ISO_INSTANT
格式是记录在这里- “这是格式化旨在允许即时的人类可读形式的特殊情况”。因此,此格式化程序旨在与Instant
not a 一起使用ZonedDateTime
。
Formatting
格式化
When formatting, ISO_INSTANT
can format any temporal object that can provide ChronoField.INSTANT_SECONDS
and ChronoField.NANO_OF_SECOND
. Both Instant
and ZonedDateTime
can provide these two fields, thus both work:
格式化时,ISO_INSTANT
可以格式化任何可以提供ChronoField.INSTANT_SECONDS
和的时态对象ChronoField.NANO_OF_SECOND
。双方Instant
并ZonedDateTime
能提供这两个领域,因此这两种工作方式:
// works with Instant
Instant instant = Instant.now();
System.out.println(DateTimeFormatter.ISO_INSTANT.format(instant));
// works with ZonedDateTime
ZonedDateTime zdt = ZonedDateTime.now();
System.out.println(zdt.format(DateTimeFormatter.ISO_INSTANT));
// example output
2014-09-02T08:05:23.653Z
Parsing
解析
When parsing, ISO_INSTANT
will only produce ChronoField.INSTANT_SECONDS
and ChronoField.NANO_OF_SECOND
. An Instant
can be built from those two fields, but ZonedDateTime
requires a ZoneId
as well:
解析时,ISO_INSTANT
只会产生ChronoField.INSTANT_SECONDS
和ChronoField.NANO_OF_SECOND
。AnInstant
可以从这两个字段构建,但也ZonedDateTime
需要一个ZoneId
:
To parse a ZonedDateTime
it is essential that a time-zone ZoneId
is present. The time-zone can be (a) parsed from the string, or (b) specified to the formatter (using JDK 8u20):
要解析 aZonedDateTime
必须存在时区ZoneId
。时区可以 (a) 从字符串中解析,或 (b) 指定给格式化程序(使用 JDK 8u20):
// option a - parsed from the string
DateTimeFormatter f = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime zdt = ZonedDateTime.parse("2014-09-02T08:05:23.653Z", f);
// option b - specified in the formatter - REQUIRES JDK 8u20 !!!
DateTimeFormatter f = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.systemDefault());
ZonedDateTime zdt = ZonedDateTime.parse("2014-09-02T08:05:23.653Z", f);
See documentation for ISO_ZONED_DATE_TIME
, ISO_OFFSET_DATE_TIME
and ISO_DATE_TIME
(any of these three can be used to parse a ZonedDateTime
without specifying withZone()
).
请参阅ISO_ZONED_DATE_TIME
,ISO_OFFSET_DATE_TIME
和ISO_DATE_TIME
(这三个中的任何一个都可用于解析 aZonedDateTime
而不指定withZone()
)的文档。
Summary
概括
The ISO_INSTANT
formatter is a special case formatter designed to work with Instant
. If you are using a ZonedDateTime
you should use a different formatter, such as ISO_DATE_TIME
or ISO_ZONED_DATE_TIME
.
该ISO_INSTANT
格式是一种特殊情况下格式化旨在与工作Instant
。如果您使用的是ZonedDateTime
,则应使用不同的格式化程序,例如ISO_DATE_TIME
或ISO_ZONED_DATE_TIME
。
回答by Cristina
I'm not sure, but this might be a bug in Java 8. Maybe it was intended to behave in this way, but I think that the workaround I'm going to propose to you should be the default behavior (when no ZoneId is specified, just take system default):
我不确定,但这可能是 Java 8 中的一个错误。也许它本打算以这种方式行事,但我认为我要向您提出的解决方法应该是默认行为(当没有 ZoneId 时)指定,只需采用系统默认值):
ZonedDateTime now = ZonedDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT
.withZone(ZoneId.systemDefault());
System.out
.println(ZonedDateTime.parse(now.format(formatter), formatter));
There's a similar bug which was fixed in OpenJDK: JDK-8033662- but it's only similar, not exactly the same.
OpenJDK 中修复了一个类似的错误:JDK-8033662- 但它只是相似,不完全相同。
回答by assylias
I don't know if it is the expected behaviour or not (it probably is) but technically the ISO_INSTANT
formatter does not include a time zone. If you try with a DateTimeFormatter.ISO_ZONED_DATE_TIME
formatter instead you will get what you expect.
我不知道这是否是预期的行为(可能是),但从技术上讲,ISO_INSTANT
格式化程序不包含时区。如果您尝试使用DateTimeFormatter.ISO_ZONED_DATE_TIME
格式化程序,您将得到您所期望的。
回答by Morgan Koh
If you're using org.threeten.bp
from Java 1.8, here's a Cheat Sheeton dealing with String to Date and vice versa.
如果您org.threeten.bp
从Java 1.8开始使用,这里有一个关于处理字符串到日期的备忘单,反之亦然。
Date to String
日期到字符串
val date = Date()
val calendar = Calendar.getInstance().apply { time = date }
val zonedDateTime = DateTimeUtils.toZonedDateTime(calendar)
val formattedDate = DateTimeFormatter.ISO_INSTANT.format(zonedDateTime)
String to Date
字符串到日期
val dateString = "2020-03-04T09:04:43.835Z"
val dateInstant = Instant.from(DateTimeFormatter.ISO_INSTANT.parse(dateString))
DateTimeUtils.toDate(dateInstant)