JavaRush /Курсы /JAVA 25 SELF /Вычисления и сравнение дат, Duration, Period

Вычисления и сравнение дат, Duration, Period

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

1. Прибавление и вычитание дат и времени

В программировании работа с датами и временем — это не только "красиво вывести дату на экран". Очень часто требуется:

  • узнать, сколько дней осталось до важного события;
  • посчитать возраст пользователя;
  • определить, сколько времени прошло между двумя событиями;
  • проверить, не наступил ли дедлайн;
  • прибавить к дате определённое количество дней, недель, месяцев или часов.

Например, в нашем приложении мы хотим напомнить пользователю, что до дедлайна задачи осталось 3 дня. Или поздравить его с прошедшим днём рождения (если дата уже в прошлом).

Для этого в java.time есть специальные классы и методы, которые делают такие вычисления простыми и безопасными.

Основные методы для сложения и вычитания

У всех классов даты и времени (LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant) есть методы:

  • plusXxx() — прибавить (дни, месяцы, годы, часы, минуты и т.д.)
  • minusXxx() — вычесть (то же самое)
import java.time.LocalDate;

LocalDate today = LocalDate.now(); // Сегодняшняя дата
LocalDate tomorrow = today.plusDays(1); // Завтра
LocalDate nextMonth = today.plusMonths(1); // Через месяц
LocalDate lastWeek = today.minusWeeks(1); // Неделю назад

System.out.println("Сегодня: " + today);
System.out.println("Завтра: " + tomorrow);
System.out.println("Через месяц: " + nextMonth);
System.out.println("Неделю назад: " + lastWeek);

Все эти методы возвращают новый объект, а не изменяют исходный. Неизменяемость — наше всё!

import java.time.LocalTime;

LocalTime now = LocalTime.now();
LocalTime inTwoHours = now.plusHours(2);
LocalTime tenMinutesAgo = now.minusMinutes(10);

System.out.println("Сейчас: " + now);
System.out.println("Через 2 часа: " + inTwoHours);
System.out.println("10 минут назад: " + tenMinutesAgo);

Комбинированные методы

LocalDate vacation = today.plusMonths(2).plusDays(10);
System.out.println("Отпуск: " + vacation);

2. Получение разницы между датами: Period и Duration

Когда нужно узнать, сколько времени прошло между двумя датами или моментами времени, на сцену выходят два героя — Period и Duration. Давайте познакомимся с ними поближе.

В чём разница между Period и Duration?

  • Period — для работы с датами (год, месяц, день). Например, "3 года, 2 месяца и 5 дней".
  • Duration — для работы с временем (часы, минуты, секунды, наносекунды). Например, "5 часов 30 минут".
Класс Для чего предназначен Пример использования
Period
Разница между датами Сколько лет/месяцев/дней между датами
Duration
Разница между моментами Сколько часов/минут/секунд между событиями

Пример: вычисляем возраст пользователя

import java.time.LocalDate;
import java.time.Period;

LocalDate birthday = LocalDate.of(2000, 1, 15); // День рождения
LocalDate today = LocalDate.now();

Period age = Period.between(birthday, today);

System.out.println("Возраст: " + age.getYears() + " лет, " +
                   age.getMonths() + " месяцев, " +
                   age.getDays() + " дней");

Аналогия: Period — это как "человеческая" разница между датами ("мне 24 года 5 месяцев 12 дней").

Пример: сколько времени осталось до дедлайна

import java.time.LocalDate;

LocalDate deadline = LocalDate.of(2025, 7, 1);
LocalDate today = LocalDate.now();

if (today.isBefore(deadline)) {
    Period left = Period.between(today, deadline);
    System.out.println("До дедлайна осталось: " +
        left.getMonths() + " месяцев и " +
        left.getDays() + " дней");
} else {
    System.out.println("Дедлайн уже прошёл!");
}

Duration: разница во времени

import java.time.LocalDateTime;
import java.time.Duration;

LocalDateTime start = LocalDateTime.of(2025, 6, 1, 10, 0, 0);
LocalDateTime end = LocalDateTime.of(2025, 6, 1, 15, 30, 0);

Duration duration = Duration.between(start, end);

System.out.println("Продолжительность: " + duration.toHours() + " часов " +
                   (duration.toMinutes() % 60) + " минут");

Duration измеряет разницу в секундах, минутах, часах, днях (но дни — всегда по 24 часа, без учёта календарных особенностей).

Сравнение: когда использовать Period, а когда Duration?

  • Если у вас только даты (без времени) — используйте Period.
  • Если у вас есть время (например, LocalDateTime, Instant) — используйте Duration.

3. Сравнение дат и времени: isBefore, isAfter, equals

Иногда нужно просто понять: дата уже наступила или ещё нет? Событие в прошлом или будущем? Для этого у всех классов даты и времени есть методы:

  • isBefore(другаяДата)
  • isAfter(другаяДата)
  • isEqual(другаяДата) (или просто equals)
import java.time.LocalDate;

LocalDate today = LocalDate.now();
LocalDate deadline = LocalDate.of(2025, 7, 1);

if (today.isBefore(deadline)) {
    System.out.println("Всё ещё есть время!");
} else if (today.isEqual(deadline)) {
    System.out.println("Сегодня дедлайн!");
} else {
    System.out.println("Дедлайн уже прошёл :(");
}
import java.time.LocalTime;

LocalTime now = LocalTime.now();
LocalTime lunch = LocalTime.of(13, 0);

if (now.isAfter(lunch)) {
    System.out.println("Обед уже был!");
} else {
    System.out.println("До обеда ещё есть время.");
}

Важно: сравнивать можно только объекты одного типа (LocalDate с LocalDate, LocalDateTime с LocalDateTime и т.д.).

4. Практика: задачи на вычисление разницы и проверку сроков

Пример: сколько дней осталось до дедлайна задачи

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

LocalDate today = LocalDate.now();
LocalDate deadline = LocalDate.of(2025, 7, 1);

long daysLeft = ChronoUnit.DAYS.between(today, deadline);

if (daysLeft > 0) {
    System.out.println("До дедлайна осталось " + daysLeft + " дней");
} else if (daysLeft == 0) {
    System.out.println("Сегодня дедлайн!");
} else {
    System.out.println("Дедлайн прошёл " + Math.abs(daysLeft) + " дней назад");
}

ChronoUnit.DAYS.between() — удобный способ узнать точное количество дней между двумя датами (без учёта месяцев и лет).

Пример: сколько секунд между двумя событиями

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

LocalDateTime start = LocalDateTime.of(2025, 6, 1, 10, 0, 0);
LocalDateTime end = LocalDateTime.of(2025, 6, 1, 15, 30, 0);

long seconds = ChronoUnit.SECONDS.between(start, end);

System.out.println("Между событиями прошло " + seconds + " секунд");

Пример: вычисление возраста задачи

import java.time.LocalDate;
import java.time.Period;

LocalDate created = LocalDate.of(2025, 5, 20);
LocalDate today = LocalDate.now();

Period period = Period.between(created, today);

System.out.println("Задача была создана " +
    period.getDays() + " дней, " +
    period.getMonths() + " месяцев и " +
    period.getYears() + " лет назад.");

Пример: длительность между двумя Instant

import java.time.Instant;
import java.time.Duration;

Instant start = Instant.now();
// ... что-то делаем ...
Instant end = Instant.now();

Duration duration = Duration.between(start, end);

System.out.println("Выполнение заняло " + duration.toMillis() + " миллисекунд");

5. Особенности использования Period и Duration

Особенности Period

  • Period считает разницу по календарю: между 28 февраля и 1 марта — 1 день, даже если это разные месяцы.
  • Можно получить количество лет, месяцев, дней по отдельности: getYears(), getMonths(), getDays().
  • Если нужно узнать общее количество дней между датами — используйте ChronoUnit.DAYS.between().

Особенности Duration

  • Duration работает с точным временем (часы, минуты, секунды).
  • Может работать с LocalTime, LocalDateTime, Instant.
  • Для дат без времени (LocalDate) использовать нельзя — будет исключение.

Пример: разница между Period и Duration

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Duration;
import java.time.Period;

LocalDate date1 = LocalDate.of(2025, 2, 28);
LocalDate date2 = LocalDate.of(2025, 3, 1);

Period period = Period.between(date1, date2); // 2 дня (високосный год)
long days = java.time.temporal.ChronoUnit.DAYS.between(date1, date2); // 2 дня

System.out.println("Period: " + period.getDays() + " дней");
System.out.println("ChronoUnit: " + days + " дней");

LocalDateTime dt1 = LocalDateTime.of(2025, 6, 1, 23, 0);
LocalDateTime dt2 = LocalDateTime.of(2025, 6, 2, 1, 0);

Duration duration = Duration.between(dt1, dt2); // 2 часа
System.out.println("Duration: " + duration.toHours() + " часов");

6. Использование Duration и Period для вывода разницы в удобном виде

Когда вы вычисляете разницу между датами или временем для пользователя, не всегда удобно показывать "123456 секунд". Обычно хочется что-то вроде "2 дня 3 часа 15 минут".

Пример: вывод разницы между датами и временем

import java.time.LocalDateTime;
import java.time.Duration;

LocalDateTime start = LocalDateTime.of(2025, 6, 1, 14, 0);
LocalDateTime end = LocalDateTime.of(2025, 6, 3, 16, 30);

Duration duration = Duration.between(start, end);

long days = duration.toDays();
long hours = duration.minusDays(days).toHours();
long minutes = duration.minusDays(days).minusHours(hours).toMinutes();

System.out.println("Разница: " + days + " дней " +
    hours + " часов " + minutes + " минут");

7. Особенности при работе с ZonedDateTime и Instant

  • Разница между двумя ZonedDateTime в разных зонах считается по абсолютному времени, а не по "человеческому" времени в каждой зоне.
  • Переход на летнее/зимнее время может влиять на разницу в часах между датами.

Пример: разница между ZonedDateTime

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

ZonedDateTime MinskTime = ZonedDateTime.of(2025, 6, 1, 12, 0, 0, 0, ZoneId.of("Europe/Minsk"));
ZonedDateTime nyTime = ZonedDateTime.of(2025, 6, 1, 5, 0, 0, 0, ZoneId.of("America/New_York"));

Duration diff = Duration.between(nyTime, MinskTime);
System.out.println("Разница: " + diff.toHours() + " часов");

8. Типичные ошибки при вычислениях с датами и временем

Ошибка №1: Путают Period и Duration.
Если попытаться использовать Duration для LocalDate, получите исключение. Для дат используйте Period, для времени — Duration.

Ошибка №2: Не учитывают часовые пояса.
Если сравнивать даты и время в разных часовых поясах, можно получить неожиданные результаты. Лучше приводить всё к одному поясу или использовать Instant.

Ошибка №3: Ожидают, что методы plus/minus изменяют объект.
Все объекты java.time неизменяемы! Не забывайте присваивать результат в новую переменную (например, today = today.plusDays(1)).

Ошибка №4: Используют getDays() у Period и думают, что это общее количество дней.
На самом деле это только остаточные дни после вычитания лет и месяцев. Для общего количества дней используйте ChronoUnit.DAYS.between().

Ошибка №5: Сравнивают объекты разных типов.
Методы isBefore, isAfter, isEqual работают только для объектов одного и того же типа (например, LocalDate с LocalDate).

1
Задача
JAVA 25 SELF, 13 уровень, 5 лекция
Недоступна
Обратный отсчет до праздника 🎉
Обратный отсчет до праздника 🎉
1
Задача
JAVA 25 SELF, 13 уровень, 5 лекция
Недоступна
Машина времени: проверка наступления даты 🕰️
Машина времени: проверка наступления даты 🕰️
1
Задача
JAVA 25 SELF, 13 уровень, 5 лекция
Недоступна
Проектный менеджмент: сколько дней до дедлайна? 🗓️
Проектный менеджмент: сколько дней до дедлайна? 🗓️
1
Задача
JAVA 25 SELF, 13 уровень, 5 лекция
Недоступна
Агентство недвижимости: расчет возраста здания 🏡
Агентство недвижимости: расчет возраста здания 🏡
1
Опрос
Даты и время, 13 уровень, 5 лекция
Недоступен
Даты и время
Даты, время и таймзоны
Комментарии (6)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Anonymous #6452546 Уровень 14
20 января 2026
В пункте 5 пример 1 опечатка в комментарии 2025 не високосный год. Она смутила при выборе ответа в тесте на вопрос.
Anonymous #3391603 Уровень 18
16 ноября 2025
Результат вызова метода parse не используется. Ничего не будет выведено.
Dthmth Уровень 11
27 октября 2025
Уже были же раньше задачи с isBefore и plus\minus, как будто хотелось бы больше задач на Period и Duration
Александр Уровень 50
19 октября 2025
В итоговом опроснике правильный ответ на вопрос "Какой метод используется для преобразования LocalDateTime в ZonedDateTime?" выделен особо. Спасибо))))
Александр Уровень 50
19 октября 2025
В разделе Дата/Время, в примерах не показаны результаты вывода в консоль - ненаглядно.
Александр Уровень 50
19 октября 2025
В этой лекции, а также некоторых предыдущих:

ZonedDateTime MinskTime
Вот это я понимаю уважение к минской временной зоне))))