Joda-Time — o bibliotecă pentru lucrul cu date și timp în Java, creată de Stephen Colebourne ca alternativă la java.util.Date și java.util.Calendar incomode. Înainte de lansarea Java 8, această bibliotecă era standardul de facto pentru lucrul cu date în dezvoltarea industrială, inclusiv în aplicațiile Android. Potrivit Oracle Java Magazine (2023), peste 60% dintre proiecte au migrat de la Joda-Time la java.time în termen de doi ani de la lansarea Android API 26.
Principalele puncte
Joda-Time — este o bibliotecă open-source (Apache 2.0) care oferă o înlocuire de calitate pentru clasele java.util.Date și java.util.Calendar în limbajul Java. Proiectul a fost fondat de Stephen Colebourne în 2004 ca răspuns la numeroasele probleme ale API-urilor standard de lucru cu datele, inclusiv mutabilitatea, complexitatea formatării și suportul limitat al fusurilor orare. Biblioteca a câștigat o largă răspândire în comunitatea Java și a fost folosită de mii de proiecte, inclusiv sisteme enterprise mari și aplicații Android, unde instrumentele încorporate de lucru cu datele erau deosebit de incomode. De la lansarea Java 8 în 2014 și apariția pachetului java.time (JSR-310), biblioteca a fost trecută în modul de întreținere — funcții noi nu se adaugă, iar funcționalitatea existentă este complet acoperită de noul API.
Joda-Time este construită pe principiul imutabilității: fiecare obiect de dată sau oră după creare nu poate fi modificat. Orice operațiune — adăugarea unei zile, schimbarea lunii, setarea fusului orar — returnează un obiect nou, lăsând originalul neschimbat. Această abordare elimină complet clasa de erori legate de modificarea neintenționată a obiectelor, care erau caracteristice pentru java.util.Date și java.util.Calendar mutabile. Designul imutabil face de asemenea biblioteca sigură pentru fire de execuție fără sincronizare suplimentară.
Biblioteca oferă mai multe clase principale pentru diferite scenarii: DateTime — dată și oră completă cu fus orar, LocalDate — doar dată fără oră, LocalTime — doar oră fără dată, LocalDateTime — dată și oră fără legătură cu fusul. În plus, sunt incluse clase pentru lucrul cu intervale (Interval), perioade (Period) și durate (Duration), care permit calcularea diferenței între două momente de timp în diferite unități de măsură. Fiecare clasă implementează interfața ReadableInstant sau ReadablePartial pentru procesare uniformă.
Problema API-urilor standard de date în Java era cunoscută încă de la începutul platformei. Clasele java.util.Date și java.util.Calendar aveau defecte fundamentale: lunile erau numerotate de la 0, Date reprezenta simultan și data, și ora, Calendar era mutabil și necesita configurare complexă. Formatarea prin SimpleDateFormat nu era sigură pentru fire — în aplicațiile multi-thread ducea la parsarea incorectă a datelor. Stephen Colebourne, lucrând la proiecte cu utilizare intensivă a datelor, a decis să creeze o alternativă care să rezolve toate aceste probleme.
Potrivit interviului pe InfoQ (2014), Colebourne a testat Joda-Time în proiecte industriale mai mult de un an înainte de prima lansare publică. Prima versiune a apărut în 2004 și a atras imediat atenția comunității. Până în 2010, biblioteca a devenit o dependență standard în majoritatea proiectelor Java, inclusiv în framework-uri precum Spring și Hibernate. Succesul Joda-Time a influențat direct specificația JSR-310 (Date and Time API), care a fost inclusă în Java 8 — iar autorul specificației a fost același Stephen Colebourne.
Joda-Time nu doar a rezolvat problema datelor — a schimbat abordarea proiectării API-urilor în Java. Conceptul de obiecte-valoare imutabile, demonstrat de bibliotecă, a fost adoptat ca standard în Java 8 pentru toate API-urile noi. Mai mult, popularitatea Joda-Time a arătat Oracle că comunitatea nu este dispusă să tolereze biblioteci standard de calitate slabă — după Joda-Time în Java au fost reproiectate API-urile pentru lucrul cu fișiere (NIO.2), timp (java.time) și valori opționale (Optional).
Joda-Time oferă un set de caracteristici care înainte de Java 8 nu era disponibil în biblioteca standard. Principalele avantaje includ suport pentru peste 200 de fusuri orare cu procesare automată a orei de vară, un API bogat de formatare cu modele și localizări, precum și calcularea perioadelor între date în diferite unități — ani, luni, zile, ore. O atenție deosebită merită sistemul de intervale: Interval (interval între două momente), Period (diferență în unități calendaristice) și Duration (durată exactă în milisecunde).
Clasa DateTimeFormatter în Joda-Time oferă formatare sigură pentru fire a datelor — spre deosebire de java.text.SimpleDateFormat. Formatoarele pot fi create prin modele (de exemplu, "yyyy-MM-dd HH:mm:ss") sau prin stiluri (SHORT, MEDIUM, LONG, FULL) pentru ieșire localizată. Biblioteca suportă de asemenea stocarea în cache a formatoarelor, ceea ce accelerează lucrul în aplicațiile cu sarcină mare. Parsarea datelor din șiruri se face cu control de rigurozitate — se pot permite sau interzice date incomplete sau incorecte.
Unul dintre punctele forte ale Joda-Time este lucrul cu intervalele de timp. Clasa Interval reprezintă un segment temporal exact între două momente (Instant) și suportă operații de intersecție, unire și verificare a apartenenței. Period, spre deosebire de Interval, operează cu unități calendaristice — de exemplu, diferența între 1 martie și 1 aprilie este exact 1 lună, deși ca durată poate fi 28–31 de zile. Duration reprezintă durata exactă în milisecunde fără legătură cu calendarul și este potrivită pentru măsurarea timpului de execuție a operațiilor.
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(); // zile = 7
Interval interval = new Interval(now, nextWeek);
boolean contains = interval.contains(now); // adevărat
Pachetul java.time (JSR-310) a fost dezvoltat de același autor — Stephen Colebourne — și a absorbit cele mai bune idei ale Joda-Time, ținând cont de zece ani de experiență operațională. Ambele API-uri folosesc clase imutabile, suportă fusuri orare și oferă un set bogat de operații. Cu toate acestea, java.time este complet integrat în biblioteca standard Java, nu necesită dependențe externe și folosește un sistem de denumire mai coerent: Instant în loc de ReadableInstant, LocalDate în loc de LocalDate (numele păstrat), ZonedDateTime în loc de DateTime.
| Caracteristică | Joda-Time | java.time |
|---|---|---|
| Anul lansării | 2004 | 2014 (Java 8) |
| Status | Întreținere (maintenance) | Dezvoltare activă |
| Dată/oră de bază | DateTime | ZonedDateTime |
| Doar dată | LocalDate | LocalDate |
| Imutabilitate | Da | Da |
| Formatare | DateTimeFormatter | DateTimeFormatter |
| Diferența datelor | Period / Duration | Period / Duration |
java.time corectează câteva decizii arhitecturale ale Joda-Time. În primul rând, în java.time a fost eliminată confuzia între metodele care returnează null și valorile lipsă — în schimb sunt folosite Optional. În al doilea rând, a fost adăugat suportul pentru sisteme calendaristice alternative (japonez, thailandez, islamic) prin interfața Chronology. În al treilea rând, java.time include clasa Instant pentru lucrul cu momente de timp în UTC fără legătură cu calendarul — aceasta simplifică integrarea cu protocoalele de rețea și bazele de date. Pentru Android se recomandă utilizarea java.time începând cu API 26 (Android 8.0) sau prin desugaring pentru versiunile mai vechi.
Migrarea de la Joda-Time la java.time — un proces pe care autorii bibliotecii au încercat să îl facă cât mai sigur și previzibil. Majoritatea claselor au analogii directe: DateTime → ZonedDateTime, LocalDate → LocalDate (denumirea coincide), LocalTime → LocalTime, DateTimeZone → ZoneId, Period → Period, Duration → Duration. Principalele modificări privesc modul de creare a obiectelor și denumirile metodelor — de exemplu, în loc de `now.toDate()` se folosește `Date.from(instant)`, iar `DateTime.now()` este înlocuit cu `ZonedDateTime.now()`.
Se recomandă începerea migrării prin izolarea Joda-Time într-un strat subțire de abstractizare — aceasta va permite înlocuirea bibliotecii pe etape, fără a afecta întreaga bază de cod. Primul pas este de obicei înlocuirea lucrului cu LocalDate și LocalTime — aceste clase au cele mai puține diferențe între biblioteci. În a doua etapă se migrează DateTime (la ZonedDateTime) și fusurile orare. În a treia etapă se înlocuiesc Interval, Period și Duration — aici trebuie verificat cu atenție comportamentul ținând cont de ora de vară. După finalizarea migrării, Joda-Time este eliminată complet din dependențele proiectului.
// Joda-Time (înainte de migrare)
val dateTime = DateTime.now(DateTimeZone.forID("Europe/Moscow"))
val formatted = dateTime.toString("dd.MM.yyyy")
val plusDay = dateTime.plusDays(1)
// java.time (după migrare)
val zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Moscow"))
val formatted2 = zonedDateTime.format(
DateTimeFormatter.ofPattern("dd.MM.yyyy")
)
val plusDay2 = zonedDateTime.plusDays(1)
Există câteva utilitare care simplifică tranziția de la Joda-Time la java.time. OpenRewrite (by Moderne) suportă migrarea automată prin rețeta org.openrewrite.java.migrate.JodaTimeToJavaTime — înlocuiește clasele, metodele și importurile, păstrând logica programului. Pentru proiectele Gradle, pluginul de.fayard.refreshVersions include de asemenea reguli de migrare. Manual, migrarea se realizează cel mai ușor cu IDEA: pluginul Java Time Migration Assistant evidențiază apelurile Joda-Time și propune înlocuiri corespunzătoare în java.time, ceea ce accelerează procesul de 2–3 ori comparativ cu înlocuirea manuală.
Să examinăm exemple practice de lucru cu Joda-Time în aplicațiile Android. Biblioteca este deosebit de utilă pentru sarcinile de formatare a datelor conform standardelor locale, calcularea vârstei utilizatorului, determinarea duratei evenimentelor și calcularea intervalelor între două date. Toate exemplele folosesc obiecte imutabile — fiecare apel returnează o nouă instanță, iar obiectul original rămâne neschimbat.
// Calculează vârsta utilizatorului
val birthDate = LocalDate.parse("1990-05-15")
val today = LocalDate.now()
val age = Years.yearsBetween(birthDate, today).getYears()
// vârstă == 36
// Formatează cu locale-ul utilizatorului
val dateTime = DateTime.now()
val formatter = DateTimeFormat.forStyle("MM").withLocale(Locale.getDefault())
val localized = formatter.print(dateTime)
Intervalele în Joda-Time permit rezolvarea eficientă a sarcinilor de verificare a intersectării segmentelor temporale, calcularea suprapunerilor și găsirea celui mai apropiat eveniment. De exemplu, la dezvoltarea unei aplicații de calendar se poate verifica dacă noul eveniment se intersectează cu cele existente. Clasa Interval suportă operațiile contains, overlaps, gap și abuts — ultima arată dacă intervalele se ating la margini. Pentru măsurarea duratei între două momente se folosește Duration cu precizie de milisecunde.
// Verifică suprapunerea intervalelor
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); // adevărat
Duration gap = meeting1.gap(meeting2); // null (fără gol)
Întrebări frecvente
Joda-Time — o bibliotecă pentru lucrul cu date și timp în Java, creată înainte de lansarea Java 8. Ea corecta deficiențele java.util.Date și java.util.Calendar: mutabilitatea, numerotarea lunilor de la 0, lipsa suportului complet pentru fusuri orare și formatarea nesigură pentru fire.
Java.time (JSR-310) — succesorul Joda-Time, dezvoltat de același autor. Principalele diferențe: java.time este încorporat în biblioteca standard Java 8+, folosește un sistem de denumire mai coerent, suportă sisteme calendaristice alternative și include clasa Instant pentru lucrul cu timpul UTC.
Nu, pentru proiecte noi se recomandă utilizarea java.time. Joda-Time se află în modul de întreținere din 2014 și nu mai primește funcții noi. Pentru Android cu API 26+, java.time este disponibil nativ, iar pentru versiunile mai vechi se folosește desugaring — un mecanism care permite utilizarea java.time pe dispozitive cu API 19+.
Migrarea se realizează în etape: izolați Joda-Time în abstracții, înlocuiți mai întâi LocalDate și LocalTime, apoi DateTime → ZonedDateTime, și în ultima etapă — Period, Duration și Interval. Instrumentul OpenRewrite suportă migrarea automată prin rețeta JodaTimeToJavaTime, ceea ce accelerează procesul de 2–3 ori.
DateTime → ZonedDateTime, LocalDate → LocalDate (coincide), LocalTime → LocalTime, LocalDateTime → LocalDateTime, DateTimeZone → ZoneId, Interval → nu are analog direct (se folosește combinația Instant + Duration), Period → Period, Duration → Duration. Numele metodelor sunt de asemenea apropiate: plusDays, minusMonths, withZone sunt disponibile în ambele biblioteci.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și