What's new in the java.time API (LocalDate, LocalDateTime, etc.) compared to legacy Date/Calendar?
Quick Answer
java.time (Java 8+, based on the Joda-Time library) replaces the old, widely criticized java.util.Date/Calendar with immutable, thread-safe types split by concern: LocalDate (date only), LocalTime (time only), LocalDateTime (date+time, no timezone), ZonedDateTime (date+time with timezone), Instant (a machine timestamp), and Duration/Period for spans of time. Unlike Date, months are numbered naturally (1=January) and the API is far more expressive for date arithmetic, formatting, and parsing.
Detailed Answer
java.util.Date and Calendar (pre-Java 8) had well-known problems: Date is mutable (unsafe to share across threads or expose from an API without defensive copying), months are zero-indexed (Calendar.JANUARY == 0, a classic source of off-by-one bugs), and the API for basic arithmetic (adding days, comparing dates) is clunky and easy to misuse.
java.time (Java 8+, based on the well-regarded Joda-Time library) fixes this with a set of immutable, thread-safe types, each modeling a distinct concept:
| Type | Represents |
|---|---|
LocalDate | a date with no time or timezone (2026-07-04) |
LocalTime | a time with no date or timezone (14:30:00) |
LocalDateTime | date + time, still no timezone |
ZonedDateTime | date + time + timezone, for absolute points tied to a specific location's rules (including DST) |
Instant | a machine-readable timestamp (epoch seconds/nanos), timezone-agnostic |
Duration | a time-based amount (hours, minutes, seconds) |
Period | a date-based amount (years, months, days) |
LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plusWeeks(1); // fluent, immutable arithmetic
Period age = Period.between(birthDate, today); // date-based span
LocalDateTime dt = LocalDateTime.of(2026, 7, 4, 10, 30); // month = 7, not 6 — sane numbering
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String formatted = dt.format(fmt);
Key improvements over the legacy API: every type is immutable (every "modifying" method returns a new instance, safe to share across threads without synchronization), months/days use natural, human-numbered values, the API distinguishes clearly between date-only, time-only, and zoned concepts instead of forcing everything through one Date/Calendar pair, and DateTimeFormatter (also thread-safe, unlike the old SimpleDateFormat) handles parsing/formatting.