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); // 1 день
long days = java.time.temporal.ChronoUnit.DAYS.between(date1, date2); // 1 день

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
Опитування
Дати й час, рівень 13, лекція 5
Недоступний
Дати й час
Дати, час і таймзони
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ