Entonces, cuando intenté reemplazar algún código heredado usando SimpleDateFormat y Date, para usar java.time.DateTimeFormatter y LocalDate me encontré con un problema. Los dos formatos de fecha no son equivalentes. En este punto, debo decir que sé que los dos tipos de fecha no son iguales, pero el escenario en el que me encuentro significa que nunca me preocupo por el aspecto del tiempo, por lo que puedo ignorarlo.
public Date getDate(String value) { SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); try { return dateFormat.parse(value); } catch (ParseException e) { return null; } } public LocalDate getLocalDate(String value) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); try { return LocalDate.parse(value, formatter); } catch (DateTimeParseException e) { return null; } } public void testDates() { getDate("03/07/2016"); // Sun Jul 03 00:00:00 BST 2016 getDate("3/7/2016"); // Sun Jul 03 00:00:00 BST 2016 getDate("3/7/2016 00:00:00"); // Sun Jul 03 00:00:00 BST 2016 getDate("3/7/2016 00:00:00.0+0100"); // Sun Jul 03 00:00:00 BST 2016 getDate("3/7/2016T00:00:00.0+0100"); // Sun Jul 03 00:00:00 BST 2016 getLocalDate("03/07/2016"); // 2016-07-03 getLocalDate("3/7/2016"); // null getLocalDate("3/7/2016 00:00:00"); // null getLocalDate("3/7/2016 00:00:00.0+0100"); // null getLocalDate("3/7/2016T00:00:00.0+0100"); // null }Como puede ver, cuando se usa el mismo patrón en ambos formateadores, DateTimeFormatter termina produciendo valores nulos donde esperaría ver fechas equivalentes a las de SDF. En este escenario, esperaría que se eliminen los datos no necesarios, pero no es así.
Entonces, ¿cómo creamos un analizador robusto de fecha/hora?
Entonces, puede haber otras respuestas a esto, pero lo que se me ocurrió satisface el caso más extremo que tengo. Primero reduje dd/MM a d/M. Esto denota la cantidad mínima de caracteres esperados, por lo que analizará dos dígitos completamente bien. Tenga en cuenta que también podría usar el nuevo DateTimeFormatterBuilder().parseLenient() pero esto parecía innecesario.
En segundo lugar, decidí usar la cláusula opcional en el patrón de formato en sí. Esto le permite especificar qué partes no se pueden proporcionar, que es exactamente el caso que estaba tratando de resolver.
Dejándonos con:
DateTimeFormatter.ofPattern("d/M/yyyy[' ']['T'][H:mm[:ss[.S]]][X]");Esto ahora se encargará de proporcionar una fecha con o sin tiempo, incluido un separador T, segundos, milisegundos y compensación de zona.
¡Con un poco de suerte, esto ayuda a alguien más!
private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy[' ']['T'][H:mm[:ss[.S]]][X]"); public LocalDate getRobustLocalDate(String value) { try { return LocalDate.parse(value, formatter); } catch (DateTimeParseException e) { return null; } } @Test public void testDates() { getRobustLocalDate("03/07/2016"); // 2016-07-03 getRobustLocalDate("3/7/2016"); // 2016-07-03 getRobustLocalDate("3/7/2016 00:00:00"); // 2016-07-03 getRobustLocalDate("3/7/2016 00:00:00.0+0100"); // 2016-07-03 getRobustLocalDate("3/7/2016T00:00:00.0+0100"); // 2016-07-03 }