Dates & Times
The java.time package (Java 8+) is a clear, immutable and thread-safe API for dates, times, durations and time zones. It replaced the confusing old Date and Calendar classes. Use it for everything from due dates to scheduling across time zones.
The main types
| Class | Represents | Example |
|---|---|---|
LocalDate | A date without time | 2026-03-05 |
LocalTime | A time of day | 14:30 |
LocalDateTime | Date and time, no zone | 2026-03-05T14:30 |
ZonedDateTime | Date and time in a time zone | 2026-03-05T14:30+00:00[Europe/Lisbon] |
Instant | An exact moment (UTC timestamp) | 2026-03-05T14:30:00Z |
Duration / Period | An amount of time (hours…) / of dates (days, months…) | PT2H30M / P1M10D |
Creating and reading dates
import java.time.LocalDate; import java.time.LocalTime; import java.time.LocalDateTime; public class Main { public static void main(String[] args) { LocalDate date = LocalDate.of(2026, 3, 5); LocalDate parsed = LocalDate.parse("2026-12-25"); LocalDateTime meeting = LocalDateTime.of(2026, 3, 5, 14, 30); System.out.println(date + " " + parsed + " " + meeting); System.out.println(date.getDayOfWeek() + " " + date.getMonth() + " " + date.getDayOfYear()); System.out.println(date.isLeapYear() + " " + date.lengthOfMonth()); System.out.println(LocalTime.of(9, 5).isBefore(LocalTime.NOON)); } }
2026-03-05 2026-12-25 2026-03-05T14:30 THURSDAY MARCH 64 false 31 true
LocalDate.now() gives today's date. Dates are immutable — every "change" returns a new object.
Date arithmetic
import java.time.LocalDate; import java.time.DayOfWeek; import java.time.temporal.TemporalAdjusters; public class Main { public static void main(String[] args) { LocalDate order = LocalDate.of(2026, 1, 31); System.out.println(order.plusDays(14)); System.out.println(order.plusMonths(1)); System.out.println(order.minusWeeks(2)); System.out.println(order.with(TemporalAdjusters.lastDayOfMonth())); System.out.println(order.with(TemporalAdjusters.next(DayOfWeek.MONDAY))); System.out.println(order.withDayOfMonth(1)); } }
2026-02-14 2026-02-28 2026-01-17 2026-01-31 2026-02-02 2026-01-01
Adding a month to 31 January gives 28 February: java.time clamps to the last valid day rather than overflowing. Temporal adjusters answer questions like "the next Monday" or "the end of the month".
Differences between dates
import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Period; import java.time.temporal.ChronoUnit; public class Main { public static void main(String[] args) { LocalDate hired = LocalDate.of(2019, 2, 18); LocalDate today = LocalDate.of(2026, 3, 31); Period service = Period.between(hired, today); System.out.println(service.getYears() + " years, " + service.getMonths() + " months, " + service.getDays() + " days"); System.out.println(ChronoUnit.DAYS.between(hired, today) + " days in total"); Duration call = Duration.between(LocalDateTime.of(2026, 3, 5, 9, 15), LocalDateTime.of(2026, 3, 5, 11, 40)); System.out.println(call + " = " + call.toMinutes() + " minutes"); } }
7 years, 1 months, 13 days 2598 days in total PT2H25M = 145 minutes
Period measures in calendar units (years, months, days); Duration in exact time (hours, minutes, seconds). ChronoUnit.X.between gives a single total.
Formatting and parsing
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; public class Main { public static void main(String[] args) { LocalDateTime t = LocalDateTime.of(2026, 3, 5, 14, 30); System.out.println(t.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"))); System.out.println(t.format(DateTimeFormatter.ofPattern("EEEE d MMMM yyyy", Locale.ENGLISH))); System.out.println(t.format(DateTimeFormatter.ofPattern("EEEE d MMMM yyyy", Locale.forLanguageTag("pt-PT")))); LocalDate d = LocalDate.parse("05.03.2026", DateTimeFormatter.ofPattern("dd.MM.yyyy")); System.out.println(d); } }
05/03/2026 14:30 Thursday 5 March 2026 quinta-feira 5 março 2026 2026-03-05
Pattern letters: yyyy year, MM month number, MMMM month name, dd day, EEEE weekday name, HH hour (0–23), mm minutes. Note MM (month) vs mm (minutes). Names follow the locale.
Time zones
import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; public class Main { public static void main(String[] args) { ZonedDateTime lisbon = ZonedDateTime.of(LocalDateTime.of(2026, 7, 1, 9, 0), ZoneId.of("Europe/Lisbon")); ZonedDateTime tokyo = lisbon.withZoneSameInstant(ZoneId.of("Asia/Tokyo")); ZonedDateTime newYork = lisbon.withZoneSameInstant(ZoneId.of("America/New_York")); System.out.println(lisbon); System.out.println(tokyo); System.out.println(newYork); Instant instant = lisbon.toInstant(); System.out.println(instant + " " + instant.getEpochSecond()); } }
2026-07-01T09:00+01:00[Europe/Lisbon] 2026-07-01T17:00+09:00[Asia/Tokyo] 2026-07-01T04:00-04:00[America/New_York] 2026-07-01T08:00:00Z 1782892800
A ZonedDateTime knows its zone's rules, including daylight saving time (Lisbon is UTC+1 in summer). Store moments as Instant (UTC) and convert to the user's zone only for display.
Try it yourself
List the next four monthly billing dates for a subscription started on 31 January.
Bill 1: Sat 28 Feb 2026 Bill 2: Tue 31 Mar 2026 Bill 3: Thu 30 Apr 2026 Bill 4: Sun 31 May 2026