util manejo horas fechas example ejemplo java java-8 java-time

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.