Mastery
Mastery/Java/I. Modules & misc stdlib
T1 · high-leverage

java.time vs. legacy Date/Calendar

The old java.util.Date/Calendar API has two infamous, real-bug-generating properties: months are 0-indexed (Calendar.JANUARY == 0), and Date objects are mutable -- two references to what you thought was "the same date" can be silently changed out from under each other. java.time (Java 8+) fixes both: months are a proper Month enum (January really is 1), and every type is immutable -- every "modifying" method returns a new instance.

java
import java.util.*;

Calendar cal = Calendar.getInstance();
cal.set(2024, Calendar.JANUARY, 15);
System.out.println("Calendar.JANUARY == " + Calendar.JANUARY + "  (0-indexed months -- a classic off-by-one bug source)");

Date mutable = new Date();
Date sameRef = mutable;
mutable.setTime(0);
System.out.println("Date is mutable -- \"sameRef\" changed too, since it's the SAME object: " + sameRef.getTime());
java
import java.time.*;

LocalDate date = LocalDate.of(2024, Month.JANUARY, 15);   // Month.JANUARY is 1, and it's a real enum, not a raw int
System.out.println("LocalDate: " + date);

LocalDate nextMonth = date.plusMonths(1);
System.out.println("original date is UNCHANGED (immutable): " + date);
System.out.println("plusMonths returns a brand new instance: " + nextMonth);

Duration measures machine-precision time spans (for Instants); Period measures calendar-aware spans (years/months/days) -- deliberately different types, because "1 month" isn't a fixed number of seconds:

java
Instant now = Instant.now();
Instant later = now.plusSeconds(3600);
System.out.println("Duration between instants: " + Duration.between(now, later));

Period period = Period.between(LocalDate.of(2024, 1, 1), LocalDate.of(2024, 3, 15));
System.out.println("Period (calendar-aware): " + period.getMonths() + " months, " + period.getDays() + " days");

LocalDate leapDayPlusYear = LocalDate.of(2024, 2, 29).plusYears(1);
System.out.println("Feb 29 2024 + 1 year (2025 isn't a leap year): " + leapDayPlusYear);

Interview angle

A practical "have you actually shipped date-handling bugs" question — asking why Calendar.JANUARY == 0 matters, or why Date being mutable is dangerous, tends to get much more specific, war-story answers from candidates who've actually debugged an off-by-one-month bug or a shared-mutable-date bug in production than from candidates reciting API docs.

In the industry

java.time has been the unambiguous default for any new code since Java 8 — style guides and static analysis at any team with a modern codebase flag new usage of Date/Calendar as a code-review comment on sight. Legacy codebases still interoperate with the old API at I/O boundaries (some old libraries and JDBC drivers still speak java.sql.Date), so Date.from(instant)/Date.toInstant()-style conversions at the boundary, followed by java.time everywhere else, is the standard migration pattern.