Una librería con libros holográficos hechos de código fuente.

Aprende a usar fechas en Java con java.time y domina el tiempo

Introducción

Antes de Java 1.8, el manejo de fechas y horas en Java era complicado y propenso a errores. Las clases Date y Calendar tenían limitaciones y problemas de diseño. Con la llegada de Java 1.8, se introdujo una nueva API de fechas y horas en el paquete java.time, más moderna, intuitiva, robusta y flexible.

En esta entrada, vamos a explorar cómo trabajar con fechas en Java 1.8, explicando las clases más importantes, sus métodos y por qué esta nueva API es la mejor opción para manejar fechas y horas.

¿Qué vamos a aprender hoy?

  • Por qué java.time es tu mejor amigo (y no java.util.Date).
  • Las clases principales para representar fechas y horas: LocalDate, LocalTime, LocalDateTime, ZonedDateTime.
  • Cómo crear fechas y horas: Desde cero y a partir de cadenas de texto.
  • Cómo obtener información de una fecha: Día, mes, año, etc.
  • Cómo manipular fechas: Sumar, restar, comparar.
  • Formateo: Cómo mostrar las fechas en el formato que necesites (ej: «12/01/2024»).
  • Zonas horarias: Cómo manejar fechas en diferentes partes del mundo.

¿Por qué usar java.time en lugar de Date o Calendar?

Las clases Date y Calendar presentaban varias desventajas:

  • Mutabilidad: Eran mutables, lo que podía llevar a errores en aplicaciones concurrentes.
  • Complejidad: Su uso era poco intuitivo y propenso a errores.
  • Limitaciones: Carecían de soporte adecuado para zonas horarias y operaciones comunes con fechas.

La nueva API java.time aborda estos problemas proporcionando clases inmutables y un diseño más claro y robusto.

  1. Inmutabilidad: Las clases de java.time son inmutables, lo que significa que no pueden modificarse después de su creación.  Los objetos java.time no se modifican directamente. Cuando sumas un día a una fecha, creas un nuevo objeto. Esto evita errores inesperados y facilita la depuración. Imagina que intentas modificar un String. No puedes, siempre creas uno nuevo. Lo mismo ocurre con las fechas en java.time. Esto evita errores comunes en programas concurrentes.
  2. Claridad y facilidad de uso: La nueva API es mucho más intuitiva y fácil de entender.  Los nombres de los métodos son descriptivos y separa claramente los conceptos de fecha, hora y fecha-hora.
  3. Thread-safe: Seguro para usar en programas con múltiples hilos de ejecución (un tema que veréis más adelante, ¡pero es importante!).
  4. Flexibilidad: Proporciona métodos para realizar cálculos y manipulaciones de fechas de manera sencilla.
  5. Mejor Manejo de Zonas Horarias: Simplifica el trabajo con fechas en diferentes zonas horarias.
  6. Compatibilidad con estándares: Sigue el estándar ISO-8601, que es ampliamente utilizado en todo el mundo.

Clases Principales de la API java.time

Las clases más importantes de la API java.time son:

  1. LocalDate: Representa una fecha (año, mes, día) sin hora.
  2. LocalTime: Representa una hora (hora, minuto, segundo) sin fecha.
  3. LocalDateTime: Combina fecha y hora, pero sin zona horaria.
  4. ZonedDateTime: Representa una fecha y hora con zona horaria.
  5. Instant: Representa un punto específico en el tiempo (timestamp) en UTC.
  6. Duration: Representa una cantidad de tiempo en segundos y nanosegundos.
  7. Period: Representa una cantidad de tiempo en años, meses y días.

A continuación, se presentan las clases más utilizadas de la nueva API:

1. LocalDate

LocalDate es ideal para representar fechas sin hora, como fechas de nacimiento o fechas de eventos.

Ejemplo de uso:

import java.time.LocalDate;

public class EjemploLocalDate {
    public static void main(String[] args) {
        // Fecha actual
        LocalDate hoy = LocalDate.now();
        System.out.println("Fecha actual: " + hoy);

        // Crear una fecha específica
        LocalDate nacimiento = LocalDate.of(2005, 2, 12);
        System.out.println("Fecha de nacimiento: " + nacimiento);

        // Sumar días a una fecha
        LocalDate mañana = hoy.plusDays(1);
        System.out.println("Mañana será: " + mañana);

        // Comparar fechas
        if (hoy.isBefore(mañana)) {
            System.out.println("Hoy es antes del " + mañana);
        }

        // Crear una fecha a partir de una cadena de texto (String)
        LocalDate otraFecha = LocalDate.parse("2024-01-15");
        System.out.println("Otra fecha: " + otraFecha);
    }
}

Salida: (Ten en cuenta si ejecutas el código que las fechas de hoy y mañana diferirán)

Fecha actual: 2025-02-12
Fecha de nacimiento: 2005-02-12
Mañana será: 2025-02-13
Hoy es antes del 2025-02-13
Otra fecha: 2024-01-15
  • LocalDate.now() obtiene la fecha actual.
  • LocalDate.of() crea una fecha específica.
  • LocalDate.parse(): Crea una fecha a partir de un texto. El formato por defecto es «AAAA-MM-DD».
  • Métodos como plusDays() e isBefore() facilitan la manipulación y comparación de fechas.

2. LocalTime

Representa una hora sin información de fecha ni zona horaria, útil para horarios de apertura o cierre.

Ejemplo de uso:

import java.time.LocalTime;

public class EjemploLocalTime {
    public static void main(String[] args) {
        // Hora actual
        LocalTime ahora = LocalTime.now();
        System.out.println("Hora actual: " + ahora);

        // Crear una hora específica
        LocalTime inicioClase = LocalTime.of(8, 30);
        System.out.println("Inicio de clase: " + inicioClase);

        // Sumar horas y minutos
        LocalTime másTarde = ahora.plusHours(2).plusMinutes(15);
        System.out.println("En 2 horas y 15 minutos será: " + másTarde);

        // Crear una hora a partir de una cadena
        LocalTime otraHora = LocalTime.parse("14:45");
        System.out.println("Otra hora: " + otraHora);
    }
}

Salida:

Hora actual: 10:24:31.123
Inicio de clase: 08:30
En 2 horas y 15 minutos será: 12:39:31.123
Otra hora: 14:45

Explicación del código:

  • LocalTime.now() obtiene la hora actual.
  • LocalTime.of() crea una hora específica.
  • Métodos como plusHours() permiten manipular la hora.
  • LocalTime.parse(): Crea una hora a partir de un texto. El formato por defecto es «HH:MM».

3. LocalDateTime

Combina fecha y hora sin información de zona horaria. Útil para representar eventos específicos, registrar sucesos, etc.

Ejemplo de uso:

import java.time.LocalDateTime;

public class EjemploLocalDateTime {
    public static void main(String[] args) {
        // Fecha y hora actuales
        LocalDateTime ahora = LocalDateTime.now();
        System.out.println("Fecha y hora actuales: " + ahora);

        // Crear una fecha y hora específicas
        LocalDateTime evento = LocalDateTime.of(2025, 5, 20, 14, 0);
        System.out.println("Evento programado para: " + evento);

        // Restar días y horas
        LocalDateTime antes = evento.minusDays(2).minusHours(3);
        System.out.println("Dos días y tres horas antes del evento: " + antes);

        // Crear a partir de cadenas
        LocalDateTime otraFechaHora = LocalDateTime.parse("2024-03-10T18:00");
        System.out.println("Otra fecha y hora: " + otraFechaHora);
    }
}

Salida:

Fecha y hora actuales: 2025-02-12T10:24:31.123
Evento programado para: 2025-05-20T14:00
Dos días y tres horas antes del evento: 2025-05-18T11:00
Otra fecha y hora: 2024-03-10T18:00

Explicación del código:

  • LocalDateTime.now() obtiene la fecha y hora actual.
  • LocalDateTime.of() crea una fecha y hora específica.
  • Métodos como minusDays() y minusHours() permiten manipular la fecha y hora.
  • LocalDateTime.parse(«2024-03-10T18:00»): Crea una fecha y hora a partir de un texto. El formato por defecto es «AAAA-MM-DDTHH:MM». La «T» separa la fecha de la hora.

4. ZonedDateTime

Representa una fecha y hora con zona horaria, útil para aplicaciones globales, que manejan múltiples zonas horarias.

Ejemplo de uso:

import java.time.ZonedDateTime;
import java.time.ZoneId;

public class EjemploZonedDateTime {
    public static void main(String[] args) {
        // Fecha y hora actuales en la zona horaria del sistema
        ZonedDateTime ahora = ZonedDateTime.now();
        System.out.println("Fecha y hora actuales: " + ahora);

        // Crear una fecha y hora específica con zona horaria
        ZonedDateTime fechaHoraEspecifica = ZonedDateTime.of(2025, 2, 13, 14, 30, 0, 0, ZoneId.of("Europe/Madrid"));
        System.out.println("Fecha y hora específica con zona horaria: " + fechaHoraEspecifica);

        // Cambiar la zona horaria
        ZonedDateTime fechaHoraNuevaZona = fechaHoraEspecifica.withZoneSameInstant(ZoneId.of("America/New_York"));
        System.out.println("Fecha y hora en Nueva York: " + fechaHoraNuevaZona);

        //Crear una fecha desde un string
        ZonedDateTime otraFechaConZona = ZonedDateTime.parse("2025-02-13T10:21:21.978+01:00[Europe/Paris]");
        System.out.println("Otra fecha con zona horaria: " + otraFechaConZona);
    }
}

Salida:

Fecha y hora actuales: 2025-02-13T10:21:21.978+01:00[Europe/Paris]
Fecha y hora específica con zona horaria: 2025-02-13T14:30+01:00[Europe/Madrid]
Fecha y hora en Nueva York: 2025-02-13T08:30-05:00[America/New_York]
Otra fecha con zona horaria: 2025-02-13T10:21:21.978+01:00[Europe/Paris]

Explicación del código:

  • Necesitamos ZoneId para especificar la zona horaria. ZoneId.of(«Europe/Madrid») crea un objeto que representa la zona horaria de Madrid.
  • ZonedDateTime.now() obtiene la fecha y hora actual con la zona horaria del sistema.
  • ZonedDateTime.of() crea una fecha y hora específica con una zona horaria.
  • withZoneSameInstant() convierte la fecha y hora a otra zona horaria.
  • ZonedDateTime.parse(): Permite la creación desde texto especificando la zona horaria.

Desmenuzando el tiempo: obteniendo información

Una vez que tienes una fecha, puedes extraer información útil:

import java.time.LocalDate;
import java.time.Month;

public class ObtenerInfo {
    public static void main(String[] args) {
        LocalDate miCumple = LocalDate.of(2006, 5, 10);

        int anio = miCumple.getYear();
        Month mes = miCumple.getMonth();
        int dia = miCumple.getDayOfMonth();
        int diaDelAnio = miCumple.getDayOfYear();

        System.out.println("Año: " + anio); // Año: 2006
        System.out.println("Mes: " + mes);   // Mes: MAY
        System.out.println("Día: " + dia);   // Día: 10
        System.out.println("Día del año: " + diaDelAnio); // Día del año: 130 (El día 130 del año)
    }
}

Explicación:

  • getYear(): Obtiene el año.
  • getMonth(): Obtiene el mes (como un objeto Month).
  • getDayOfMonth(): Obtiene el día del mes.
  • getDayOfYear(): Obtiene el día del año (1-365/366).

Formateo y Análisis de Fechas

El formateo de fechas es esencial para mostrar fechas en un formato legible para el usuario. La clase DateTimeFormatter permite definir patrones personalizados para formatear y parsear fechas (interpretar fechas en formato String).

Patrones Comunes

SímboloSignificadoEjemplo
yyyyAño con 4 dígitos2023
MMMes con 2 dígitos10 (octubre)
ddDía con 2 dígitos15
HHHora (24 horas)14
mmMinutos30
ssSegundos45
EEEDía de la semanaMon (lunes)
MMMMMes completoOctober

Ejemplo de formateo:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class FormateoFechas {
    public static void main(String[] args) {
        LocalDate fecha = LocalDate.of(2023, 10, 15);

        // Formatear fecha en "dd/MM/yyyy"
        DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("dd/MM/yyyy");
        System.out.println("Fecha formateada (dd/MM/yyyy): " + fecha.format(formatter1));

        // Formatear fecha en "MMMM dd, yyyy"
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MMMM dd, yyyy");
        System.out.println("Fecha formateada (MMMM dd, yyyy): " + fecha.format(formatter2));

        // Formatear fecha en "EEE, dd MMM yyyy"
        DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy");
        System.out.println("Fecha formateada (EEE, dd MMM yyyy): " + fecha.format(formatter3));
    }
}

Salida:

Fecha formateada (dd/MM/yyyy): 15/10/2023
Fecha formateada (MMMM dd, yyyy): October 15, 2023
Fecha formateada (EEE, dd MMM yyyy): Sun, 15 Oct 2023

Ejemplo de análisis:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class EjemploAnalisis {
    public static void main(String[] args) {
        String fechaTexto = "15/08/2025";
        DateTimeFormatter formato = DateTimeFormatter.ofPattern("dd/MM/yyyy");
        LocalDate fecha = LocalDate.parse(fechaTexto, formato);
        System.out.println("Fecha analizada: " + fecha);
    }
}

Salida:

Fecha analizada: 2025-08-15

Modificación de fechas

Las clases de java.time proporcionan métodos para modificar fechas de manera sencilla. Estos métodos devuelven un nuevo objeto, ya que las fechas son inmutables.

Métodos Comunes

MétodoDescripciónEjemplo
plusDays(long)Suma días a la fechafecha.plusDays(5)
minusDays(long)Resta días a la fechafecha.minusDays(5)
plusMonths(long)Suma meses a la fechafecha.plusMonths(2)
minusMonths(long)Resta meses a la fechafecha.minusMonths(2)
plusYears(long)Suma años a la fechafecha.plusYears(1)
minusYears(long)Resta años a la fechafecha.minusYears(1)
withDayOfMonth(int)Cambia el día del mesfecha.withDayOfMonth(20)
withMonth(int)Cambia el mesfecha.withMonth(12)
withYear(int)Cambia el añofecha.withYear(2024)

Ejemplo de Modificación

import java.time.LocalDate;

public class ModificacionFechas {
    public static void main(String[] args) {
        LocalDate fecha = LocalDate.of(2023, 10, 15);

        // Sumar 5 días
        LocalDate fechaSumada = fecha.plusDays(5);
        System.out.println("Fecha + 5 días: " + fechaSumada);

        // Restar 2 meses
        LocalDate fechaRestada = fecha.minusMonths(2);
        System.out.println("Fecha - 2 meses: " + fechaRestada);

        // Cambiar el año a 2024
        LocalDate fechaCambiada = fecha.withYear(2024);
        System.out.println("Fecha con año 2024: " + fechaCambiada);
    }
}

Salida:

Fecha + 5 días: 2023-10-20
Fecha - 2 meses: 2023-08-15
Fecha con año 2024: 2024-10-15

Comparación entre Fechas

Comparar fechas es una operación común para determinar si una fecha es anterior, posterior o igual a otra.

Métodos Comunes

MétodoDescripciónEjemplo
isBefore()Verifica si una fecha es anteriorfecha1.isBefore(fecha2)
isAfter()Verifica si una fecha es posteriorfecha1.isAfter(fecha2)
isEqual()Verifica si dos fechas son igualesfecha1.isEqual(fecha2)
compareTo()Compara dos fechas (devuelve -1, 0, 1)fecha1.compareTo(fecha2)

Ejemplo de Comparación

import java.time.LocalDate;

public class ComparacionFechas {
    public static void main(String[] args) {
        LocalDate fecha1 = LocalDate.of(2023, 10, 15);
        LocalDate fecha2 = LocalDate.of(2023, 12, 25);

        // Verificar si fecha1 es antes que fecha2
        if (fecha1.isBefore(fecha2)) {
            System.out.println("fecha1 es antes que fecha2");
        }

        // Verificar si fecha1 es después que fecha2
        if (fecha1.isAfter(fecha2)) {
            System.out.println("fecha1 es después que fecha2");
        }

        // Verificar si fecha1 es igual a fecha2
        if (fecha1.isEqual(fecha2)) {
            System.out.println("fecha1 es igual a fecha2");
        }

        // Comparar fechas usando compareTo
        int comparacion = fecha1.compareTo(fecha2);
        if (comparacion < 0) {
            System.out.println("fecha1 es anterior a fecha2");
        } else if (comparacion > 0) {
            System.out.println("fecha1 es posterior a fecha2");
        } else {
            System.out.println("fecha1 es igual a fecha2");
        }
    }
}

Salida:

fecha1 es antes que fecha2
fecha1 es anterior a fecha2

Conclusión

La API java.time de Java 1.8 es la mejor forma de manejar fechas y horas en Java. Es moderna, intuitiva y sigue estándares internacionales. Permite crear fechas de distintas maneras, con y sin zona horaria. También el formateo, modificación y comparación de fechas, que son operaciones esenciales en cualquier aplicación.

Con la API java.time de Java 1.8, estas tareas son más sencillas y seguras. Con estas herramientas, podrás trabajar con fechas de manera eficiente y sin errores comunes. ¡Practica con los ejemplos y domina esta API!

Próximos Pasos

  • Experimenta con los ejemplos de esta guía.
  • Investiga otros métodos de las clases LocalDate, LocalTime, LocalDateTime y ZonedDateTime.
  • Practica el formateo de fechas con diferentes patrones.
  • Explora cómo convertir entre la antigua API java.util.Date y la nueva java.time (si necesitas trabajar con código antiguo).

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.