java.time: LocalDate & LocalDateTime
Immutable date/time without zone; plusDays returns a new object.
Calendar and clock
**LocalDate: a date like a birthday (2024-07-04). LocalTime: a wall-clock time like 09:00. LocalDateTime: both together. None of them has a time zone — they describe what's written on a calendar or clock. Months are 1–12** (the old Calendar used 0–11!).
Immutable objects
Every java.time object is immutable. plusDays, plusWeeks, withYear… return a new object; the original never changes.
LocalDate due = LocalDate.of(2024, 5, 1);
LocalDate later = due.plusWeeks(2);
LocalDateTime meet = due.atTime(14, 30);
// due is still 2024-05-01Lost days
What does this print?
LocalDate d = LocalDate.of(2025, 12, 30);
d.plusDays(5);
System.out.println(d);
System.out.println(d.plusDays(5));2026-01-04 2026-01-042025-12-30 2026-01-042025-12-35 2026-01-04
Show the answer
Line 2 creates a new date and throws it away, so d is still 2025-12-30. Using the result gives 2026-01-04 — year rollover handled for you.
January 31 + 1 month?
What is LocalDate.of(2024, 1, 31).plusMonths(1)?
Think about it, then reveal the answer
2024-02-29. February 31 doesn't exist, so java.time clamps to the last valid day of the month. 2024 is a leap year, hence the 29th (in 2023 it would be the 28th).
Invalid dates throw
LocalDate.of validates every field. February 29 in a non-leap year throws **DateTimeException** instead of silently rolling over to March 1 like the old lenient Calendar did.
LocalDate.of(2023, 2, 29);
// DateTimeException: 2023 isn't a leap year
LocalDate.of(2024, 2, 29); // fineLeap day birthday
What does this print?
LocalDate leap = LocalDate.of(2024, 2, 29);
System.out.println(leap.plusYears(1));2025-03-012025-02-28Throws DateTimeException
Show the answer
2025-02-28 — another clamp: 2025 has no February 29, so java.time uses the last valid day of that month.
Dates in real apps
Subscription renewals, due dates and birthdays are classic LocalDate jobs. Month-end clamping is a real product decision: a plan bought on Jan 31 renews on Feb 29 — then on Mar 29 if you keep chaining from the last date, which is why billing systems usually compute from the *original* date.
Key takeaways
- Months are 1-12 (unlike old Calendar's 0-11)
- plusDays/withYear… return NEW objects
- Invalid dates throw DateTimeException
- Jan 31 + 1 month → last day of February
In the old API, Calendar.JANUARY is 0 — off-by-one month bugs were so common that java.time made months 1–12.
Practice questions
What does this print?
LocalDate d = LocalDate.of(2024, 3, 10);
d.plusDays(5);
System.out.println(d);- 2024-03-15
- 2024-03-10
- 2024-08-10
- 2024-3-10
Check your answer
2024-03-10. plusDays returns a new LocalDate, but the result is ignored. d still holds 2024-03-10.
What does this print?
LocalDate d = LocalDate.of(2024, 1, 31)
.plusMonths(1);
System.out.println(d);- 2024-02-31
- 2024-03-02
- 2024-02-29
- Throws DateTimeException
Check your answer
2024-02-29. February 31 doesn't exist, so plusMonths clamps to the last valid day. 2024 is a leap year, so that's the 29th.