No se puede analizar la cadena en formato ISO 8601, sin dos puntos en el desplazamiento, a Java 8 Date
parsing datetime (1)
Estoy un poco frustrado con la funcionalidad de formato / análisis de fecha de Java 8.
Estaba tratando de encontrar la configuración de Jackson y
DateTimeFormatter
para analizar la
"2018-02-13T10:20:12.120+0000"
a cualquier fecha de Java 8, y no lo encontré.
Este es el ejemplo de
java.util.Date
que funciona bien:
Date date = new SimpleDateFormat("yyyy-MM-dd''T''hh:mm:ss.SSSZZZ")
.parse("2018-02-13T10:20:12.120+0000");
El mismo formato no funciona con la nueva API de fecha y hora
ZonedDateTime dateTime = ZonedDateTime.parse("2018-02-13T10:20:12.120+0000",
DateTimeFormatter.ofPattern("yyyy-MM-dd''T''hh:mm:ss.SSSZZZ"));
Deberíamos poder formatear / analizar la fecha en cualquier formato adecuado para la aplicación FE UI.
Tal vez no entiendo o confundo algo, pero creo que
java.util.Date
brinda más flexibilidad de formato y es más fácil de usar.
tl; dr
Hasta que se solucione el error:
OffsetDateTime.parse(
"2018-02-13T10:20:12.120+0000" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd''T''HH:mm:ss.SSSX" )
)
Cuando se corrige el error:
OffsetDateTime.parse( "2018-02-13T10:20:12.120+0000" )
Detalles
Estás usando las clases equivocadas.
Evite las antiguas clases problemáticas, como
Date
,
Calendar
y
SimpleDateFormat
.
Ahora suplantado por las clases
java.time
.
La clase
ZonedDateTime
que usó es buena, es parte de java.time.
Pero está destinado a una zona horaria completa.
Su cadena de entrada tiene simplemente un
offset-from-UTC
.
Una zona horaria completa, en contraste, es una colección de compensaciones vigentes para una región en diferentes puntos en el tiempo, pasado, presente y futuro.
Por ejemplo, con el horario de verano (DST) en la mayor parte de América del Norte, las compensaciones cambian dos veces al año y se vuelven más pequeñas en la primavera a medida que adelantamos los relojes una hora, y restauramos a un valor más largo en el otoño cuando los retrasamos hora.
OffsetDateTime
Para solo un desplazamiento en lugar de una zona horaria, use la clase
OffsetDateTime
.
Su cadena de entrada cumple con el estándar ISO 8601 . Las clases java.time utilizan los formatos estándar de forma predeterminada al analizar / generar cadenas. Por lo tanto, no es necesario especificar un patrón de formato.
OffsetDateTime odt = OffsetDateTime.parse( "2018-02-13T10:20:12.120+0000" );
Bueno, eso
debería
haber funcionado.
Desafortunadamente, hay un
error en Java 8
(al menos hasta la Actualización 121 de Java 8) en el que esa clase no puede analizar un desplazamiento omitiendo los dos puntos entre horas y minutos.
Entonces el error muerde en
+0000
pero no en
+00:00
.
Entonces, hasta que llegue una solución, tiene la opción de dos soluciones: (a) un truco, manipulando la cadena de entrada, o (b) defina un patrón de formato explícito.
El truco: manipula la cadena de entrada para insertar los dos puntos.
String input = "2018-02-13T10:20:12.120+0000".replace( "+0000" , "+00:00" );
OffsetDateTime odt = OffsetDateTime.parse( input );
DateTimeFormatter
La solución más sólida es definir y pasar un patrón de formato en un objeto
DateTimeFormatter
.
String input = "2018-02-13T10:20:12.120+0000" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd''T''HH:mm:ss.SSSX" );
OffsetDateTime odt = OffsetDateTime.parse( input , f );
odt.toString (): 2018-02-13T10: 20: 12.120Z
Por cierto, aquí hay un consejo: descubrí que con muchos protocolos y bibliotecas, su vida es más fácil si sus desplazamientos siempre tienen dos puntos, siempre tienen horas y minutos (incluso si los minutos son cero) y siempre usan un relleno cero (
-05:00
lugar de
-5
).
DateTimeFormatterBuilder
Para un formateador más flexible, creado a través de
DateTimeFormatterBuilder
, vea
esta excelente respuesta
en una pregunta duplicada.
Instant
Si desea trabajar con valores que siempre están en UTC (y debería hacerlo), extraiga un objeto
Instant
.
Instant instant = odt.toInstant();
ZonedDateTime
Si desea ver ese momento a través de la lente del reloj de pared de alguna región, aplique una zona horaria.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );
Vea este código en vivo en IdeOne.com .
Todo esto se ha cubierto muchas veces en muchas respuestas para muchas preguntas. Busque a fondo antes de publicar. Habría descubierto muchas docenas, si no cientos, de ejemplos.
Sobre java.time
El marco
java.time
está integrado en Java 8 y
java.time
posteriores.
Estas clases suplantan a las antiguas clases problemáticas de fecha y hora
legacy
, como
java.util.Date
,
Calendar
y
SimpleDateFormat
.
El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .
Para obtener más información, consulte el Tutorial de Oracle . Y busque para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .
Puede intercambiar objetos
java.time
directamente con su base de datos.
Utilice un
controlador JDBC
compatible con
JDBC 4.2
o posterior.
No necesita cadenas, no necesita clases
java.sql.*
.
¿Dónde obtener las clases java.time?
-
Java SE 8
,
Java SE 9
,
Java SE 10
y posterior
- Incorporado.
- Parte de la API Java estándar con una implementación integrada.
- Java 9 agrega algunas características menores y correcciones.
-
Java SE 6
y
Java SE 7
- Gran parte de la funcionalidad java.time se transfiere a Java 6 y 7 en ThreeTen-Backport .
-
Android
- Versiones posteriores de las implementaciones de paquetes de Android de las clases java.time .
- Para Android anterior (<26), el proyecto ThreeTen-Backport adapta ThreeTen-Backport (mencionado anteriormente). Vea Cómo usar ThreeTenABP ...
El proyecto
ThreeTen-Extra
extiende java.time con clases adicionales.
Este proyecto es un campo de pruebas para posibles adiciones futuras a java.time.
Puede encontrar algunas clases útiles aquí, como
Interval
,
YearWeek
,
YearQuarter
y
more
.