Fechas en Java: LocalDate, LocalTime y LocalDateTime

La gestión del tiempo en Java, utilizando las clases LocalDate, LocalTime y LocalDateTime, es una novedad de la versión 8. Antes de empezar, recuerda que en el examen de certificación OCAJ8P no están incluidas las zonas horarias. Esto facilita bastante las cosas pero, como ya te dije en el artículo anterior, el examen va a intentar ponerte trampas.

More...

Las clases relativas al tiempo en Java tienen su propio paquete

Esto es algo muy importante ya que, sin importar el paquete, el código no puede compilar. De este modo, si en el examen aparece un fragmento de código y falta el import correspondiente, ya sabes cuál es la consecuencia.

¡Recuerda! 


  • check
    El paquete java.time contiene las clases relativas al tiempo (LocalDate, LocalTime y LocalDateTime).
  • check
    El paquete java.time.format contiene la clase DateTimeFormatter.
  • check
    Si en el código que te aparezca en el examen aparecen fechas u horas, ha de importarse java.time.
  • check
    Si, además de aparecer, el código las formatea, han de importarse ambos paquetes (java.time y java.time.format).

¡Nunca mezcles las clases relativas al tiempo en Java!

Las clases LocalDate, LocalTime y LocalDateTime no mantienen relación alguna de herencia. Esto quiere decir que no puedes hacer uso del polimorfismo. Por ello, una referencia de tipo LocalDateTime no puede apuntar a un objeto de tipo LocalDate, por ejemplo. Te lo muestro en el siguiente ejemplo:

Como ves, las clases relativas al tiempo en Java utilizan siempre métodos estáticos, que devuelven una referencia del tipo de la clase que se ha utilizado para ejecutarlos. Eso quiere decir que si estás utilizando una referencia de tipo LocalDate, tienes que usar LocalDate.now() para instanciarla.

Si no lo haces, el código no va a compilar, porque LocalDate.now() es incompatible con una referencia de tipo LocalTime. Y LocalDateTime es incompatible con ambos.

Lo que sí puedes hacer es crear un objeto de tipo LocalDateTime a partir de un objeto de tipo LocalDate y de otro LocalTime (¡en este orden!). Lo que no puedes hacer es apuntar la referencia de una de estas clases a un objeto de otra.

No existe otra manera de instanciar alguna de las clases relativas al tiempo en Java, ya que sus constructores son privados. No olvides que los métodos estáticos pueden utilizarse tanto con el nombre de la clase, como con una instancia de dicha clase, aunque esta no apunte a ningún objeto (valor null):

Compila sin problema e imprime la hora actual.

Period solo acepta el último método

Como ya te he dicho antes, para instanciar las clases relativas al tiempo en Java se utilizan métodos estáticos. Period no es una excepción. Lo único que tienes que tener en cuenta es que, al instanciar un objeto de tipo PeriodJava solo tiene en cuenta el último método estático que has utilizado:

Recuerda que las fechas son inmutables. Eso quiere decir que, en el código anterior, el objeto al que apunta la referencia hoy no se ve afectado por hoy.plus(periodo) si no lo reasignas.

Cómo darle formato a una fecha/hora sin liarte

El formato de las instancias de las clases relativas al tiempo en Java puede ser un poco lioso, así que vamos a ir paso a paso. Estos son los tres tipos de formato que tienes que conocer:

Chuleta formato DateTimeFormatter

Guarda esta chuleta

Formato ISO

El formato ISO hace referencia al estándar ISO 8601. Este es el formato predeterminado en las fechas/horas. Esto significa que, al imprimirlas, vas a obtener una fecha/hora con este formato, aunque no se lo apliques.

No obstante, a la hora de aplicarlo, ten en cuenta lo siguiente:

  • check
    ISO_LOCAL_DATE puede utilizarse con LocalDate y LocalDateTime (contienen una fecha).
  • check
    ISO_LOCAL_TIME puede utilizarse con LocalTime y LocalDateTime (contienen una hora).
  • check
    ISO_LOCAL_DATE_TIME puede utilizarse solo con LocalDateTime (contiene una fecha y una hora).

Esto quiere decir que solo puedes utilizar un formato ISO si el objeto temporal al que lo aplicas contiene aquello que estás formateando. LocalDateTime acepta los tres. La diferencia consiste en que, si imprimes el objeto LocalDateTime con el formato ISO_LOCAL_TIME, vas a ver solo la hora que contiene. Si le aplicas ISO_LOCAL_DATE, va a imprimir solo la fecha:

Formato .ofLocalizedDate/Time/DateTime

En este caso, al igual que con el formato ISO, tienes que utilizar el que corresponda con la referencia temporal que estás utilizando. Es decir, no utilices .ofLocalizedDate para formatear un objeto de tipo LocalTime.

Formato arbitrario .ofPattern

Este método de DateTimeFormatter acepta una String (cadena de texto). Así, podemos darle cualquier formato a un objeto de tipo LocalDate, LocalTime o LocalDateTime. En la cadena de texto que utilizamos como patrón puede haber tres tipos de elementos: 

  • check
    Letras que simbolizan un elemento temporal. La lista completa está en la página web de Oracle.
  • check
    Texto entre comillas simples, que aparece tal cual al imprimir.
  • check
    Signos de puntuación.

Te lo muestro en el ejemplo que sigue:

Todas las letras están reservadas, tanto las mayúsculas como las minúsculas. Esto significa que, cuando se utilice el formato .ofPattern en el examen, has de estar atento a los siguientes puntos:

  • Al igual que en los casos anteriores, no puedes formatear una fecha en un objeto de tipo LocalTime, o una hora en un objeto de tipo LocalDate. Si lo intentas, el código compilará pero la ejecución se detendrá con una excepción (UnsupportedTemporalTypeException). Fíjate bien en el patrón que se utilice en el examen.
  • En relación con el punto anterior, asegúrate de que el texto literal que aparezca en el patrón esté entre comillas simples.
  • Algunos símbolos son similares, pero tienen significados muy distintos. Mientras que m minúscula equivale a "minuto", M mayúscula equivale a "mes".
  • En relación con el punto anterior, las combinaciones raras son válidas, aunque no debas utilizarlas tú en tu código.

Ejemplo de línea de formato arbitrario con error (puntos 1 y 2)

La única diferencia con el ejemplo anterior es que he retirado las comillas simples que había en torno a la "y". Así, ha pasado de ser texto literal a simbolizar YearOfEra. Como en este caso estoy formateando un objeto de tipo LocalTime, sin información sobre el año, la ejecución se detiene con una excepción.

Ejemplo de combinación rara (puntos 3 y 4)

Si el examen te diese una fecha y hora completas, y te preguntase qué imprime este código, podrías caer en la trampa de pensar que va a imprimir la hora y los minutos. Pero no: imprime la hora y el mes. Son las cinco de la tarde de un día de febrero.

Échale un vistazo a la lista de símbolos en la página de Oracle y practícalos. Recuerda que, para el OCAJ8P, no es necesario que practiques los símbolos relativos a las zonas horarias.

BONUS: método .parse

El método .parse se utiliza para crear un objeto de tipo LocalDate, LocalTime o LocalDateTime a partir de una cadena de texto. El método .parse admite dos argumentos:

  • El primer argumento se trata de la cadena de texto que vas a transformar en un objeto temporal.
  • El segundo argumento se trata del objeto de tipo DateTimeFormatter con el que le vas a decir al método .parse cómo aparece la fecha expresada en la cadena de texto, para que la entienda.

El segundo argumento, el formateador, puede ser cualquier formato que hemos visto más arriba: un ISO, un .ofLocalizedDate/Time/DateTime o un patrón arbitrario. Lo importante es que el primer argumento se ha de corresponder con el formato que vas a utilizar para "traducirlo" a una instancia de alguna clase relativa al tiempo en Java. Es por ello que debes conocer el resultado de imprimir cada uno de los tipos de formato disponibles, y cuál es el significado de cada letra en los formatos arbitrarios de .ofPattern.

Por último, .parse acepta un único argumento si la cadena de texto se corresponde con el formato ISO, el predeterminado.

Ejercicio recomendado

Te recomiendo que practiques bien las fechas y las horas, cómo instanciarlas y cómo modificarlas. Además, no olvides que tienes que dominar cómo formatear las fechas/horas para el examen. En mi opinión, el formato arbitrario (.ofPattern) es donde el examen puede intentar ponértelo más difícil.

Deja una respuesta 0 comentarios