online library dates current java jodatime java-time

java - library - jodatime difference between dates



Java 8 ¿Fecha equivalente a DateTimeFormatterBuilder de Joda con múltiples formatos de analizador? (5)

Aquí es lo que finalmente se me ocurrió. Maneja tres formatos principales diferentes, cada uno con múltiples diferencias de formato menores (como permitir - o / delimitadores), así como el número variable de microsegundos (de 0 a 6):

private static final DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder() .parseCaseInsensitive() .appendPattern( "[ddMMMyyyy:HH:mm:ss" ) .optionalStart() .appendFraction( ChronoField.MICRO_OF_SECOND , 1 , 6 , true ) .optionalEnd() .appendPattern( "[ ][Z][X]]" ) .appendPattern( "[yyyy[-][/]MM[-][/]dd[''T''][ ]HH:mm[:][.]ss" ) .optionalStart() .appendFraction( ChronoField.MICRO_OF_SECOND , 1 , 6 , true ) .optionalEnd() .appendPattern( "[Z][X]]" ) .appendPattern( "[EEE, dd MMM yyyy HH:mm:ss zzz]" ) .toFormatter();

Actualmente tengo un analizador de fecha de Joda que usa DateTimeFormatterBuilder con media docena de formatos de fecha diferentes que puedo recibir.

Estoy migrando a las rutinas de fecha de Java 8 y no veo un equivalente.

¿Cómo puedo hacer algo como esto usando Java 8 Dates?

DateTimeParser[] parsers = { DateTimeFormat.forPattern( "yyyy/MM/dd HH:mm:ss.SSSSSS" ).getParser() , DateTimeFormat.forPattern( "yyyy-MM-dd HH:mm:ss" ).getParser() , DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSS Z" ).getParser() , DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSS" ).getParser() , DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSSSSS" ).getParser() , DateTimeFormat.forPattern( "yyyy-MM-dd HH:mm:ss.SSS" ).getParser() }; DateTimeFormatter dateTimeFormatterInput = new DateTimeFormatterBuilder() .append( null, parsers ).toFormatter();


Basado en la respuesta de @Brice, escribí el siguiente método, que funcionó mejor para mí

private LocalDate parseDate(String date) { DateTimeFormatter yearFormat = new DateTimeFormatterBuilder() .appendPattern("yyyy") .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1) .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) .toFormatter(); DateTimeFormatter yearAndMonthFormat = new DateTimeFormatterBuilder() .appendPattern("yyyy-MM") .parseDefaulting(ChronoField.DAY_OF_MONTH,1) .toFormatter(); DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendOptional(DateTimeFormatter.ISO_DATE) .appendOptional(yearAndMonthFormat) .appendOptional(yearFormat) .toFormatter(); LocalDate result = LocalDate.parse(date, formatter); return result; }

Preste atención al orden de los formateadores opcionales agregados al último. El orden inverso solo funcionaría para las fechas del tipo "aaaa". El orden propuesto me permite analizar todo lo siguiente:

  • 2014
  • 2014-10
  • 2014-03-15

Solo agregando para el caso alguien tendría un caso de uso similar.


Como una respuesta alternativa a Tunaki, también puede usar DateTimeFormatterBuilder:

DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder() .appendPattern("[yyyy]") .appendPattern("[M/d/yyyy]") .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1) .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) .toFormatter()


Iterando sobre la solución de @ Tunaki, usando flujos, cuando el código necesita aceptar diferentes patrones de una manera configurable:

DateTimeFormatter dateTimeFormatter = dateFormats.stream() .map(DateTimeFormatter::ofPattern) .reduce(new DateTimeFormatterBuilder(), DateTimeFormatterBuilder::appendOptional, (f1, f2) -> f1.append(f2.toFormatter())) .toFormatter();

En este caso, no me importa la parte combinadora del reductor, pero la necesito en la firma, así que hice la combinación correcta.

Este código equivaldría virtualmente a si los patrones anteriores ( yyyy/MM/dd HH:mm:ss.SSSSSS , yyyy-MM-dd HH:mm:ss[.SSS] , ddMMMyyyy:HH:mm:ss.SSS[ Z] ) sería alimentado a la corriente:

DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendOptional(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSSSSS") .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]" .appendOptional(DateTimeFormatter.ofPattern("ddMMMyyyy:HH:mm:ss.SSS[ Z]") .toFormatter();


No hay una facilidad directa para hacer esto, pero puede usar secciones opcionales. Las secciones opcionales están encerradas entre corchetes [] . Esto permite que falte toda la sección de la cadena.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("" + "[yyyy/MM/dd HH:mm:ss.SSSSSS]" + "[yyyy-MM-dd HH:mm:ss[.SSS]]" + "[ddMMMyyyy:HH:mm:ss.SSS[ Z]]" );

Este formateador define 3 grandes secciones opcionales para los tres patrones principales que tiene. Cada uno de ellos está dentro de su propia sección opcional.

Código de demostración de trabajo:

public static void main(String[] args) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("" + "[yyyy/MM/dd HH:mm:ss.SSSSSS]" + "[yyyy-MM-dd HH:mm:ss[.SSS]]" + "[ddMMMyyyy:HH:mm:ss.SSS[ Z]]" , Locale.ENGLISH); System.out.println(LocalDateTime.parse("2016/03/23 22:00:00.256145", formatter)); System.out.println(LocalDateTime.parse("2016-03-23 22:00:00", formatter)); System.out.println(LocalDateTime.parse("2016-03-23 22:00:00.123", formatter)); System.out.println(LocalDateTime.parse("23Mar2016:22:00:00.123", formatter)); System.out.println(LocalDateTime.parse("23Mar2016:22:00:00.123 -0800", formatter)); }