CodeGym /Kursy /JAVA 25 SELF /Obliczenia i porównywanie dat, Duration, Period

Obliczenia i porównywanie dat, Duration, Period

JAVA 25 SELF
Poziom 13, Lekcja 5
Dostępny

1. Dodawanie i odejmowanie dat i czasu

W programowaniu praca z datami i czasem to nie tylko „ładnie wyświetlić datę na ekranie”. Bardzo często trzeba:

  • dowiedzieć się, ile dni zostało do ważnego wydarzenia;
  • policzyć wiek użytkownika;
  • określić, ile czasu upłynęło między dwoma zdarzeniami;
  • sprawdzić, czy termin (deadline) już nadszedł;
  • dodać do daty określoną liczbę dni, tygodni, miesięcy lub godzin.

Na przykład w naszej aplikacji chcemy przypomnieć użytkownikowi, że do deadline’u zadania zostały 3 dni. Albo pogratulować mu minionych urodzin (jeśli data jest już w przeszłości).

Do tego w java.time są specjalne klasy i metody, które czynią takie obliczenia prostymi i bezpiecznymi.

Metody podstawowe do dodawania i odejmowania

Wszystkie klasy daty i czasu (LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant) mają metody:

  • plusXxx() — dodać (dni, miesiące, lata, godziny, minuty itp.)
  • minusXxx() — odjąć (to samo)
import java.time.LocalDate;

LocalDate today = LocalDate.now(); // Dzisiejsza data
LocalDate tomorrow = today.plusDays(1); // Jutro
LocalDate nextMonth = today.plusMonths(1); // Za miesiąc
LocalDate lastWeek = today.minusWeeks(1); // Tydzień temu

System.out.println("Dzisiaj: " + today);
System.out.println("Jutro: " + tomorrow);
System.out.println("Za miesiąc: " + nextMonth);
System.out.println("Tydzień temu: " + lastWeek);

Wszystkie te metody zwracają nowy obiekt, a nie zmieniają obiektu źródłowego. Niemutowalność — to podstawa!

import java.time.LocalTime;

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

System.out.println("Teraz: " + now);
System.out.println("Za 2 godziny: " + inTwoHours);
System.out.println("10 minut temu: " + tenMinutesAgo);

Metody łączone

LocalDate vacation = today.plusMonths(2).plusDays(10);
System.out.println("Urlop: " + vacation);

2. Obliczanie różnicy między datami: Period i Duration

Gdy trzeba dowiedzieć się, ile czasu upłynęło między dwiema datami lub momentami w czasie, na scenę wchodzą dwaj bohaterowie — Period i Duration. Poznajmy ich bliżej.

Jaka jest różnica między Period a Duration?

  • Period — do pracy z datami (rok, miesiąc, dzień). Na przykład „3 lata, 2 miesiące i 5 dni”.
  • Duration — do pracy z czasem (godziny, minuty, sekundy, nanosekundy). Na przykład „5 godzin 30 minut”.
Klasa Do czego służy Przykład użycia
Period
Różnica między datami Ile lat/miesięcy/dni pomiędzy datami
Duration
Różnica między momentami Ile godzin/minut/sekund między zdarzeniami

Przykład: obliczamy wiek użytkownika

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

LocalDate birthday = LocalDate.of(2000, 1, 15); // Urodziny
LocalDate today = LocalDate.now();

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

System.out.println("Wiek: " + age.getYears() + " lat, " +
                   age.getMonths() + " miesięcy, " +
                   age.getDays() + " dni");

Analogicznie: Period to „ludzka” różnica między datami („mam 24 lata 5 miesięcy 12 dni”).

Przykład: ile czasu pozostało do deadline’u

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("Do deadline’u pozostało: " +
        left.getMonths() + " miesięcy i " +
        left.getDays() + " dni");
} else {
    System.out.println("Deadline już minął!");
}

Duration: różnica czasu

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("Czas trwania: " + duration.toHours() + " godzin " +
                   (duration.toMinutes() % 60) + " minut");

Duration mierzy różnicę w sekundach, minutach, godzinach, dniach (ale dni — zawsze po 24 godziny, bez uwzględniania specyfiki kalendarza).

Porównanie: kiedy używać Period, a kiedy Duration?

  • Jeśli masz tylko daty (bez czasu) — użyj Period.
  • Jeśli masz czas (na przykład LocalDateTime, Instant) — użyj Duration.

3. Porównywanie dat i czasu: isBefore, isAfter, equals

Czasem trzeba po prostu ustalić: czy data już nadeszła, czy jeszcze nie? Zdarzenie jest w przeszłości czy w przyszłości? Do tego wszystkie klasy daty i czasu mają metody:

  • isBefore(otherDate)
  • isAfter(otherDate)
  • isEqual(otherDate) (albo po prostu equals)
import java.time.LocalDate;

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

if (today.isBefore(deadline)) {
    System.out.println("Wciąż jest czas!");
} else if (today.isEqual(deadline)) {
    System.out.println("Dziś deadline!");
} else {
    System.out.println("Deadline już minął :(");
}
import java.time.LocalTime;

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

if (now.isAfter(lunch)) {
    System.out.println("Obiad już był!");
} else {
    System.out.println("Do obiadu wciąż jest czas.");
}

Ważne: porównywać można tylko obiekty tego samego typu (LocalDate z LocalDate, LocalDateTime z LocalDateTime itd.).

4. Praktyka: zadania na obliczanie różnic i sprawdzanie terminów

Przykład: ile dni zostało do deadline’u zadania

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("Do deadline’u pozostało " + daysLeft + " dni");
} else if (daysLeft == 0) {
    System.out.println("Dziś deadline!");
} else {
    System.out.println("Deadline minął " + Math.abs(daysLeft) + " dni temu");
}

ChronoUnit.DAYS.between() — wygodny sposób, by poznać dokładną liczbę dni między dwiema datami (bez uwzględniania miesięcy i lat).

Przykład: ile sekund między dwoma zdarzeniami

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("Między zdarzeniami upłynęło " + seconds + " sekund");

Przykład: obliczanie „wieku” zadania

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("Zadanie zostało utworzone " +
    period.getDays() + " dni, " +
    period.getMonths() + " miesięcy i " +
    period.getYears() + " lat temu.");

Przykład: długość między dwoma Instant

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

Instant start = Instant.now();
// ... coś robimy ...
Instant end = Instant.now();

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

System.out.println("Wykonanie zajęło " + duration.toMillis() + " milisekund");

5. Szczegóły użycia Period i Duration

Specyfika Period

  • Period liczy różnicę według kalendarza: między 28 lutego a 1 marca — 1 dzień, nawet jeśli to różne miesiące.
  • Można osobno pobrać liczbę lat, miesięcy, dni: getYears(), getMonths(), getDays().
  • Jeśli potrzebujesz poznać łączną liczbę dni między datami — użyj ChronoUnit.DAYS.between().

Specyfika Duration

  • Duration pracuje z dokładnym czasem (godziny, minuty, sekundy).
  • Może współpracować z LocalTime, LocalDateTime, Instant.
  • Dla dat bez czasu (LocalDate) użyć nie można — będzie wyjątek.

Przykład: różnica między Period i 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 dni (rok przestępny)
long days = java.time.temporal.ChronoUnit.DAYS.between(date1, date2); // 2 dni

System.out.println("Period: " + period.getDays() + " dni");
System.out.println("ChronoUnit: " + days + " dni");

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 godziny
System.out.println("Duration: " + duration.toHours() + " godzin");

6. Użycie Duration i Period do prezentacji różnicy w wygodnej formie

Gdy obliczasz różnicę między datami lub czasem dla użytkownika, nie zawsze wygodnie jest pokazywać „123456 sekund”. Zwykle chcemy coś w rodzaju „2 dni 3 godziny 15 minut”.

Przykład: wyświetlenie różnicy między datą i czasem

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("Różnica: " + days + " dni " +
    hours + " godzin " + minutes + " minut");

7. Specyfika pracy z ZonedDateTime i Instant

  • Różnica między dwoma ZonedDateTime w różnych strefach jest liczona według czasu absolutnego, a nie „ludzkiego” czasu w każdej strefie.
  • Przejście na czas letni/zimowy może wpływać na różnicę godzin między datami.

Przykład: różnica między 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("Różnica: " + diff.toHours() + " godzin");

8. Typowe błędy przy obliczeniach z datami i czasem

Błąd nr 1: Mylenie Period i Duration.
Jeśli spróbujesz użyć Duration dla LocalDate, dostaniesz wyjątek. Dla dat używaj Period, dla czasu — Duration.

Błąd nr 2: Nieuwzględnianie stref czasowych.
Jeśli porównujesz daty i czas w różnych strefach czasowych, możesz otrzymać nieoczekiwane wyniki. Lepiej sprowadzić wszystko do jednej strefy albo używać Instant.

Błąd nr 3: Oczekiwanie, że metody plus/minus modyfikują obiekt.
Wszystkie obiekty java.time są niemutowalne! Pamiętaj, aby przypisać wynik do nowej zmiennej (na przykład today = today.plusDays(1)).

Błąd nr 4: Używanie getDays() w Period i mylenie tego z łączną liczbą dni.
W rzeczywistości to tylko dni resztowe po odjęciu lat i miesięcy. Aby poznać łączną liczbę dni, użyj ChronoUnit.DAYS.between().

Błąd nr 5: Porównywanie obiektów różnych typów.
Metody isBefore, isAfter, isEqual działają tylko dla obiektów tego samego typu (na przykład LocalDate z LocalDate).

1
Zadanie
JAVA 25 SELF, poziom 13, lekcja 5
Niedostępne
Odliczanie do święta 🎉
Odliczanie do święta 🎉
1
Zadanie
JAVA 25 SELF, poziom 13, lekcja 5
Niedostępne
Maszyna czasu: sprawdzenie, czy nadeszła data 🕰️
Maszyna czasu: sprawdzenie, czy nadeszła data 🕰️
1
Zadanie
JAVA 25 SELF, poziom 13, lekcja 5
Niedostępne
Zarządzanie projektem: ile dni pozostało do terminu? 🗓️
Zarządzanie projektem: ile dni pozostało do terminu? 🗓️
1
Zadanie
JAVA 25 SELF, poziom 13, lekcja 5
Niedostępne
Agencja nieruchomości: obliczanie wieku budynku 🏡
Agencja nieruchomości: obliczanie wieku budynku 🏡
1
Ankieta/quiz
Daty i czas, poziom 13, lekcja 5
Niedostępny
Daty i czas
Daty, czas i strefy czasowe
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION