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

ClassRepresentsExample
LocalDateA date without time2026-03-05
LocalTimeA time of day14:30
LocalDateTimeDate and time, no zone2026-03-05T14:30
ZonedDateTimeDate and time in a time zone2026-03-05T14:30+00:00[Europe/Lisbon]
InstantAn exact moment (UTC timestamp)2026-03-05T14:30:00Z
Duration / PeriodAn amount of time (hours…) / of dates (days, months…)PT2H30M / P1M10D

Creating and reading dates

JAVA
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));
    }
}
Output
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

JAVA
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));
    }
}
Output
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

JAVA
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");
    }
}
Output
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

JAVA
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);
    }
}
Output
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

JAVA
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());
    }
}
Output
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.

Try it yourself · Main.java
Edit the code, copy it into Main.java and run java Main.java (Java 25+). How to set up Java
Output
Bill 1: Sat 28 Feb 2026
Bill 2: Tue 31 Mar 2026
Bill 3: Thu 30 Apr 2026
Bill 4: Sun 31 May 2026