Java 8 – DateTimeFormatter- und ISO_INSTANT-Probleme mit ZonedDateTime
Lesezeit: 3 Minuten
asieira
Ich würde also erwarten, dass dieser Code unter dem neuen Java 8-Datums-/Uhrzeitpaket funktioniert, da er lediglich eine bestimmte ZonedDateTime in eine Zeichenfolge und zurück konvertiert, indem dieselbe integrierte DateTimeFormatter-Instanz (ISO_INSTANT) verwendet wird:
ZonedDateTime now = ZonedDateTime.now();
System.out.println(ZonedDateTime.parse(
now.format(DateTimeFormatter.ISO_INSTANT),
DateTimeFormatter.ISO_INSTANT));
Aber anscheinend nicht:
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)
Ich habe diesen Eintrag bereits gesehen, aber er hat mir nicht geholfen, weil ich ein ZonedDateTime-Objekt und kein lokales Objekt brauche und auch weil ich bereits 8u20 installiert habe: Unable to abgerufen ZonedDateTime from TemporalAccessor using DateTimeFormatter and ZonedDateTime in Java 8
Hat jemand eine Ahnung, was hier passiert?
Joda Stephen
Das ISO_INSTANT Formatierer ist dokumentiert hier – “Dies ist ein Sonderfall-Formatierer, der eine für Menschen lesbare Form eines Instants ermöglichen soll”. Daher ist dieser Formatierer für die Verwendung mit einer Instant kein ZonedDateTime.
Formatierung
Beim Formatieren ISO_INSTANT kann jedes zeitliche Objekt formatieren, das bereitstellen kann ChronoField.INSTANT_SECONDS und ChronoField.NANO_OF_SECOND. Beide Instant und ZonedDateTime kann diese beiden Felder bereitstellen, daher funktionieren beide:
// 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
Beim Analysieren ISO_INSTANT wird nur produzieren ChronoField.INSTANT_SECONDS und ChronoField.NANO_OF_SECOND. Ein Instant kann aus diesen beiden Feldern gebaut werden, aber ZonedDateTime benötigt ein ZoneId auch:
Analysieren von a ZonedDateTime Es ist wichtig, dass eine Zeitzone ZoneId ist anwesend. Die Zeitzone kann (a) aus der Zeichenfolge geparst oder (b) für den Formatierer (mithilfe von JDK 8u20) angegeben werden:
// 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);
Das ISO_INSTANT formatter ist ein Sonderfall-Formatierer, mit dem gearbeitet werden kann Instant. Wenn Sie eine verwenden ZonedDateTime Sie sollten einen anderen Formatierer verwenden, z ISO_DATE_TIME oder ISO_ZONED_DATE_TIME.
Das Seltsame daran ist, dass das abschließende Z in der generierten Zeichenfolge eine Zeitzonenkennung für UTC ist, die Zeichenfolge also eine Zeitzonenkennung enthält (en.wikipedia.org/wiki/ISO_8601#Time_zone_designators). Die Dokumentation besagt jedoch, dass dies nur für Augenblicke funktioniert, also haben Sie absolut Recht. Vielen Dank.
– asieira
2. September 2014 um 13:31 Uhr
Ich bin mir nicht sicher, aber das könnte ein Fehler in Java 8 sein. Vielleicht sollte es sich so verhalten, aber ich denke, dass die Problemumgehung, die ich Ihnen vorschlagen werde, das Standardverhalten sein sollte (wenn keine ZoneId ist angegeben, nehmen Sie einfach den Systemstandard):
Es gibt einen ähnlichen Fehler, der in OpenJDK behoben wurde: JDK-8033662 – aber es ist nur ähnlich, nicht genau gleich.
Assyrien
Ich weiß nicht, ob es das erwartete Verhalten ist oder nicht (es ist wahrscheinlich), aber technisch gesehen das ISO_INSTANT formatter enthält keine Zeitzone. Versucht man es mit a DateTimeFormatter.ISO_ZONED_DATE_TIME Formatter stattdessen erhalten Sie, was Sie erwarten.
Wenn Sie verwenden org.threeten.bp aus Java 1.8Hier ist ein Spickzettel zum Umgang mit String to Date und umgekehrt.
Datum in Zeichenfolge
val date = Date()
val calendar = Calendar.getInstance().apply { time = date }
val zonedDateTime = DateTimeUtils.toZonedDateTime(calendar)
val formattedDate = DateTimeFormatter.ISO_INSTANT.format(zonedDateTime)
Zeichenfolge bis Datum
val dateString = "2020-03-04T09:04:43.835Z"
val dateInstant = Instant.from(DateTimeFormatter.ISO_INSTANT.parse(dateString))
DateTimeUtils.toDate(dateInstant)
14362000cookie-checkJava 8 – DateTimeFormatter- und ISO_INSTANT-Probleme mit ZonedDateTimeyes