Joda-Time è una libreria per lavorare con date e orari in Java, creata da Stephen Colebourne come alternativa ai complessi java.util.Date e java.util.Calendar. Prima del rilascio di Java 8, questa libreria era lo standard de facto per la gestione delle date nello sviluppo industriale, incluse le applicazioni Android. Secondo Oracle Java Magazine (2023), oltre il 60% dei progetti è migrato da Joda-Time a java.time entro due anni dal rilascio di Android API 26.
Punti chiave
Joda-Time è una libreria open source (Apache 2.0) che fornisce un’alternativa di qualità alle classi java.util.Date e java.util.Calendar in Java. Il progetto è stato fondato da Stephen Colebourne nel 2004 in risposta ai numerosi problemi delle API standard di data e ora, tra cui mutabilità, complessità di formattazione e supporto limitato dei fusi orari. La libreria è stata ampiamente adottata dalla comunità Java ed è stata utilizzata da migliaia di progetti, inclusi grandi sistemi enterprise e applicazioni Android, dove gli strumenti integrati per la gestione delle date erano particolarmente scomodi. Dal rilascio di Java 8 nel 2014 e dall’introduzione del pacchetto java.time (JSR-310), la libreria è stata messa in modalità di manutenzione — non vengono aggiunte nuove funzionalità e le funzionalità esistenti sono completamente coperte dalla nuova API.
Joda-Time è costruita sul principio dell’immutabilità: ogni oggetto data o ora non può essere modificato dopo la creazione. Qualsiasi operazione — aggiungere un giorno, cambiare un mese, impostare un fuso orario — restituisce un nuovo oggetto, lasciando l’originale invariato. Questo approccio elimina completamente la classe di errori associati alla modifica involontaria degli oggetti che caratterizzavano i mutabili java.util.Date e java.util.Calendar. Il design immutabile rende anche la libreria thread-safe senza sincronizzazione aggiuntiva.
La libreria fornisce diverse classi principali per vari scenari: DateTime — data e ora complete con fuso orario, LocalDate — solo data senza ora, LocalTime — solo ora senza data, LocalDateTime — data e ora senza vincolo di fuso orario. Inoltre, sono incluse classi per lavorare con intervalli (Interval), periodi (Period) e durate (Duration), che permettono di calcolare la differenza tra due istanti in varie unità di misura. Ogni classe implementa l’interfaccia ReadableInstant o ReadablePartial per una gestione uniforme.
Il problema delle API standard di data in Java era noto fin dagli inizi della piattaforma. Le classi java.util.Date e java.util.Calendar avevano difetti fondamentali: i mesi erano numerati a partire da 0, Date rappresentava simultaneamente data e ora, Calendar era mutabile e richiedeva una configurazione complessa. La formattazione tramite SimpleDateFormat non era thread-safe — nelle applicazioni multithread ciò portava a un’analisi errata delle date. Stephen Colebourne, lavorando su progetti con uso intensivo di date, decise di creare un’alternativa che risolvesse tutti questi problemi.
Secondo un’intervista su InfoQ (2014), Colebourne ha testato Joda-Time in progetti di produzione per oltre un anno prima del primo rilascio pubblico. La prima versione è stata rilasciata nel 2004 e ha immediatamente attirato l’attenzione della comunità. Entro il 2010, la libreria era diventata una dipendenza standard nella maggior parte dei progetti Java, inclusi framework come Spring e Hibernate. Il successo di Joda-Time ha influenzato direttamente la specifica JSR-310 (Date and Time API), che è stata inclusa in Java 8 — con lo stesso Stephen Colebourne come leader della specifica.
Joda-Time non ha solo risolto il problema delle date — ha cambiato l’approccio alla progettazione delle API in Java. Il concetto di oggetti valore immutabili, dimostrato dalla libreria, è stato adottato come standard in Java 8 per tutte le nuove API. Inoltre, la popolarità di Joda-Time ha mostrato a Oracle che la comunità non era disposta a tollerare librerie standard di bassa qualità — dopo Joda-Time, le API Java per la gestione dei file (NIO.2), il tempo (java.time) e i valori opzionali (Optional) sono state riprogettate.
Joda-Time fornisce un insieme di funzionalità che non erano disponibili nella libreria standard prima di Java 8. I principali vantaggi includono supporto per oltre 200 fusi orari con gestione automatica dell’ora legale, una ricca API di formattazione con pattern e impostazioni locali, oltre al calcolo dei periodi tra date in varie unità — anni, mesi, giorni, ore. Degno di nota è il sistema degli intervalli: Interval (un intervallo tra due istanti), Period (differenza in unità calendariali) e Duration (durata esatta in millisecondi).
La classe DateTimeFormatter in Joda-Time fornisce una formattazione delle date thread-safe — a differenza di java.text.SimpleDateFormat. I formattatori possono essere creati tramite pattern (ad esempio, “yyyy-MM-dd HH:mm:ss”) o tramite stili (SHORT, MEDIUM, LONG, FULL) per un output localizzato. La libreria supporta anche la memorizzazione nella cache dei formattatori, che accelera le prestazioni nelle applicazioni ad alto carico. L’analisi delle date dalle stringhe viene eseguita con controllo di rigore — è possibile consentire o rifiutare date incomplete o errate.
Uno dei punti di forza di Joda-Time è il lavoro con gli intervalli di tempo. La classe Interval rappresenta un periodo di tempo esatto tra due istanti e supporta le operazioni di intersezione, unione e verifica di contenimento. Period, a differenza di Interval, opera in unità calendariali — ad esempio, la differenza tra il 1° marzo e il 1° aprile è esattamente 1 mese, sebbene in durata possano essere 28–31 giorni. Duration, invece, rappresenta una durata esatta in millisecondi senza vincoli calendariali ed è adatta per misurare il tempo di esecuzione delle operazioni.
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(); // giorni = 7
Interval interval = new Interval(now, nextWeek);
boolean contains = interval.contains(now); // vero
Il pacchetto java.time (JSR-310) è stato sviluppato dallo stesso autore — Stephen Colebourne — e ha incorporato le migliori idee di Joda-Time con dieci anni di esperienza operativa. Entrambe le API utilizzano classi immutabili, supportano i fusi orari e forniscono un ricco insieme di operazioni. Tuttavia, java.time è completamente integrato nella libreria standard di Java, non richiede dipendenze esterne e utilizza un sistema di denominazione più coerente: Instant invece di ReadableInstant, LocalDate invece di LocalDate (nome preservato), ZonedDateTime invece di DateTime.
| Caratteristica | Joda-Time | java.time |
|---|---|---|
| Anno di rilascio | 2004 | 2014 (Java 8) |
| Stato | Manutenzione | Sviluppo attivo |
| Data/ora base | DateTime | ZonedDateTime |
| Solo data | LocalDate | LocalDate |
| Immutabilità | Sì | Sì |
| Formattazione | DateTimeFormatter | DateTimeFormatter |
| Differenza date | Period / Duration | Period / Duration |
java.time corregge diverse decisioni architetturali di Joda-Time. In primo luogo, java.time elimina la confusione tra i metodi che restituiscono null e i valori mancanti — utilizzando Optional al posto. In secondo luogo, è stato aggiunto il supporto per sistemi calendariali alternativi (giapponese, tailandese, islamico) tramite l’interfaccia Chronology. In terzo luogo, java.time include la classe Instant per lavorare con istanti UTC senza vincoli calendariali — questo semplifica l’integrazione con i protocolli di rete e i database. Per Android, si raccomanda di utilizzare java.time a partire dall’API 26 (Android 8.0) o tramite desugaring per le versioni precedenti.
La migrazione da Joda-Time a java.time è un processo che gli autori della libreria hanno cercato di rendere il più sicuro e prevedibile possibile. La maggior parte delle classi ha corrispondenti diretti: DateTime → ZonedDateTime, LocalDate → LocalDate (nome coincide), LocalTime → LocalTime, DateTimeZone → ZoneId, Period → Period, Duration → Duration. Le modifiche principali riguardano il modo di creare gli oggetti e i nomi dei metodi — ad esempio, invece di `now.toDate()`, si usa `Date.from(instant)`, e `DateTime.now()` viene sostituito con `ZonedDateTime.now()`.
Si raccomanda di iniziare la migrazione isolando Joda-Time in un sottile strato di astrazione — ciò consente di sostituire la libreria in modo incrementale senza toccare l’intera base di codice. Il primo passo è solitamente sostituire il lavoro con LocalDate e LocalTime — queste classi presentano il minor numero di differenze tra le librerie. La seconda fase migra DateTime (in ZonedDateTime) e i fusi orari. La terza fase sostituisce Interval, Period e Duration — qui bisogna verificare attentamente il comportamento dell’ora legale. Dopo aver completato la migrazione, Joda-Time viene completamente rimosso dalle dipendenze del progetto.
// Joda-Time (prima della migrazione)
val dateTime = DateTime.now(DateTimeZone.forID("Europe/Moscow"))
val formatted = dateTime.toString("dd.MM.yyyy")
val plusDay = dateTime.plusDays(1)
// java.time (dopo la migrazione)
val zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Moscow"))
val formatted2 = zonedDateTime.format(
DateTimeFormatter.ofPattern("dd.MM.yyyy")
)
val plusDay2 = zonedDateTime.plusDays(1)
Esistono diverse utilità che semplificano la transizione da Joda-Time a java.time. OpenRewrite (di Moderne) supporta la migrazione automatica attraverso la ricetta org.openrewrite.java.migrate.JodaTimeToJavaTime — sostituisce classi, metodi e import preservando la logica del programma. Per i progetti Gradle, il plugin de.fayard.refreshVersions include anche regole di migrazione. Manualmente, la migrazione è più facile da eseguire con IDEA: il plugin Java Time Migration Assistant evidenzia le chiamate Joda-Time e suggerisce le sostituzioni corrispondenti in java.time, accelerando il processo di 2–3 volte rispetto alla sostituzione manuale.
Vediamo esempi pratici di lavoro con Joda-Time nelle applicazioni Android. La libreria è particolarmente utile per formattare le date secondo gli standard locali, calcolare l’età dell’utente, determinare la durata degli eventi e calcolare intervalli tra due date. Tutti gli esempi utilizzano oggetti immutabili — ogni chiamata restituisce una nuova istanza, mentre l’oggetto originale rimane invariato.
// Calcola età utente
val birthDate = LocalDate.parse("1990-05-15")
val today = LocalDate.now()
val age = Years.yearsBetween(birthDate, today).getYears()
// età == 36
// Formatta con le impostazioni locali dell’utente
val dateTime = DateTime.now()
val formatter = DateTimeFormat.forStyle("MM").withLocale(Locale.getDefault())
val localized = formatter.print(dateTime)
Gli intervalli in Joda-Time consentono di risolvere efficacemente attività come la verifica della sovrapposizione di intervalli di tempo, il calcolo delle intersezioni e la ricerca dell’evento più vicino. Ad esempio, durante lo sviluppo di un’applicazione calendario, è possibile verificare se un nuovo evento si sovrappone a quelli esistenti. La classe Interval supporta le operazioni contains, overlaps, gap e abuts — quest’ultima mostra se gli intervalli si toccano ai loro confini. Duration viene utilizzata per misurare la lunghezza tra due istanti con precisione al millisecondo.
// Verifica sovrapposizione intervalli
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); // vero
Duration gap = meeting1.gap(meeting2); // null (nessun intervallo)
Domande frequenti
Joda-Time è una libreria per lavorare con date e orari in Java, creata prima del rilascio di Java 8. Ha corretto le carenze di java.util.Date e java.util.Calendar: mutabilità, numerazione dei mesi da 0, mancanza di supporto completo dei fusi orari e formattazione non thread-safe.
Java.time (JSR-310) è il successore di Joda-Time, sviluppato dallo stesso autore. Le principali differenze: java.time è integrato nella libreria standard Java 8+, utilizza un sistema di denominazione più coerente, supporta sistemi calendariali alternativi e include la classe Instant per lavorare con il tempo UTC.
No, per i nuovi progetti si raccomanda di utilizzare java.time. Joda-Time è in modalità manutenzione dal 2014 e non riceve più nuove funzionalità. Per Android con API 26+, java.time è disponibile nativamente, e per le versioni precedenti viene utilizzato il desugaring — un meccanismo che consente di utilizzare java.time su dispositivi con API 19+.
La migrazione viene eseguita passo dopo passo: isola Joda-Time in astrazioni, sostituisci prima LocalDate e LocalTime, poi DateTime → ZonedDateTime, e infine Period, Duration e Interval. Lo strumento OpenRewrite supporta la migrazione automatica attraverso la ricetta JodaTimeToJavaTime, accelerando il processo di 2–3 volte.
DateTime → ZonedDateTime, LocalDate → LocalDate (coincide), LocalTime → LocalTime, LocalDateTime → LocalDateTime, DateTimeZone → ZoneId, Interval → nessun equivalente diretto (si usa una combinazione di Instant + Duration), Period → Period, Duration → Duration. Anche i nomi dei metodi sono simili: plusDays, minusMonths, withZone sono disponibili in entrambe le librerie.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche