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 хвилин».
| Клас | Для чого призначений | Приклад використання |
|---|---|---|
|
Різниця між датами | Скільки років/місяців/днів між датами |
|
Різниця між моментами | Скільки годин/хвилин/секунд між подіями |
Приклад: рахуємо вік користувача
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).
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ