java.time replaces Date and Calendar

Java 8 Course · lesson 8 of 16 · 4 min read

The old date classes were mutable, zero-indexed and not thread safe. Java 8 replaced them wholesale.

Open this lesson in the learning hub

Key points

  • java.util.Date is mutable, so handing one out leaks control of your own state.
  • Calendar months were zero-based - January was 0, a bug factory for twenty years.
  • SimpleDateFormat holds parsing state, so sharing one between threads silently corrupts results.
  • Every java.time type is immutable and thread safe; each operation returns a new value.
  • Pick by meaning: LocalDate for a birthday, Instant for a timestamp, ZonedDateTime when the zone matters.

Example

import java.time.*;
import java.time.format.*;
import java.time.temporal.ChronoUnit;

public class Main {
    public static void main(String[] args) {
        LocalDate release8  = LocalDate.of(2014, Month.MARCH, 18);
        LocalDate release21 = LocalDate.of(2023, 9, 19);

        System.out.println("Java 8 released  : " + release8);
        System.out.println("Java 21 released : " + release21);
        System.out.println("Years between    : " +
            ChronoUnit.YEARS.between(release8, release21));

        // Immutable: plusYears returns a NEW value
        LocalDate later = release8.plusYears(10);
        System.out.println("original untouched: " + release8 + " -> " + later);

        // DateTimeFormatter is immutable and safe to share
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MMM yyyy");
        System.out.println("formatted        : " + release8.format(fmt));

        System.out.println("a real instant   : " + Instant.ofEpochSecond(1_395_100_800L));
    }
}

java.time is not a tidier Date - it is a different model where values never change underneath you.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Java 8 Course course, and every lesson in it is listed on the Java 8 Course contents page.