manejo - Java 8: problemas de DateTimeFormatter e ISO_INSTANT con ZonedDateTime
manejo de horas en java (3)
El formateador ISO_INSTANT
está documentado here : "Este es un formateador de casos especial destinado a permitir una forma humana legible de un Instantáneo". Como tal, este formateador está diseñado para su uso con un Instant
no un ZonedDateTime
.
Formateo
Al formatear, ISO_INSTANT
puede formatear cualquier objeto temporal que pueda proporcionar ChronoField.INSTANT_SECONDS
y ChronoField.NANO_OF_SECOND
. Tanto Instant
como ZonedDateTime
pueden proporcionar estos dos campos, por lo que ambos funcionan:
// 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
Al analizar, ISO_INSTANT
solo producirá ChronoField.INSTANT_SECONDS
y ChronoField.NANO_OF_SECOND
. Se puede crear un Instant
desde esos dos campos, pero ZonedDateTime
requiere un ZoneId
:
Para analizar un ZonedDateTime
, es esencial que esté presente un ZoneId
zona ZoneId
. La zona horaria se puede (a) analizar a partir de la cadena, o (b) especificada para el formateador (usando 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);
Consulte la documentación para ISO_ZONED_DATE_TIME
, ISO_OFFSET_DATE_TIME
e ISO_DATE_TIME
(cualquiera de estos tres se puede usar para analizar un ZonedDateTime
sin especificar withZone()
).
Resumen
El formateador ISO_INSTANT
es un formateador de casos especiales diseñado para trabajar con Instant
. Si está utilizando un ZonedDateTime
, debe usar un formateador diferente, como ISO_DATE_TIME
o ISO_ZONED_DATE_TIME
.
Así que esperaría que este código funcionara bajo el nuevo paquete de fecha / hora Java 8 ya que todo lo que hace es convertir un ZonedDateTime dado en una cadena y viceversa utilizando la misma instancia incorporada de DateTimeFormatter (ISO_INSTANT):
ZonedDateTime now = ZonedDateTime.now();
System.out.println(ZonedDateTime.parse(
now.format(DateTimeFormatter.ISO_INSTANT),
DateTimeFormatter.ISO_INSTANT));
Pero aparentemente no:
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)
Ya he visto esta entrada, pero no me ayudó porque necesito un objeto ZonedDateTime y no uno local y también porque ya tengo 8u20 instalado: no se puede obtener ZonedDateTime de TemporalAccessor usando DateTimeFormatter y ZonedDateTime en Java 8
¿Alguien tiene alguna idea de lo que está pasando aquí?
No estoy seguro, pero esto podría ser un error en Java 8. Tal vez fue la intención de comportarse de esta manera, pero creo que la solución alternativa que voy a proponerle debe ser el comportamiento predeterminado (cuando no hay ZoneId especificado, simplemente tome el sistema predeterminado):
ZonedDateTime now = ZonedDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT
.withZone(ZoneId.systemDefault());
System.out
.println(ZonedDateTime.parse(now.format(formatter), formatter));
Hay un error similar que fue corregido en OpenJDK: JDK-8033662 , pero solo es similar, no exactamente lo mismo.
No sé si es el comportamiento esperado o no (probablemente lo sea) pero técnicamente el formateador ISO_INSTANT
no incluye un huso horario. Si lo intentas con un formateador DateTimeFormatter.ISO_ZONED_DATE_TIME
obtendrás lo que esperas.