ThreeTenABP: cos'è, libreria java.time per Android

Autore: IT Sectr Pubblicato: 2026-07-14 Tempo di lettura: 11 min

ThreeTenABP è una libreria adattatrice per Android che fornisce l'API java.time (pacchetto org.threeten.bp) su dispositivi con Android inferiore all'8 (API < 26). Secondo le specifiche di Jake Wharton (GitHub, 2023), la libreria è un wrapper attorno al progetto ThreeTen-Backport, adattato per Android con ottimizzazione delle risorse e supporto tzdata tramite AssetManager.

Punti chiave

  • ThreeTenABP è un adattatore Android per ThreeTen-Backport, che fornisce java.time su API < 26.
  • Aggiunto tramite Gradle: implementation "com.jakewharton.threetenabp:threetenabp:1.4.x".
  • Richiede inizializzazione in Application.onCreate() tramite AndroidThreeTen.init(this).
  • Utilizza il pacchetto org.threeten.bp invece di java.time — l'API è praticamente identica.
  • Con l'avvento del desugaring (AGP 4.0+), ThreeTenABP è diventato opzionale e viene utilizzato per progetti legacy.

Cos'è ThreeTenABP?

ThreeTenABP (ThreeTen Android Backport) è una libreria creata da Jake Wharton per utilizzare l'API data/ora di Java 8 su versioni precedenti di Android. È un adattatore per il progetto ThreeTen-Backport, che porta java.time (JSR-310) su Java 7 e Android API < 26.

Il problema principale che la libreria risolve: Android prima della versione 8 (API 26) non includeva java.time nella distribuzione standard. Gli sviluppatori erano costretti a usare java.util.Date/Calendar o aggiungere Joda-Time. ThreeTenABP fornisce la stessa API moderna di java.time integrato, ma attraverso il pacchetto org.threeten.bp.

Secondo il repository GitHub (2023), la libreria è ottimizzata per Android: i dati tzdata (IANA Time Zone Database) sono memorizzati in assets e caricati tramite AssetManager, invece del classpath come sul desktop. Questo riduce la dimensione dell'APK e accelera il caricamento.

L'ultima versione stabile è la 1.4.0 (agosto 2021). La libreria è in modalità manutenzione, poiché con l'adozione diffusa del desugaring, la necessità diminuisce, ma rimane rilevante per progetti con API minima < 26.

Perché serve un backport di java.time?

Prima dell'introduzione di java.time in Java 8 (2014), gli sviluppatori usavano java.util.Date e java.util.Calendar. Queste classi hanno seri inconvenienti: Date è mutabile, Calendar usa costanti non intuitive (Calendar.JANUARY = 0), entrambe le classi non sono thread-safe e sono soggette a errori quando si lavora con i fusi orari.

Joda-Time era lo standard de facto prima di Java 8, ma il suo creatore Stephen Colebourne ha progettato java.time come sostituto ufficiale, basandosi sull'esperienza di Joda-Time e affrontandone le carenze. Il pacchetto java.time è stato incluso in JDK 8, ma Android non lo ha ricevuto fino all'API 26.

ThreeTen-Backport è un porting di java.time su Java 7, creato dallo stesso autore (Stephen Colebourne). Include tutte le classi principali: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. ThreeTenABP adatta questo porting per Android, aggiungendo l'inizializzazione tramite AssetsManager e l'ottimizzazione per dispositivi mobili.

Pertanto, ThreeTenABP consente di utilizzare l'API moderna di data/ora su dispositivi con Android 4.0+ (API 14+) senza attendere un aggiornamento del sistema operativo.

Aggiungere ThreeTenABP a un progetto Android

L'aggiunta avviene in due passaggi: aggiungere la dipendenza in build.gradle (livello app) e inizializzare nella classe Application. Importante: ThreeTenABP richiede compileSdk di almeno 21 e versione Gradle di almeno 4.0.

La dipendenza viene aggiunta nella sezione dependencies: implementation "com.jakewharton.threetenabp:threetenabp:1.4.0". Dal rilascio della 1.4.0, la libreria non è stata aggiornata, poiché è stabile e copre tutti i casi necessari.

Secondo la documentazione ufficiale, la libreria include tzdata in assets. Se l'app ha già una cartella assets con altri file, ThreeTenABP coesiste correttamente con essi. La dimensione di tzdata è di circa 200 KB compresso.

groovy
// build.gradle (livello app)
android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
}

Inizializzazione di ThreeTenABP

Prima di utilizzare qualsiasi classe da org.threeten.bp, la libreria deve essere inizializzata. L'inizializzazione viene eseguita una volta in Application.onCreate() chiamando AndroidThreeTen.init(this).

L'inizializzazione carica i dati tzdata da assets e configura l'orologio di sistema. Senza chiamare init(), i metodi now() lanceranno un'eccezione IllegalStateException con un messaggio che la libreria non è inizializzata.

Per i test, è possibile utilizzare AndroidThreeTen.init(applicationContext, zoneId) — un overload con specifica esplicita del fuso orario. Ciò è utile per un comportamento prevedibile nei test. Se è necessaria solo l'inizializzazione di base senza tzdata, utilizzare AndroidThreeTen.initWithoutFiles(context).

kotlin
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        AndroidThreeTen.init(this)
    }
}

// Utilizzo dopo l'inizializzazione
val today = LocalDate.now()
val now = LocalDateTime.now()

Quali classi sono disponibili?

ThreeTenABP fornisce tutte le classi principali di java.time, ma nel pacchetto org.threeten.bp. L'API è praticamente identica a java.time originale, facilitando la migrazione quando si passa a API 26+.

Classi principali:

  • LocalDate — data senza ora e fuso orario
  • LocalTime — ora senza data e fuso orario
  • LocalDateTime — data e ora senza fuso orario
  • ZonedDateTime — data e ora con fuso orario
  • OffsetDateTime — data e ora con offset fisso
  • OffsetTime — ora con offset fisso
  • Instant — momento nel tempo in UTC
  • Duration — durata basata sul tempo
  • Period — durata basata sulla data
  • DateTimeFormatter — formattazione e analisi
  • ZoneId / ZoneOffset — fusi orari

Sono supportate anche le classi ausiliarie: Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. I fusi orari sono forniti con la libreria (IANA tzdata). La versione tzdata in ThreeTenABP 1.4.0 corrisponde a 2021a.

ThreeTenABP vs desugaring

A partire da Android Gradle Plugin 4.0 (2020) e desugar_jdk_libs, gli sviluppatori hanno ottenuto la possibilità di utilizzare java.time su tutte le versioni di Android tramite coreLibraryDesugaring. Il desugaring trasforma il bytecode in modo che le chiamate java.time funzionino su API precedenti senza librerie aggiuntive.

Vantaggi del desugaring: utilizza il pacchetto java.time originale (non org.threeten.bp), non richiede inizializzazione, integrazione completa con Android Studio. Svantaggi: richiede AGP 4.0+, aumenta il tempo di compilazione, la dimensione dell'APK può aumentare di 2-3 MB.

ThreeTenABP rimane la scelta migliore per progetti legacy che non possono aggiornare AGP a 4.0+, o dove la dimensione dell'APK è critica. ThreeTenABP è anche più facile da configurare — solo una dipendenza e una riga di inizializzazione. Secondo Stack Overflow (2024), circa il 30% dei progetti con minSdk < 26 utilizza ancora ThreeTenABP invece del desugaring.

Esempi di utilizzo

Il primo esempio mostra il lavoro con le date utilizzando ThreeTenABP. L'API è identica a java.time, ma gli import provengono da org.threeten.bp. Ciò consente di scrivere codice che, dopo la migrazione, richiede solo la sostituzione degli import.

kotlin
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalTime
import org.threeten.bp.Duration

fun isWeekend(date: LocalDate): Boolean {
    val dayOfWeek = date.getDayOfWeek()
    return dayOfWeek == DayOfWeek.SATURDAY ||
           dayOfWeek == DayOfWeek.SUNDAY
}

fun timeBetween(
    start: LocalTime, end: LocalTime
): Duration {
    return Duration.between(start, end)
}

Il secondo esempio mostra la formattazione delle date. DateTimeFormatter di org.threeten.bp funziona come in java.time.

kotlin
import org.threeten.bp.LocalDateTime
import org.threeten.bp.format.DateTimeFormatter

fun formatTimestamp(dateTime: LocalDateTime): String {
    val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
    return dateTime.format(formatter)
}

Il terzo esempio mostra il lavoro con ZonedDateTime e la conversione tra fusi orari in ThreeTenABP.

kotlin
import org.threeten.bp.ZonedDateTime
import org.threeten.bp.ZoneId

fun convertTimeZone(
    time: ZonedDateTime,
    targetZone: ZoneId
): ZonedDateTime {
    return time.withZoneSameInstant(targetZone)
}

Migrazione da ThreeTenABP a java.time integrato

Quando si aumenta minSdk a 26, è possibile eliminare ThreeTenABP e passare a java.time integrato. Il processo di migrazione include diversi passaggi e richiede test approfonditi.

Il primo passo è sostituire gli import. Gli import da org.threeten.bp vengono cambiati in java.time. Nella maggior parte dei casi, i nomi delle classi corrispondono: LocalDate → java.time.LocalDate, ZonedDateTime → java.time.ZonedDateTime. L'eccezione è DateTimeFormatter — in ThreeTenABP si trova in org.threeten.bp.format, in java.time si trova in java.time.format.

Il secondo passo è rimuovere l'inizializzazione. La riga AndroidThreeTen.init(this) non è più necessaria, poiché java.time è integrato in Android SDK. Rimuovere la chiamata da Application.onCreate() e la dipendenza da build.gradle.

Il terzo passo è sostituire la dipendenza con desugaring, se minSdk rimane inferiore a 26. Aggiungere isCoreLibraryDesugaringEnabled = true in compileOptions e la dipendenza desugar_jdk_libs. Ciò garantirà il funzionamento di java.time sulle API precedenti senza ThreeTenABP. Secondo Google I/O (2023), il desugaring è l'approccio preferito per i nuovi progetti.

groovy
// build.gradle — sostituire ThreeTenABP con desugaring
android {
    compileOptions {
        isCoreLibraryDesugaringEnabled = true
    }
}

dependencies {
    // Rimuovere: implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
    // Aggiungere:
    "coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}

// Rimuovere AndroidThreeTen.init(this) da Application

Domande frequenti

Si può usare ThreeTenABP insieme al desugaring?

Tecnicamente — sì, ma non ha senso. Se si utilizza il desugaring, java.time integrato è già disponibile. Usare entrambe le librerie porterà a duplicazione di codice e aumento della dimensione dell'APK. Scegliere un approccio per il proprio progetto.

Perché ThreeTenABP richiede l'inizializzazione in Application?

L'inizializzazione carica l'IANA Time Zone Database da assets in memoria. Su JDK standard, tzdata è disponibile tramite classpath, ma Android utilizza AssetManager. Il metodo init() copia i dati nella directory di sistema, rendendoli disponibili per ZoneId.

Quali versioni di Android supporta ThreeTenABP?

ThreeTenABP supporta API 14+ (Android 4.0 Ice Cream Sandwich e superiori). È richiesta la compatibilità Java 8 (sourceCompatibility e targetCompatibility in compileOptions). Su API 26+, la libreria non è necessaria — utilizzare java.time integrato.

Come aggiornare i fusi orari in ThreeTenABP?

I fusi orari sono forniti con la libreria. La versione 1.4.0 include tzdata 2021a. Per aggiornare, è necessario aggiornare la versione di ThreeTenABP o sostituire manualmente tzdata in assets. Le ultime versioni di tzdata possono essere ottenute dal repository IANA o tramite ThreeTen-Backport.

Come testare il codice con ThreeTenABP?

Per i test unitari, utilizzare AndroidThreeTen.init(context, zoneId) con specifica esplicita del fuso. Per i test Robolectric — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). Per i test JVM puri senza Android — utilizzare ThreeTen-Backport direttamente senza ThreeTenABP.

Riepilogo

  • ThreeTenABP è un adattatore Android per ThreeTen-Backport, che fornisce l'API java.time su dispositivi con Android < 8 (API < 26).
  • Aggiunto tramite dipendenza Gradle com.jakewharton.threetenabp:threetenabp:1.4.0 e richiede inizializzazione AndroidThreeTen.init(this) in Application.onCreate().
  • Utilizza il pacchetto org.threeten.bp invece di java.time — l'API è praticamente identica, semplificando la migrazione a API 26+.
  • Classi principali: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter — tutte disponibili in ThreeTenABP.
  • Con l'avvento del desugaring (AGP 4.0+), ThreeTenABP è diventato opzionale ma rimane rilevante per progetti legacy o quando la dimensione dell'APK è limitata.
  • Durante la migrazione a java.time, sostituire gli import org.threeten.bp → java.time, rimuovere AndroidThreeTen.init() e sostituire la dipendenza con desugar_jdk_libs.
  • Per i test, utilizzare AndroidThreeTen.init(context, zoneId) con specifica esplicita del fuso per un comportamento prevedibile.

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.

Discuti il progetto

Leggi anche