Java 49: java.time — LocalDate, Duration, Period & ZonedDateTime
easy⏱ 5 mincoursejava
Los tipos centrales
LocalDate (fecha, sin hora, sin zona — un cumpleaños). LocalTime (hora de reloj). LocalDateTime (ambos, aún sin zona). Instant (un punto en la línea de tiempo UTC — un timestamp). ZonedDateTime (instante + reglas de zona). Duration (cantidad basada en tiempo: segundos/nanos). Period (cantidad basada en fecha: años/meses/días). Todos inmutables — cada plusDays devuelve un objeto nuevo.
LocalDate d = LocalDate.of(2024, 2, 29);
LocalDate next = d.plusYears(1); // 2025-02-28 (clamped!)
Instant now = Instant.now();
ZonedDateTime z = now.atZone(ZoneId.of("Europe/Madrid"));
Period vs Duration
Period es tiempo humano — '2 meses y 3 días'; cuánto dura un mes depende del calendario. Duration es tiempo de máquina — un número fijo de segundos, agnóstico al calendario. Period.between(date1, date2) para edad en años/meses; Duration.between(instant1, instant2) para segundos transcurridos. Mezclarlos es un error de categoría: no puedes sumar un Period a un Instant.
DST: donde discrepan
A través de una transición DST de adelanto (spring-forward), un solo día de calendario (Period de 1 día) son solo 23 horas de tiempo real transcurrido (Duration). zdt.plus(Period.ofDays(1)) mantiene la misma hora de reloj mañana; zdt.plus(Duration.ofHours(24)) suma segundos literales y puede caer en otra hora de reloj. Elige según la intención: 'misma hora mañana' = Period; 'exactamente 24h después' = Duration.
Edad, transcurrido y desajuste DST
(1) Calcula la edad en años enteros desde una fecha de nacimiento a una fecha de 'hoy' usando un diff estilo Period. (2) Calcula la Duration en horas entre dos timestamps. (3) Modela un día de spring-forward: sumar un Period de 1 día da 24h de reloj pero solo 23h de Duration real — imprime ambos para que discrepen en una hora. Confirma la inmutabilidad: sumar días devuelve un valor nuevo, el original no cambia.
Pasa siempre un ZoneId / Clock explícito
LocalDate.now() lee la zona por defecto del sistema — no determinista e imposible de testear. Pasa un Clock (LocalDate.now(clock)) o un ZoneId explícito para que el comportamiento sea reproducible y los tests congelen el tiempo con Clock.fixed(...). Guarda timestamps como Instant en UTC; convierte a zona solo al mostrar.
Quiz: sumar 1 mes a Jan 31
LocalDate.of(2023,1,31).plusMonths(1) = ? 2023-02-28 — java.time recorta al último día válido del mes destino en vez de desbordar a marzo. El viejo Calendar saltaría a marzo 3. Este recorte es una regla deliberada y bien definida que vale la pena conocer para preguntas de aritmética de fechas.