Java 49: java.time — LocalDate, Duration, Period & ZonedDateTime
easy⏱ 5 mincoursejava
The core types
LocalDate (date, no time, no zone — a birthday). LocalTime (wall-clock time). LocalDateTime (both, still no zone). Instant (a point on the UTC timeline — a timestamp). ZonedDateTime (instant + zone rules). Duration (time-based amount: seconds/nanos). Period (date-based amount: years/months/days). All are immutable — every plusDays returns a new object.
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 is human time — '2 months and 3 days'; how long a month is depends on the calendar. Duration is machine time — a fixed number of seconds, calendar-agnostic. Period.between(date1, date2) for age in years/months; Duration.between(instant1, instant2) for elapsed seconds. Mixing them is a category error: you can't add a Period to an Instant.
DST: where they disagree
Across a spring-forward DST transition, a single calendar day (Period of 1 day) is only 23 hours of real elapsed time (Duration). zdt.plus(Period.ofDays(1)) keeps the same wall-clock time tomorrow; zdt.plus(Duration.ofHours(24)) adds literal seconds and may land on a different wall-clock hour. Choose based on intent: 'same time tomorrow' = Period; 'exactly 24h later' = Duration.
Age, elapsed & DST mismatch
(1) Compute age in whole years from a birth date to a 'today' date using a Period-style diff. (2) Compute the Duration in hours between two timestamps. (3) Model a spring-forward day: adding a 1-day Period yields 24h of wall-clock but only 23h of real Duration — print both so they disagree by one hour. Confirm immutability: adding days returns a new value, the original is unchanged.
Always pass an explicit ZoneId / Clock
LocalDate.now() reads the system default zone — non-deterministic and untestable. Pass a Clock (LocalDate.now(clock)) or an explicit ZoneId so behavior is reproducible and tests can freeze time with Clock.fixed(...). Store timestamps as UTC Instant; convert to a zone only at display time.
Quiz: add 1 month to Jan 31
LocalDate.of(2023,1,31).plusMonths(1) = ? 2023-02-28 — java.time clamps to the last valid day of the target month rather than overflowing into March. The old Calendar would roll over to March 3. This clamping is a deliberate, well-defined rule worth knowing for date-math interview questions.