Java: análisis de fechas, ¿por qué recibo un error?
date simpledateformat (3)
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SZ");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
Date test = dateFormat.parse(text);
Las primeras tres líneas funcionan bien. Cuando intento analizar la cadena en una fecha nuevamente, aparece un error. ¿Como puedo resolver esto?
El error se ve así:
Caused by: java.text.ParseException: Unparseable date: "2018-02-07T15:32:13.214+0100"
at java.text.DateFormat.parse(DateFormat.java:366) ~[na:1.8.0_151]
at TimeRange.parseDateFromIsoString(TimeRange.java:33) ~[classes/:na]
Eliminé Z en el formato de fecha simple que se relaciona con la zona horaria que da el fragmento correcto.
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.S");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
try {
Date test = dateFormat.parse(text);
} catch (ParseException e) {
e.printStackTrace();
}
Me gustaría contribuir con la respuesta moderna.
Porque desaliento el uso de
SimpleDateFormat
, más sobre eso más adelante.
java.time
OffsetDateTime dateTime = OffsetDateTime.now(ZoneId.of("Europe/Rome"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd''T''HH:mm:ss.SSSxx");
String text = dateTime.format(formatter);
OffsetDateTime test = OffsetDateTime.parse(text, formatter);
Esto produce una cadena como
2018-02-07T17:51:21.087+0100
, bastante cerca de lo que creo que
2018-02-07T17:51:21.087+0100
en la pregunta, y la analiza muy bien.
Con
SSS
en la cadena de patrón de formato, siempre produce 3 decimales en los segundos y también requiere exactamente 3 decimales por análisis.
Puede usar
S
o
SSSSSS
para obtener 1 o 6 decimales, por ejemplo.
En mi Java 9,
OffsetDateTime.now()
tiene una precisión de 6 decimales (microsegundos), por lo que si especifico menos, pierdo precisión en el formato.
EDITAR: por compatibilidad con versiones anteriores, no puede usar lo siguiente, pero para cualquiera que lea, me gustaría presentar una variante sin un formateador explícito:
String text = dateTime.toString();
OffsetDateTime test = OffsetDateTime.parse(text);
Las dos diferencias en la cadena producida son:
-
Produce tantos grupos de 3 decimales como sean necesarios para representar la precisión.
Por lo general, 3 decimales en mi Java 8 y 6 decimales en mi Java 9, pero ocasionalmente alcanza un número redondo de milisegundos y produce menos decimales.
Analiza una cadena con todo de 0 a 9 decimales, por lo que esto no presenta un problema en el análisis.
Y siempre conservo toda la presición del objeto original
OffsetDateTime
. -
El desplazamiento desde UTC se representa con dos puntos, por ejemplo
+01:00
.
¿Qué salió mal en tu código?
La clase
SimpleDateFormat
es obsoleta desde hace mucho tiempo y es notoriamente problemática, por lo que incluso si no hubiera tenido un problema con ella en este momento, le recomendaría que la abandone y use
java.time
, la API moderna de fecha y hora de Java, ya que yo hacer arriba.
Una diferencia entre el viejo
SimpleDateFormat
y el moderno
DateTimeFormatter
es que mientras
S
en el formateador moderno significa fracción de segundo, en
SimpleDateFormat
significa milisegundos, por lo que cualquier otro número que tres no tiene sentido.
Sin embargo, acepta otros números.
Al formatear, su formateador produjo suficientes dígitos para los milisegundos, por ejemplo
89
si hubo 21.089 segundos o
214
cuando tenía 13.214 como en la pregunta. El primero es incorrecto, los 21.089 segundos se representaron como
21.89
.
Creo firmemente que los milisegundos de tres dígitos hicieron que su análisis fallara cuando solo tenía una
S
En mi Java 8 y 9 funciona y también analiza
21.89
como 21 segundos 89 milisegundos, por lo que el error se iguala.
Este comportamiento concuerda con la documentación de Java 9, que establece: “Para formatear, el número de letras de patrón es el número mínimo de dígitos, y los números más cortos se rellenan con ceros a esta cantidad. Para el análisis, se ignora el número de letras de patrón a menos que sea necesario separar dos campos adyacentes ".
Enlazar
-
Tutorial de Oracle: Fecha y hora que
explica cómo usar
java.time
. -
Documentación
SimpleDateFormat
para Java 9
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSSZ");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
try {
Date test = dateFormat.parse(text);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
trabajó para mi. Con "SSSZ" en lugar de "SZ" al final del patrón.