Platform & Advanced APIs
The Date & Time API (java.time)
java.time models time correctly by separating concepts:
Instant (machine time), LocalDate/LocalTime/LocalDateTime (human calendar, no zone), ZonedDateTime (zoned), Duration (machine spans) and Period (calendar spans). All immutable, all fluent.Instant= point on the timeline (UTC);LocalDateTime= wall-clock without zone;ZonedDateTime= both- Store and exchange Instant/UTC; apply
ZoneIdonly at presentation and business-rule edges Durationcounts seconds/nanos;Periodcounts years/months/days — DST makes them differ- Formatting/parsing:
DateTimeFormatter(immutable, thread-safe — unlike oldSimpleDateFormat) - Everything is immutable:
plusDaysreturns a new object - Legacy bridges:
Date.toInstant(),Timestamp.toLocalDateTime(),Calendar.toZonedDateTime()
Instant now = Instant.now(); // event timestamps, logs, DB
LocalDate birthday = LocalDate.of(1990, Month.MAY, 3); // no zone: calendar fact
ZonedDateTime meeting = ZonedDateTime.of(
LocalDate.of(2026, 7, 20), LocalTime.of(9, 30),
ZoneId.of("Europe/Belgrade")); // zoned: a real moment
Duration d = Duration.between(start, Instant.now()); // machine span
Period p = Period.between(birthday, LocalDate.now()); // calendar span (y/m/d)
long days = ChronoUnit.DAYS.between(birthday, LocalDate.now());The API forces the right questions. Adding a day across a DST fall-back: zoned.plusDays(1) keeps 9:30 next day (25 hours elapse); zoned.plus(Duration.ofHours(24)) gives 8:30. Neither is wrong — they answer different questions, and the old Date/Calendar API couldn't even express the distinction. TemporalAdjusters handle calendar arithmetic: date.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
.withLocale(Locale.GERMANY);
String s = fmt.format(meeting);
LocalDateTime parsed = LocalDateTime.parse("07.07.2026 09:30", fmt);
String iso = DateTimeFormatter.ISO_INSTANT.format(now); // 2026-07-07T14:00:00Z — for APIs