Fechas y horas en Java con java.time

El paquete java.time llegó en Java 8 y sustituyó a Date y Calendar, que eran mutables y empezaban los meses en cero. Si estás escribiendo código nuevo con SimpleDateFormat, esto es lo que lo reemplaza.

Cuatro clases, y elegir bien

Clase Guarda Úsala para
LocalDate 2026-10-06 cumpleaños, vencimientos, un día sin hora
LocalTime 14:30 una hora del día, sin fecha
LocalDateTime las dos, sin zona la hora de una reunión local
ZonedDateTime las dos con zona cualquier cosa que cruce husos
Instant un punto en la línea de tiempo marcas de tiempo, guardar en base de datos
salidaLocalDate     2026-10-06
  LocalTime     14:30
  LocalDateTime 2026-10-06T14:30
  ZonedDateTime 2026-10-06T14:30+02:00[Europe/Madrid]
  Instant       2026-10-06T12:30:00Z

Fíjate en la última línea: el mismo momento, visto desde UTC, son las 12:30. Un LocalDateTime no identifica un instante: «el 6 de octubre a las 14:30» ocurre a horas distintas en Madrid y en Tokio. Para registrar cuándo pasó algo, Instant.

Son inmutables

LocalDate manana = d.plusDays(1);
d.plusMonths(3);
d.withDayOfMonth(1);
d.withDayOfMonth(d.lengthOfMonth());
salidad=2026-10-06  d.plusDays(1)=2026-10-07
  dentro de 3 meses: 2027-01-06
  primer día del mes: 2026-10-01
  último del mes    : 2026-10-31

Ninguna operación modifica el objeto: todas devuelven uno nuevo. Igual que con los String, hay que recoger el resultado. Esto, que parece un detalle, es la razón principal de que java.time sustituyera a Calendar: una fecha que cambia bajo tus pies es un error difícil de encontrar.

Diferencias: Period y Duration

ChronoUnit.DAYS.between(d, otra);          // 146
Period.between(d, otra);                   // 0 años, 4 meses, 23 días
Duration.ofMinutes(195);                   // PT3H15M
salidadías entre: 146
  Period    : 0a 4m 23d
  Duration  : PT3H15M  -> 3h 15min

La distinción importa: Period es para fechas —años, meses, días, que duran lo que duran según el calendario— y Duration es para tiempo exacto, en segundos y nanosegundos. Sumar «un mes» no es sumar 30 días, y sumar «un día» en el cambio de hora no es sumar 24 horas. Por eso son dos clases.

Formatear y analizar

var fmt = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
dt.format(fmt);
LocalDateTime.parse("06/10/2026 14:30", fmt);
d.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(Locale.of("es","ES")));
salida06/10/2026 14:30
  2026-10-06T14:30
  ISO: 2026-10-06T14:30:00
  largo: martes, 6 de octubre de 2026
Cuidado con las letras del patrón. MM es el mes y mm los minutos; yyyy es el año y YYYY es el «año de la semana», que en los últimos días de diciembre devuelve el año siguiente. Ese último ha roto sistemas en producción cada 31 de diciembre durante años.

Y lo que pasa con una fecha imposible, que es lo que uno quiere que pase:

LocalDate.parse("2026-02-30")Text '2026-02-30' could not be parsed: Invalid date 'FEBRUARY 30'

Zonas horarias

madrid.withZoneSameInstant(ZoneId.of("America/Mexico_City"));
madrid.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
salidaMadrid           2026-10-06T14:30+02:00[Europe/Madrid]
  Ciudad de México 2026-10-06T06:30-06:00[America/Mexico_City]
  Tokio            2026-10-06T21:30+09:00[Asia/Tokyo]

El mismo instante, tres relojes. withZoneSameInstant cambia la zona conservando el momento; withZoneSameLocal hace lo contrario, conserva los números y cambia el instante. Casi siempre quieres el primero.

Y usa siempre identificadores de región —Europe/Madrid— y no desplazamientos fijos como +02:00: la región sabe cuándo hay horario de verano y el desplazamiento no.

Resumen

Quieres… Usa
Hoy LocalDate.now()
El instante actual, para registrar Instant.now()
Sumar días o meses plusDays, plusMonths (devuelven otro)
Cuántos días hay entre dos ChronoUnit.DAYS.between(a, b)
Años, meses y días Period.between(a, b)
Horas y minutos Duration
Mostrar con formato DateTimeFormatter.ofPattern
Cambiar de huso withZoneSameInstant

Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.