Cómo convertir una cadena a fecha en Java

Convertir una cadena en una fecha en Java (o cualquier lenguaje de programación) es una habilidad fundamental y es útil saberlo cuando se trabaja en proyectos. A veces, es simple...

Convertir una cadena en una fecha en Java (o cualquier lenguaje de programación) es una habilidad fundamental y es útil saberlo cuando se trabaja en proyectos. A veces, simplemente es más fácil trabajar con una cadena para representar una fecha y luego convertirla en un objeto Fecha para su uso posterior.

En este artículo, repasaremos los muchos métodos y bibliotecas que puede usar para convertir una cadena Java en un objeto de fecha.

API de fecha y hora

La API de fecha/hora en Java funciona con el formato [ISO 8601] (https://en.wikipedia.org/wiki/ISO_8601) de forma predeterminada, que es (yyyy-MM-dd).

Todas las fechas siguen este formato de forma predeterminada, y todas las cadenas que se convierten deben seguirlo si está utilizando el formateador predeterminado.

analizar()

Esta API define un método parse() que acepta una secuencia de caracteres y usa el formato ISO_LOCAL_DATE para analizar la entrada:

1
parse(CharSequence);

Alternativamente, puede usar la variante de dos argumentos de este método, definiendo un formateador diferente:

1
parse(CharSequence, DateTimeFormatter);

Se usa un DateTimeFormatter para formatear y analizar objetos de fecha y hora en la nueva API de Fecha/Hora. Todas las clases de fecha y hora de esta API contienen un método para analizar y formatear, donde cada una acepta un DateTimeFormatter para definir un patrón.

Convertir una cadena en una fecha local {#convertir una cadena en una fecha local}

Un LocalDate representa una fecha, sin tiempo en formato ISO-8601.

Se diferencia de Date en el hecho de que no almacena el tiempo como un desplazamiento de milisegundos desde la época, sino simplemente la fecha actual. También es una implementación más reciente de la API Fecha/Hora y ofrece su propio método de formato/análisis, así como la suma y resta de días, semanas y años, que no existe en la variante Fecha.

Para convertir una cadena en un objeto LocalDate, basta con escribir:

1
LocalDate date = LocalDate.parse("2018-09-16");

Este es el equivalente a escribir el código de procedimiento para instanciar un objeto LocalDate:

1
LocalDate date = LocalDate.of(2018, 09, 16);

Conversión de una cadena a la hora local {#conversión de una cadena a la hora local}

LocalTime representa la hora, sin zona horaria en formato ISO-8601. No almacena el tiempo en función del desplazamiento desde la época y ofrece una precisión de nanosegundos.

Al igual que LocalDate, proporciona una gran cantidad de métodos de formato y análisis muy útiles incorporados, así como los medios para agregar o restar tiempo.

Para convertir una cadena en un objeto LocalTime, basta con escribir:

1
LocalTime localTime = LocalTime.parse("8:00");

Este es el equivalente a escribir el código de procedimiento para instanciar un objeto LocalTime:

1
LocalTime localTime = LocalTime.of(8, 00);

Conversión de una cadena a LocalDateTime

LocalDateTime es la clase más utilizada con respecto a Fecha/Hora en Java. Representa una combinación de fecha y hora, y se puede utilizar para muchos propósitos:

1
LocalDateTime localDateTime = LocalDateTime.parse("2018-09-16T08:00:00");

Este formato puede parecer confuso al principio, pero en realidad es bastante simple:

localdatetime{.img-responsive}

El marcador "Hora" simplemente representa una línea entre las partes LocalDate y LocalTime del formato.

También puede formatear fácilmente este LocalDateTime en un formato más legible:

1
2
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatDateTime = localDateTime.format(formatter);

Ejecutar este fragmento de código e imprimir formatDateTime produciría:

1
2018-09-16 08:00:00

Por lo general, haría esto para mostrar el resultado al usuario final en formato de cadena, mientras realiza operaciones en el objeto LocalDateTime de antemano.

Conversión de una cadena a ZonedDateTime

Dependiendo del proyecto en el que esté trabajando, es posible que deba manejar diferentes zonas horarias cuando se trata de fechas y horas.

Convertir una cadena en un objeto ZonedDateTime es tan simple como:

1
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2018-09-16T08:00:00+00:00[Europe/London]");

El ejemplo anterior muestra cómo inicializaría un ZonedDateTime para Londres.

Conversión de una cadena mediante un formateador personalizado

A veces, es posible que deseemos utilizar nuestro propio formateador personalizado, que acepta una cadena de las formas más variadas y aún así no lanza una DateTimeParseException.

Estos son algunos de los patrones más comunes que usaría:

  • y: Año (2018, 18)
  • M: mes en un año (agosto, agosto, 08)
  • d: Día en un mes (1, 5, 25)
  • E: Nombre de un día en una semana (lunes, sábado)
  • a: Marcador de mañana/tarde (AM, PM)
  • H: Hora en estilo 24h (1, 7, 14, 21)
  • h: Hora en estilo 12h (1, 5, 12)
  • m: Minuto en una hora (1, 25, 54)
  • s: Segundo en un minuto (1, 25, 54)

Y algunos que quizás no uses tan a menudo:

  • G: Designador de era (AD, CE)
  • Y: Semana año (2018, 18)
  • w: Semana en un año (25, 53)
  • W: Semana en un mes (2)
  • D: Día en un año (254)
  • F: Día de la semana en un mes (3)
  • E: Nombre del día en una semana (lunes, lunes)
  • u: Número de día de una semana (1, 4)
  • k: Hora en un día (17)
  • K: Hora en un día en AM/PM (5)
  • S: Milisegundo (1245)
  • z: Zona horaria general (hora estándar del Pacífico; PST; GMT-8:00)
  • Z: RFC 822 Zona horaria (-0800)
  • X: Zona horaria ISO 8601 (-08, -0800, -8:00)

Nota: La semana año difiere de un año: una semana año está sincronizada con un ciclo WEEK_OF_YEAR. Todas las semanas entre la primera y la última semana (incluidas) tienen el mismo valor de semana y año. Por lo tanto, el primer y el último día de un año de semana pueden tener diferentes valores de año calendario.

Nota: K y H se diferencian de la misma manera que k y h. H y h se refieren al modelo 0-23 y 1-12 respectivamente, mientras que K y k se refieren al 0-11 y 1-24 respectivamente.

Si esto aún no satisface su necesidad de un formateador personalizado, puede usar DateTimeFormatterBuilderDateTimeFormatterBuilder para construir formateadores muy específicos y complejos. Entre otras cosas, DateTimeFormatter se crea utilizando esta clase.

java.util.Date

Este es un enfoque más antiguo, que no se usa con frecuencia en la actualidad, pero aún vale la pena cubrirlo, ya que a veces todavía usamos las clases de estas API:

1
2
3
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");

Date date = formatter.parse("22-Sep-2018");

Hay muchos patrones que podemos pasar al constructor de SimpleDateFormat. Puede combinar prácticamente cualquier cantidad de formatos utilizando los patrones disponibles.

No es posible establecer una zona horaria para una Fecha, porque simplemente no contiene dicha información. Sin embargo, es fácil formatear la fecha y agregar la información de la zona horaria a una cadena:

1
2
3
4
5
6
7
8
SimpleDateFormat formatter = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));

Date date = formatter.parse("22-09-2018 08:23:43 PM");
String formattedDate = formatter.format(date);

System.out.println(date);
System.out.println(formattedDate);

Ejecutar este fragmento de código producirá:

1
2
Sat Sep 22 22:23:43 CEST 2018
22-9-2018 08:23:43 PM

"22:23:43 CEST" corresponde a la hora "10:23:43 p. m.", mientras que la fecha formateada representa "8:23:43 p. m." ya que está en una zona horaria diferente.

SimpleDateFormat vs DateTimeFormatter

Al leer este artículo, es justo plantear la pregunta: "¿Cuál es la diferencia y cuál debo usar?"

DateTimeFormatter se ha agregado en Java 8 con la nueva API de Fecha/Hora, y reemplaza a SimpleDateFormat, más antigua y que ahora se usa con menos frecuencia. Es seguro para subprocesos a diferencia de su contraparte anterior y ofrece una nueva funcionalidad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// SimpleDateFormat
SimpleDateFormat formatter = new SimpleDateFormat("dd-M-yyyy");
Date date = new Date();
String formattedDate = formatter.format(date);
Date parsedDate = formatter.parse(formattedDate);

// DateTimeFormatter
LocalDate date = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-M-yyyy");
String formattedDate = date.format(formatter);
LocalDate parsedDate = LocalDate.parse(formattedDate, formatter);  

Es claro ver la diferencia entre estos dos. En la forma más antigua, se usa un formateador para formatear y luego analizar la fecha. En la forma más nueva, las fechas tienen su propio formato y métodos de análisis y usan un DateTimeFormatter simplemente para el patrón.

Si está usando Java 8 y la nueva API, use DateTimeFormatter, mientras que si todavía está usando una versión anterior de Java, use SimpleDateFormat.

Joda-Tiempo

Joda-Tiempo fue desarrollado para contrarrestar los problemas con las antiguas clases de fecha y hora de Java.

A partir de Java 8, estos problemas se han corregido y Joda-Time ha cumplido su propósito. Incluso los autores del mismo aconsejan migrar a java.time oficial para trabajar con fechas y horas.

En el caso de que esto sea imposible, y para aquellos que todavía usan una versión de Java anterior a Java 8, Joda-Time sigue siendo una gran biblioteca para usar.

Se puede agregar fácilmente una dependencia para esta biblioteca con una dependencia Experto:

1
2
3
4
5
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>{version}</version>
</dependency>

Trabajar con Joda-Time es muy similar a trabajar con la API de fecha/hora de Java:

1
2
3
DateTimeFormatter formatter = DateTimeFormatter.forPattern("dd-MM-yyyy HH:mm:ss");

DateTime dateTime = DateTime.parse("22-Sep-2018 8:15:43", formatter);

La clase DateTime de Joda-Time también admite zonas horarias:

1
2
3
4
DateTimeFormatter formatter = DateTimeFormatter.forPattern("dd-MM-yyyy HH:mm:ss");

DateTime dateTime = DateTime.parse("22-Sep-2018 8:15:43", formatter);
DateTime dateTimeZoned = dateTime.withZone(DateTimeZone.forID("Europe/London));

Para obtener una lista completa de los ID de zona horaria disponibles para su uso, visite los documentos oficiales.

Apache Commons

Apache Commons es una biblioteca útil utilizada en muchos proyectos.

Para agregar esta biblioteca a su proyecto, puede usar la dependencia de Maven:

1
2
3
4
5
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>{version}</version>
</dependency>

Las dos implementaciones a continuación aceptan una variedad de patrones. Estos métodos analizarán cada patrón tras otro. Si ningún patrón coincide con la cadena de entrada, se lanza una ParseException.

Usando DateTimeConverter

1
2
3
DateTimeConverter dtc = new DateConverter();
dtc.setPatterns(new String[] { "yyyy-MM-dd", "yyyy-MM-dd hh:mm:ss" });
ConvertUtils.register(dtc, Date.class);

Usando DateUtils

1
Date date = DateUtils.parseDate("22-Sep-2018", String[] {"dd-MM-yyyy HH:mm:ss", "dd-MM-yyyy"});

Conclusión

Hemos cubierto varias formas de convertir una cadena simple en clases de fecha y fecha y hora en Java. Algunos de estos enfoques utilizan bibliotecas de terceros que quizás ya tenga en su proyecto, y algunos se realizan utilizando las API que ofrece Java.

Licensed under CC BY-NC-SA 4.0