JavaRush /Курсы /JAVA 25 SELF /Обзор java.time API, отличие от старых API

Обзор java.time API, отличие от старых API

JAVA 25 SELF
13 уровень , 1 лекция
Открыта

1. Исторический контекст: как работали с датами до Java 8

В далёкой древности (до Java 8) для работы с датами и временем использовали классы java.util.Date, java.util.Calendar и для форматирования — java.text.SimpleDateFormat. Это был тот случай, когда программисты всей планеты дружно вздыхали и, скрипя зубами, писали что-то вроде:

import java.util.Date;

Date now = new Date();
System.out.println(now); // Выведет что-то странное вроде "Wed Jun 05 14:15:22 MSK 2025"

Звучит просто, но на деле всё было не так радужно. Вот лишь некоторые "радости" старого API:

  • Date — изменяемый (mutable) объект. Его можно было случайно поменять, и это часто приводило к багам.
  • Месяцы в Date и Calendar начинались с нуля (январь — это 0, декабрь — 11), а дни — с единицы.
  • SimpleDateFormat не был потокобезопасным: если два потока форматировали дату одновременно, можно было получить неожиданные результаты.
  • Огромное количество методов было объявлено как @Deprecated (устаревшие), и IDE постоянно пугала вас жёлтыми предупреждениями.
  • Работа с часовыми поясами была настоящей болью: легко было перепутать локальное время и UTC, а про переход на летнее/зимнее время лучше вообще не вспоминать.

Пример боли

import java.util.Date;

Date date = new Date(2025, 5, 1); // 2025 год, 5 месяц (июнь?), 1 число
System.out.println(date); // Не то, что ожидаешь!

2. Появление java.time: новый подход

К 2014 году стало понятно: старый API не просто неудобен — он опасен. Поэтому в Java появился новый пакет — java.time, реализующий спецификацию JSR‑310. Этот API был вдохновлён популярной библиотекой Joda-Time и сразу стал стандартом де‑факто.

Основные пакеты и классы

  • java.time — основной пакет, где живут все новые классы для дат и времени.
  • java.time.format — для форматирования и парсинга дат и времени.
  • java.time.temporal — для более продвинутых временных операций.
  • java.time.zone — для работы с часовыми поясами.

Вот главные герои нового API:

Класс Для чего? Пример использования
LocalDate
Только дата (год, месяц, день) День рождения, без времени
LocalTime
Только время (часы, минуты, секунды) Время встречи, без даты
LocalDateTime
Дата и время, без часового пояса Локальное событие
ZonedDateTime
Дата и время с учётом таймзоны Встреча в Минске по местному времени
Instant
Абсолютная точка времени (UTC) Метка события в журнале
Duration
Промежуток времени (часы, минуты, сек.) Длительность звонка
Period
Период (годы, месяцы, дни) Стаж работы, возраст

Пример: создание даты по‑новому

import java.time.LocalDate;

LocalDate today = LocalDate.now();
System.out.println(today); // Например, "2025-06-05"

3. Преимущества нового API

Неизменяемость (immutable)

Все классы из java.time — неизменяемые. Это значит: если вы создали объект LocalDate, изменить его нельзя. Любая операция (например, добавить день) возвращает новый объект.

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

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

Явная работа с часовыми поясами

В старом API легко было забыть, в каком часовом поясе находится дата. В java.time всё явно: если нужен часовой пояс — используйте ZonedDateTime, если не нужен — используйте 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]

Удобные методы для вычислений и сравнения

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

Форматирование и парсинг

Форматирование и парсинг — через DateTimeFormatter (подробно — на следующей лекции):

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. Совместимость: как жить со старым кодом

В реальном мире очень часто приходится работать с библиотеками или старыми системами, где используются Date и Calendar. К счастью, новый API дружелюбен к наследию: можно конвертировать старые типы в новые и наоборот.

Преобразование DateInstant

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);

Преобразование CalendarZonedDateTime

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()));

Таблица: сопоставление старых и новых классов

Старый класс Новый класс Комментарий
java.util.Date
Instant
Абсолютное время
java.util.Calendar
ZonedDateTime
Дата и время с таймзоной
java.text.SimpleDateFormat
DateTimeFormatter
Форматирование/парсинг дат

5. Практика: первые шаги с java.time

Допустим, у вас есть пользователь с датой рождения. Сохраним и выведем эту дату:

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);
        System.out.println("Дата рождения: " + birthDate);
    }
}

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

Вывод:

Имя: Алиса
Дата рождения: 1998-12-25

6. Сравнение: старый API vs новый API

Пример: добавить неделю к дате рождения

Старый способ (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()); // Муторно и неочевидно

Новый способ (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

В новом API код короче, проще и безопаснее.

7. Типичные ошибки при работе с java.time

Ошибка №1: забыли, что объекты неизменяемы.
Если вызвать date.plusDays(1); и не сохранить результат, исходная дата останется прежней.

Ошибка №2: путаница между LocalDate и LocalDateTime.
LocalDate хранит только дату (год, месяц, день), а LocalDateTime — ещё и время. Не перепутайте, если нужно обработать и часы, и минуты.

Ошибка №3: использование старых классов в новых проектах.
Если есть возможность — всегда используйте java.time. Старые классы нужны только для совместимости.

Ошибка №4: неправильная работа с часовыми поясами.
Если нужно хранить событие, важное для разных регионов, используйте ZonedDateTime или хотя бы Instant. LocalDateTime не содержит информации о временной зоне!

Ошибка №5: попытка напрямую сравнивать LocalDate и LocalDateTime.
Это разные типы данных, сравнивать их напрямую нельзя. Сначала приведите к одному типу.

1
Задача
JAVA 25 SELF, 13 уровень, 1 лекция
Недоступна
Отметка текущего дня в календаре 🗓️
Отметка текущего дня в календаре 🗓️
1
Задача
JAVA 25 SELF, 13 уровень, 1 лекция
Недоступна
Взгляд назад: какой день был вчера? ⏪
Взгляд назад: какой день был вчера? ⏪
1
Задача
JAVA 25 SELF, 13 уровень, 1 лекция
Недоступна
Заглядываем в будущее: какой день будет завтра? ⏩
Заглядываем в будущее: какой день будет завтра? ⏩
1
Задача
JAVA 25 SELF, 13 уровень, 1 лекция
Недоступна
Фиксация важного исторического момента 📜
Фиксация важного исторического момента 📜
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
German Malykh Уровень 31
22 сентября 2025
Задание Фиксация важного исторического момента 📜

LocalDateTime historicMoment = LocalDateTime.of(...);

// Реализация метода из LocalDateTime класса 
// (Все параметры даты указываются через запятую)

public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) {
        LocalDate date = LocalDate.of(year, month, dayOfMonth);
        LocalTime time = LocalTime.of(hour, minute);
        return new LocalDateTime(date, time);
}