Joda-Time: co to jest, biblioteka dat i zamiennik na Java 8

Autor: IT Sectr Opublikowano: 2026-07-14 Czas czytania: 10 min

Joda-Time — biblioteka do pracy z datami i czasem w Javie, stworzona przez Stephena Colebourne'a jako alternatywa dla niewygodnych java.util.Date i java.util.Calendar. Przed wydaniem Javy 8 biblioteka ta była de facto standardem pracy z datami w rozwoju przemysłowym, w tym w aplikacjach Android. Według danych Oracle Java Magazine (2023), ponad 60% projektów migrowało z Joda-Time na java.time w ciągu dwóch lat po wydaniu Android API 26.

Najważniejsze

  • Joda-Time — biblioteka do pracy z datami i czasem, poprzednik java.time w Javie 8
  • Immutable-klasy — DateTime, LocalDate, LocalTime, LocalDateTime zapewniają bezpieczeństwo wątków
  • Wsparcie stref czasowych — wbudowana baza stref czasowych z automatycznymi aktualizacjami
  • Migracja — java.time (JSR-310) całkowicie zastępuje Joda-Time, autorzy biblioteki zalecają przejście
  • Android — Joda-Time działa od API 1, ale dla Android 8+ (API 26) preferowany jest java.time

Czym jest Joda-Time?

Joda-Time — to biblioteka typu open source (Apache 2.0), zapewniająca wysokiej jakości zastąpienie klas java.util.Date i java.util.Calendar w języku Java. Projekt został założony przez Stephena Colebourne'a w 2004 roku w odpowiedzi na liczne problemy standardowych API do pracy z datami, w tym mutowalność, złożoność formatowania i ograniczone wsparcie stref czasowych. Biblioteka zyskała szerokie rozpowszechnienie w społeczności Java i była używana przez tysiące projektów, w tym duże systemy klasy enterprise i aplikacje Android, gdzie wbudowane narzędzia do pracy z datami były szczególnie niewygodne. Od momentu wydania Javy 8 w 2014 roku i pojawienia się pakietu java.time (JSR-310) biblioteka została przeniesiona w tryb utrzymania — nowe funkcje nie są dodawane, a istniejąca funkcjonalność jest w pełni pokrywana przez nowe API.

Architektura biblioteki

Joda-Time jest zbudowana na zasadzie niemutowalności: każdy obiekt daty lub czasu po utworzeniu nie może zostać zmieniony. Każda operacja — dodanie dnia, zmiana miesiąca, ustawienie strefy czasowej — zwraca nowy obiekt, pozostawiając oryginał bez zmian. Takie podejście całkowicie eliminuje klasę błędów związanych z niezamierzoną modyfikacją obiektów, które były charakterystyczne dla mutowalnych java.util.Date i java.util.Calendar. Immutable-design czyni również bibliotekę bezpieczną wątkowo bez dodatkowej synchronizacji.

Podstawowe klasy Joda-Time

Biblioteka udostępnia kilka głównych klas dla różnych scenariuszy: DateTime — pełna data i czas ze strefą czasową, LocalDate — tylko data bez czasu, LocalTime — tylko czas bez daty, LocalDateTime — data i czas bez przypisania do strefy. Ponadto dołączone są klasy do pracy z interwałami (Interval), okresami (Period) i czasami trwania (Duration), które umożliwiają obliczanie różnicy między dwoma momentami czasu w różnych jednostkach miary. Każda klasa implementuje interfejs ReadableInstant lub ReadablePartial dla jednolitego przetwarzania.

Historia powstania Joda-Time

Problem standardowych API dat w Javie był znany od samego początku platformy. Klasy java.util.Date i java.util.Calendar miały fundamentalne wady: miesiące numerowane były od 0, Date jednocześnie reprezentował datę i czas, Calendar był mutowalny i wymagał złożonej konfiguracji. Formatowanie przez SimpleDateFormat nie było bezpieczne wątkowo — w aplikacjach wielowątkowych prowadziło to do nieprawidłowego parsowania dat. Stephen Colebourne, pracując nad projektami intensywnie wykorzystującymi daty, postanowił stworzyć alternatywę, która naprawiłaby wszystkie te problemy.

Według wywiadu na InfoQ (2014), Colebourne testował Joda-Time w projektach przemysłowych przez ponad rok przed pierwszym publicznym wydaniem. Pierwsza wersja ukazała się w 2004 roku i od razu przyciągnęła uwagę społeczności. Do 2010 roku biblioteka stała się standardową zależnością w większości projektów Java, w tym w takich frameworkach jak Spring i Hibernate. Sukces Joda-Time bezpośrednio wpłynął na specyfikację JSR-310 (Date and Time API), która została włączona do Javy 8 — przy czym autorem specyfikacji został ten sam Stephen Colebourne.

Wpływ na ekosystem Javy

Joda-Time nie tylko rozwiązała problem dat — zmieniła podejście do projektowania API w Javie. Koncepcja niemutowalnych obiektów wartości, zademonstrowana przez bibliotekę, została przyjęta jako standard w Javie 8 dla wszystkich nowych API. Co więcej, popularność Joda-Time pokazała Oracle, że społeczność nie godzi się na niskiej jakości standardowe biblioteki — po Joda-Time w Javie przeprojektowano API do pracy z plikami (NIO.2), czasem (java.time) i wartościami opcjonalnymi (Optional).

Kluczowe możliwości biblioteki Joda-Time

Joda-Time oferuje zestaw możliwości, który przed Javą 8 był niedostępny w standardowej bibliotece. Główne zalety obejmują wsparcie dla ponad 200 stref czasowych z automatycznym przetwarzaniem czasu letniego, bogate API formatowania z wzorcami i lokalizacjami, a także obliczanie okresów między datami w różnych jednostkach — latach, miesiącach, dniach, godzinach. Osobnej uwagi zasługuje system interwałów: Interval (odstęp między dwoma momentami), Period (różnica w jednostkach kalendarzowych) i Duration (dokładny czas trwania w milisekundach).

Formatowanie i parsowanie

Klasa DateTimeFormatter w Joda-Time zapewnia bezpieczne wątkowo formatowanie dat — w przeciwieństwie do java.text.SimpleDateFormat. Formatery można tworzyć przez wzorce (np. "yyyy-MM-dd HH:mm:ss") lub przez style (SHORT, MEDIUM, LONG, FULL) dla zlokalizowanego wyjścia. Biblioteka obsługuje również buforowanie formaterów, co przyspiesza działanie w aplikacjach o wysokim obciążeniu. Parsowanie dat z łańcuchów znaków odbywa się z kontrolą ścisłości — można zezwolić lub zabronić niepełnych lub nieprawidłowych dat.

Interwały i obliczenia

Jedną z mocnych stron Joda-Time jest praca z przedziałami czasowymi. Klasa Interval reprezentuje dokładny odcinek czasu między dwoma momentami (Instant) i obsługuje operacje przecięcia, połączenia i sprawdzania przynależności. Period, w przeciwieństwie do Interval, operuje jednostkami kalendarzowymi — na przykład różnica między 1 marca a 1 kwietnia wynosi dokładnie 1 miesiąc, chociaż pod względem długości może to być 28–31 dni. Duration natomiast reprezentuje dokładny czas trwania w milisekundach bez przypisania do kalendarza i nadaje się do pomiaru czasu wykonania operacji.

java
import org.joda.time.*;
import org.joda.time.format.*;

DateTime now = new DateTime();
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
String formatted = fmt.print(now);

DateTime nextWeek = now.plusWeeks(1);
Period period = new Period(now, nextWeek);
int days = period.getDays(); // dni = 7

Interval interval = new Interval(now, nextWeek);
boolean contains = interval.contains(now); // true

Porównanie Joda-Time i java.time

Pakiet java.time (JSR-310) został opracowany przez tego samego autora — Stephena Colebourne'a — i wchłonął najlepsze pomysły Joda-Time, uwzględniając dziesięć lat doświadczenia eksploatacyjnego. Oba API używają niemutowalnych klas, obsługują strefy czasowe i oferują bogaty zestaw operacji. Jednak java.time jest w pełni zintegrowany ze standardową biblioteką Javy, nie wymaga zewnętrznych zależności i używa bardziej spójnego systemu nazewnictwa: Instant zamiast ReadableInstant, LocalDate zamiast LocalDate (nazwa zachowana), ZonedDateTime zamiast DateTime.

CechaJoda-Timejava.time
Rok wydania20042014 (Java 8)
StatusUtrzymanie (maintenance)Aktywny rozwój
Podstawowa data/czasDateTimeZonedDateTime
Tylko dataLocalDateLocalDate
NiemutowalnośćTakTak
FormatowanieDateTimeFormatterDateTimeFormatter
Różnica datPeriod / DurationPeriod / Duration

Kluczowe różnice

java.time naprawia kilka decyzji architektonicznych Joda-Time. Po pierwsze, w java.time wyeliminowano zamieszanie między metodami zwracającymi null a brakującymi wartościami — zamiast tego używane są Optional. Po drugie, dodano wsparcie dla alternatywnych systemów kalendarzowych (japoński, tajski, islamski) poprzez interfejs Chronology. Po trzecie, java.time zawiera klasę Instant do pracy z momentami czasu w UTC bez przypisania do kalendarza — upraszcza to integrację z protokołami sieciowymi i bazami danych. Dla Androida zaleca się używanie java.time począwszy od API 26 (Android 8.0) lub przez desugaring dla starszych wersji.

Migracja z Joda-Time na java.time

Migracja z Joda-Time na java.time — to proces, który autorzy biblioteki starali się uczynić maksymalnie bezpiecznym i przewidywalnym. Większość klas ma bezpośrednie odpowiedniki: DateTime → ZonedDateTime, LocalDate → LocalDate (nazwa się pokrywa), LocalTime → LocalTime, DateTimeZone → ZoneId, Period → Period, Duration → Duration. Główne zmiany dotyczą sposobu tworzenia obiektów i nazw metod — na przykład, zamiast `now.toDate()` używa się `Date.from(instant)`, a `DateTime.now()` zastępuje się `ZonedDateTime.now()`.

Strategia migracji krok po kroku

Migrację zaleca się rozpocząć od izolacji Joda-Time w cienkiej warstwie abstrakcji — umożliwi to wymianę biblioteki etapami, bez wpływania na całą bazę kodu. Pierwszym krokiem zwykle zastępuje się pracę z LocalDate i LocalTime — te klasy mają najmniej różnic między bibliotekami. Drugim etapem migruje się DateTime (na ZonedDateTime) i strefy czasowe. W trzecim etapie zastępuje się Interval, Period i Duration — tutaj należy uważnie sprawdzić zachowanie z uwzględnieniem czasu letniego. Po zakończeniu migracji Joda-Time jest całkowicie usuwana z zależności projektu.

kotlin
// Joda-Time (przed migracją)
val dateTime = DateTime.now(DateTimeZone.forID("Europe/Moscow"))
val formatted = dateTime.toString("dd.MM.yyyy")
val plusDay = dateTime.plusDays(1)

// java.time (po migracji)
val zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Moscow"))
val formatted2 = zonedDateTime.format(
    DateTimeFormatter.ofPattern("dd.MM.yyyy")
)
val plusDay2 = zonedDateTime.plusDays(1)

Narzędzia do migracji

Istnieje kilka narzędzi ułatwiających przejście z Joda-Time na java.time. OpenRewrite (by Moderne) obsługuje automatyczną migrację przez przepis org.openrewrite.java.migrate.JodaTimeToJavaTime — zastępuje on klasy, metody i importy, zachowując logikę programu. Dla projektów Gradle wtyczka de.fayard.refreshVersions również zawiera reguły migracji. Ręcznie migrację najłatwiej przeprowadzić z IDEA: wtyczka Java Time Migration Assistant podświetla wywołania Joda-Time i proponuje odpowiednie zamienniki na java.time, co przyspiesza proces 2–3 razy w porównaniu z ręczną zamianą.

Przykłady kodu Joda-Time

Rozważmy praktyczne przykłady pracy z Joda-Time w aplikacjach Android. Biblioteka jest szczególnie przydatna do zadań formatowania dat według lokalnych standardów, obliczania wieku użytkownika, określania czasu trwania wydarzeń i obliczania interwałów między dwiema datami. Wszystkie przykłady używają niemutowalnych obiektów — każde wywołanie zwraca nową instancję, a oryginalny obiekt pozostaje niezmieniony.

kotlin
// Oblicz wiek użytkownika
val birthDate = LocalDate.parse("1990-05-15")
val today = LocalDate.now()
val age = Years.yearsBetween(birthDate, today).getYears()
// wiek == 36

// Formatuj z lokalizacją użytkownika
val dateTime = DateTime.now()
val formatter = DateTimeFormat.forStyle("MM").withLocale(Locale.getDefault())
val localized = formatter.print(dateTime)

Praca z interwałami

Interwały w Joda-Time umożliwiają efektywne rozwiązywanie zadań sprawdzania przecięcia przedziałów czasowych, obliczania nakładek i znajdowania najbliższego zdarzenia. Na przykład przy opracowywaniu aplikacji kalendarza można sprawdzić, czy nowe wydarzenie nakłada się na już istniejące. Klasa Interval obsługuje operacje contains, overlaps, gap i abuts — ostatnia pokazuje, czy interwały stykają się granicami. Do pomiaru czasu trwania między dwoma momentami używana jest Duration z dokładnością do milisekund.

java
// Sprawdź nakładanie się interwałów
Interval meeting1 = new Interval(
    new DateTime(2026, 7, 21, 10, 0),
    new DateTime(2026, 7, 21, 11, 0)
);
Interval meeting2 = new Interval(
    new DateTime(2026, 7, 21, 10, 30),
    new DateTime(2026, 7, 21, 11, 30)
);

boolean overlaps = meeting1.overlaps(meeting2); // true
Duration gap = meeting1.gap(meeting2); // null (brak przerwy)

Często zadawane pytania

Czym jest Joda-Time i do czego służy?

Joda-Time — biblioteka do pracy z datami i czasem w Javie, stworzona przed wydaniem Javy 8. Naprawiała wady java.util.Date i java.util.Calendar: mutowalność, numerację miesięcy od 0, brak pełnego wsparcia stref czasowych i niebezpieczne wątkowo formatowanie.

Czym różni się Joda-Time od java.time?

Java.time (JSR-310) — następca Joda-Time, opracowany przez tego samego autora. Główne różnice: java.time jest wbudowany w standardową bibliotekę Javy 8+, używa bardziej spójnego systemu nazewnictwa, obsługuje alternatywne systemy kalendarzowe i zawiera klasę Instant do pracy z czasem UTC.

Czy warto używać Joda-Time w nowych projektach?

Nie, dla nowych projektów zaleca się używanie java.time. Joda-Time znajduje się w trybie utrzymania od 2014 roku i nie otrzymuje już nowych funkcji. Dla Androida z API 26+ java.time jest dostępny natywnie, a dla starszych wersji używany jest desugaring — mechanizm umożliwiający używanie java.time na urządzeniach z API 19+.

Jak migrować kod z Joda-Time na java.time?

Migracja odbywa się etapami: wyizoluj Joda-Time w abstrakcjach, zastąp najpierw LocalDate i LocalTime, następnie DateTime → ZonedDateTime, a na ostatnim etapie — Period, Duration i Interval. Narzędzie OpenRewrite obsługuje automatyczną migrację przez przepis JodaTimeToJavaTime, co przyspiesza proces 2–3 razy.

Które klasy Joda-Time odpowiadają java.time?

DateTime → ZonedDateTime, LocalDate → LocalDate (pokrywa się), LocalTime → LocalTime, LocalDateTime → LocalDateTime, DateTimeZone → ZoneId, Interval → brak bezpośredniego odpowiednika (używana jest kombinacja Instant + Duration), Period → Period, Duration → Duration. Nazwy metod są również zbliżone: plusDays, minusMonths, withZone są dostępne w obu bibliotekach.

Podsumowanie

  • Joda-Time — biblioteka dat i czasu dla Javy, która stała się standardem przed wydaniem Javy 8 i miała bezpośredni wpływ na specyfikację JSR-310
  • Immutable-design — wszystkie klasy Joda-Time są niemutowalne, co gwarantuje bezpieczeństwo wątkowe i zapobiega przypadkowym mutacjom obiektów
  • Kluczowe klasy — DateTime, LocalDate, LocalTime, LocalDateTime, Period, Duration i Interval pokrywają wszystkie scenariusze pracy z datami i czasem
  • Wsparcie stref czasowych — wbudowana baza ponad 200 stref z automatycznym przetwarzaniem przejścia na czas letni i aktualizacjami
  • Migracja na java.time — zalecana dla wszystkich projektów; odbywa się etapowo, z użyciem narzędzi OpenRewrite i wbudowanych narzędzi IDE
  • Zgodność z Androidem — Joda-Time działa od API 1, ale dla API 26+ preferowany jest java.time, dostępny przez desugaring na starszych wersjach
  • Znaczenie historyczne — Joda-Time zmieniła podejście do projektowania API w Javie i pokazała społeczności zalety niemutowalnych obiektów wartości

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również