java date simpledateformat datetime-parsing unparseable

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:

  1. 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 .
  2. 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


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.