CodeGym /Courses /JAVA 25 SELF /Overview of the java.time API and differences from the le...

Overview of the java.time API and differences from the legacy APIs

JAVA 25 SELF
Level 13, Lesson 1
Available

1. Historical context: how dates were handled before Java 8

In the distant past (before Java 8), for working with dates and time, developers used the classes java.util.Date, java.util.Calendar and — for formatting — java.text.SimpleDateFormat. It was one of those cases where developers around the world sighed and, through gritted teeth, wrote something like:

import java.util.Date;

Date now = new Date();
System.out.println(now); // Will print something odd like "Wed Jun 05 14:15:22 MSK 2025"

It sounds simple, but in reality it wasn’t that rosy. Here are just some of the “joys” of the old API:

  • Date is a mutable object. You could accidentally change it, and that often led to bugs.
  • Months in Date and Calendar started at zero (January is 0, December is 11), while days started at one.
  • SimpleDateFormat was not thread‑safe: if two threads formatted a date simultaneously, you could get unexpected results.
  • A huge number of methods were annotated @Deprecated, and IDEs constantly peppered you with yellow warnings.
  • Working with time zones was a real pain: it was easy to confuse local time and UTC, and daylight saving time transitions were better left unmentioned.

An example of the pain

import java.util.Date;

Date date = new Date(2025, 5, 1); // year 2025, month 5 (June?), day 1
System.out.println(date); // Not what you expect!

2. The arrival of java.time: a new approach

By 2014 it had become clear: the old API was not just inconvenient — it was dangerous. Therefore, Java introduced a new package — java.time, implementing the JSR‑310 specification. This API was inspired by the popular Joda‑Time library and immediately became the de facto standard.

Core packages and classes

  • java.time — the core package where all the new date and time classes live.
  • java.time.format — for formatting and parsing dates and times.
  • java.time.temporal — for more advanced temporal operations.
  • java.time.zone — for working with time zones.

Here are the main players of the new API:

Class What for? Usage example
LocalDate
Date only (year, month, day) Birthday, no time
LocalTime
Time only (hours, minutes, seconds) Meeting time, no date
LocalDateTime
Date and time, no time zone Local event
ZonedDateTime
Date and time with time zone A meeting in Minsk in local time
Instant
Absolute point in time (UTC) Event log timestamp
Duration
Duration (hours, minutes, sec.) Call length
Period
Period (years, months, days) Work tenure, age

Example: creating a date the new way

import java.time.LocalDate;

LocalDate today = LocalDate.now();
System.out.println(today); // For example, "2025-06-05"

3. Advantages of the new API

Immutability (immutable)

All classes from java.time are immutable. This means: if you created a LocalDate object, you cannot change it. Any operation (for example, adding a day) returns a new object.

LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);

System.out.println(today);    // 2025-06-05
System.out.println(tomorrow); // 2025-06-06

Explicit time‑zone handling

In the old API it was easy to forget which time zone a date was in. In java.time everything is explicit: if you need a time zone — use ZonedDateTime, if you don’t — use LocalDateTime.

import java.time.ZonedDateTime;
import java.time.ZoneId;

ZonedDateTime MinskTime = ZonedDateTime.now(ZoneId.of("Europe/Minsk"));
System.out.println(MinskTime); // 2025-06-05T14:23:45+03:00[Europe/Minsk]

Convenient methods for calculations and comparison

LocalDate today = LocalDate.now();
LocalDate nextMonth = today.plusMonths(1);
boolean isAfter = LocalDate.now().plusDays(1).isAfter(today); // true

Formatting and parsing

Formatting and parsing are done via DateTimeFormatter (details — in the next lecture):

import java.time.format.DateTimeFormatter;

LocalDate today = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
String formatted = today.format(formatter); // "05.08.2025"

4. Compatibility: how to live with legacy code

In the real world, you very often have to work with libraries or legacy systems that use Date and Calendar. Fortunately, the new API is friendly to legacy: you can convert old types into new ones and back.

Converting Date ↔ Instant

import java.util.Date;
import java.time.Instant;

// Date → Instant
Date legacyDate = new Date();
Instant instant = legacyDate.toInstant();

// Instant → Date
Date dateBack = Date.from(instant);

Converting Calendar ↔ ZonedDateTime

import java.util.Calendar;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.util.Date;

// Calendar → ZonedDateTime
Calendar calendar = Calendar.getInstance();
ZonedDateTime zdt = ZonedDateTime.ofInstant(
        calendar.toInstant(),
        calendar.getTimeZone().toZoneId()
);

// ZonedDateTime → Calendar
Calendar calBack = Calendar.getInstance();
calBack.setTime(Date.from(zdt.toInstant()));

Table: mapping old and new classes

Old class New class Comment
java.util.Date
Instant
Absolute time
java.util.Calendar
ZonedDateTime
Date and time with time zone
java.text.SimpleDateFormat
DateTimeFormatter
Date formatting/parsing

5. Practice: first steps with java.time

Suppose you have a user with a date of birth. Let’s store and print this date:

import java.time.LocalDate;

public class UserProfile {
    private String name;
    private LocalDate birthDate;

    public UserProfile(String name, LocalDate birthDate) {
        this.name = name;
        this.birthDate = birthDate;
    }

    public void printProfile() {
        System.out.println("Name: " + name);
        System.out.println("Date of birth: " + birthDate);
    }
}

public class Main {
    public static void main(String[] args) {
        UserProfile user = new UserProfile("Alisa", LocalDate.of(1998, 12, 25));
        user.printProfile();
    }
}

Output:

Name: Alisa
Date of birth: 1998-12-25

6. Comparison: old API vs new API

Example: add a week to a birth date

Old way (Date/Calendar):

import java.util.Calendar;

Calendar cal = Calendar.getInstance();
cal.set(1998, Calendar.DECEMBER, 25);
cal.add(Calendar.WEEK_OF_YEAR, 1);
System.out.println(cal.getTime()); // Cumbersome and non-obvious

New way (java.time):

import java.time.LocalDate;

LocalDate birthDate = LocalDate.of(1998, 12, 25);
LocalDate nextWeek = birthDate.plusWeeks(1);
System.out.println(nextWeek); // 1999-01-01

In the new API, the code is shorter, simpler, and safer.

7. Common mistakes when working with java.time

Error No. 1: forgetting that objects are immutable.
If you call date.plusDays(1); and don’t store the result, the original date will remain the same.

Error No. 2: mixing up LocalDate and LocalDateTime.
LocalDate stores only a date (year, month, day), while LocalDateTime also stores time. Don’t confuse them if you need to handle hours and minutes.

Error No. 3: using old classes in new projects.
If possible — always use java.time. Old classes are only needed for compatibility.

Error No. 4: incorrect handling of time zones.
If you need to store an event that matters across regions, use ZonedDateTime or at least Instant. LocalDateTime does not contain time‑zone information!

Error No. 5: trying to compare LocalDate and LocalDateTime directly.
They are different data types; you cannot compare them directly. First convert to a common type.

1
Task
JAVA 25 SELF, level 13, lesson 1
Locked
Marking the current day in the calendar 🗓️
Marking the current day in the calendar 🗓️
1
Task
JAVA 25 SELF, level 13, lesson 1
Locked
Looking back: what day was yesterday? ⏪
Looking back: what day was yesterday? ⏪
1
Task
JAVA 25 SELF, level 13, lesson 1
Locked
Looking into the future: what day will tomorrow be? ⏩
Looking into the future: what day will tomorrow be? ⏩
1
Task
JAVA 25 SELF, level 13, lesson 1
Locked
Recording an important historical moment 📜
Recording an important historical moment 📜
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION