Nueva API de fechas

java.time: LocalDate, LocalDateTime y ZonedDateTime

Por qué reemplaza Date y Calendar

java.util.Date y Calendar son mutuamente (y tristemente) célebres por ser mutables, con índices inconsistentes (mes 0-based, año relativo a 1900) y SimpleDateFormat sin thread-safety. La nueva API java.time (basada en Joda-Time) es inmutable, clara y segura.

// java.util.Date y Calendar: los problemas clásicos
Date fecha = new Date(2024, 1, 15); // ¡año=2024+1900, mes=0-indexed!
// → en realidad es 3924-02-15

Calendar cal = Calendar.getInstance();
cal.set(2024, Calendar.JANUARY, 15); // verboso y mutable
Date resultado = cal.getTime();      // la clase Date es mutable: peligrosa en APIs

// SimpleDateFormat: no es thread-safe
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// compartir este objeto entre hilos produce resultados incorrectos

LocalDate: fecha sin hora

Representa un día del calendario (año, mes, día) sin información de hora ni zona horaria. Inmutable. Ideal para fechas de nacimiento, vencimientos, eventos de día completo.

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

// Creación
LocalDate hoy = LocalDate.now();
LocalDate navidad = LocalDate.of(2024, Month.DECEMBER, 25);
LocalDate parseada = LocalDate.parse("2024-06-15"); // ISO 8601 por defecto

// Consulta
int año = navidad.getYear();          // 2024
Month mes = navidad.getMonth();       // DECEMBER
int dia = navidad.getDayOfMonth();    // 25
DayOfWeek diaSemana = navidad.getDayOfWeek(); // WEDNESDAY

// Aritmética (devuelve nueva instancia, son inmutables)
LocalDate manana = hoy.plusDays(1);
LocalDate mesAnterior = hoy.minusMonths(1);
LocalDate primeroDiaMes = hoy.withDayOfMonth(1);

LocalTime y LocalDateTime

LocalTime representa solo la hora del día. LocalDateTime combina fecha y hora, sin zona horaria — útil para horarios locales donde la zona se gestiona externamente.

import java.time.LocalDateTime;
import java.time.LocalTime;

// LocalTime: solo hora, sin fecha ni zona horaria
LocalTime ahora = LocalTime.now();
LocalTime mediodia = LocalTime.of(12, 0, 0);

// LocalDateTime: fecha + hora, sin zona horaria
LocalDateTime reunion = LocalDateTime.of(2024, 6, 15, 10, 30);
LocalDateTime ahora2 = LocalDateTime.now();

// Combinación
LocalDate fecha = LocalDate.of(2024, 6, 15);
LocalTime hora = LocalTime.of(10, 30);
LocalDateTime combinado = LocalDateTime.of(fecha, hora);

// Extracción
LocalDate soloFecha = reunion.toLocalDate();
LocalTime solaHora = reunion.toLocalTime();

ZonedDateTime e Instant

ZonedDateTime incluye zona horaria y gestiona correctamente el horario de verano (DST). Instant representa un punto exacto en la línea de tiempo en UTC, ideal para timestamps en logs y bases de datos.

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

// ZoneId identifica una zona horaria por nombre
ZoneId madrid = ZoneId.of("Europe/Madrid");
ZoneId nuevaYork = ZoneId.of("America/New_York");

// ZonedDateTime: fecha + hora + zona
ZonedDateTime ahoraEnMadrid = ZonedDateTime.now(madrid);
ZonedDateTime reunionNY = ZonedDateTime.of(2024, 6, 15, 10, 0, 0, 0, nuevaYork);

// Conversión entre zonas: automática, correcta con DST
ZonedDateTime mismaMadrid = reunionNY.withZoneSameInstant(madrid);

// Instant: punto en el tiempo en UTC (para logs, bbdd, comparaciones)
Instant ahora3 = Instant.now();
ZonedDateTime desde = ahora3.atZone(madrid);

Period y Duration

Period mide diferencias en unidades de calendario (años, meses, días). Duration mide diferencias en unidades de tiempo (horas, minutos, segundos, nanosegundos).

import java.time.Period;
import java.time.Duration;

// Period: diferencia en términos de fecha (años, meses, días)
LocalDate nacimiento = LocalDate.of(1990, 3, 15);
LocalDate hoy = LocalDate.now();
Period edad = Period.between(nacimiento, hoy);
System.out.println(edad.getYears() + " años"); // 34 años

// Duration: diferencia en términos de tiempo (horas, minutos, segundos, nanos)
LocalTime inicio = LocalTime.of(9, 0);
LocalTime fin = LocalTime.of(17, 30);
Duration jornada = Duration.between(inicio, fin);
System.out.println(jornada.toHours() + "h " + jornada.toMinutesPart() + "min");
// "8h 30min"

DateTimeFormatter

Reemplaza a SimpleDateFormat. Es inmutable y thread-safe: se puede compartir como constante estática sin riesgo.

import java.time.format.DateTimeFormatter;

LocalDateTime ahora = LocalDateTime.now();

// Formatters predefinidos
String iso = ahora.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
// "2024-06-15T10:30:00"

// Patrón personalizado
DateTimeFormatter formato = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
String legible = ahora.format(formato); // "15/06/2024 10:30"

// Parsing
LocalDateTime parseada = LocalDateTime.parse("15/06/2024 10:30", formato);

// DateTimeFormatter es thread-safe (a diferencia de SimpleDateFormat)
Guía de elección: usa LocalDate para fechas sin hora; LocalDateTime para fechas+hora sin zona; ZonedDateTime cuando la zona horaria importa; Instant para timestamps en logs y BBDD. Evita Date y Calendar en código nuevo.

Índice de la sección

Índice del curso