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)