ThreeTenABP est une bibliothèque adaptatrice pour Android qui fournit l’API java.time (paquetage org.threeten.bp) sur les appareils avec Android inférieur à 8 (API < 26). Selon la spécification de Jake Wharton (GitHub, 2023), la bibliothèque est un wrapper autour du projet ThreeTen-Backport, adapté pour Android avec optimisation des ressources et prise en charge de tzdata via AssetManager.
Points clés
ThreeTenABP (ThreeTen Android Backport) est une bibliothèque créée par Jake Wharton pour utiliser l’API de date/heure Java 8 sur les anciennes versions d’Android. C’est un adaptateur pour le projet ThreeTen-Backport, qui porte java.time (JSR-310) vers Java 7 et Android API < 26.
Le principal problème que la bibliothèque résout : Android avant la version 8 (API 26) n’incluait pas java.time dans la distribution standard. Les développeurs étaient obligés d’utiliser java.util.Date/Calendar ou d’ajouter Joda-Time. ThreeTenABP fournit la même API moderne que java.time intégré, mais via le paquetage org.threeten.bp.
Selon le dépôt GitHub (2023), la bibliothèque est optimisée pour Android : les données tzdata (IANA Time Zone Database) sont stockées dans assets et chargées via AssetManager, plutôt que via classpath comme sur le desktop. Cela réduit la taille de l’APK et accélère le chargement.
La dernière version stable est la 1.4.0 (août 2021). La bibliothèque est en mode maintenance, car avec l’adoption généralisée du desugaring, son besoin diminue, mais elle reste pertinente pour les projets avec une API minimale < 26.
Avant l’introduction de java.time dans Java 8 (2014), les développeurs utilisaient java.util.Date et java.util.Calendar. Ces classes présentent de sérieux inconvénients : Date est mutable, Calendar utilise des constantes non intuitives (Calendar.JANUARY = 0), les deux classes ne sont pas thread-safe et sont sujettes aux erreurs lors du travail avec les fuseaux horaires.
Joda-Time était le standard de facto avant Java 8, mais son créateur Stephen Colebourne a conçu java.time comme le remplacement officiel, basé sur l’expérience de Joda-Time et corrigeant ses lacunes. Le paquetage java.time a été inclus dans JDK 8, mais Android ne l’a reçu qu’avec API 26.
ThreeTen-Backport est un portage de java.time vers Java 7, créé par le même auteur (Stephen Colebourne). Il inclut toutes les classes principales : LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. ThreeTenABP adapte ce portage pour Android, ajoutant l’initialisation via AssetsManager et l’optimisation pour les appareils mobiles.
Ainsi, ThreeTenABP permet d’utiliser l’API moderne de date/heure sur les appareils avec Android 4.0+ (API 14+) sans attendre une mise à jour du système d’exploitation.
L’ajout se fait en deux étapes : ajouter la dépendance dans build.gradle (niveau app) et initialiser dans la classe Application. Important : ThreeTenABP nécessite un compileSdk d’au moins 21 et une version Gradle d’au moins 4.0.
La dépendance est ajoutée dans la section dependencies : implementation "com.jakewharton.threetenabp:threetenabp:1.4.0". Depuis la sortie de la 1.4.0, la bibliothèque n’a pas été mise à jour, car elle est stable et couvre tous les cas nécessaires.
Selon la documentation officielle, la bibliothèque inclut tzdata dans assets. Si l’application a déjà un dossier assets avec d’autres fichiers, ThreeTenABP coexiste correctement avec eux. La taille de tzdata est d’environ 200 Ko compressé.
// build.gradle (niveau app)
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
}
Avant d’utiliser une classe de org.threeten.bp, la bibliothèque doit être initialisée. L’initialisation est effectuée une fois dans Application.onCreate() en appelant AndroidThreeTen.init(this).
L’initialisation charge les données tzdata depuis assets et configure l’horloge système. Sans appel à init(), les méthodes now() lanceront une IllegalStateException avec un message indiquant que la bibliothèque n’est pas initialisée.
Pour les tests, vous pouvez utiliser AndroidThreeTen.init(applicationContext, zoneId) — une surcharge avec spécification explicite du fuseau horaire. Ceci est utile pour un comportement prévisible dans les tests. Si seule une initialisation de base sans tzdata est nécessaire, utilisez AndroidThreeTen.initWithoutFiles(context).
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// Utilisation après initialisation
val today = LocalDate.now()
val now = LocalDateTime.now()
ThreeTenABP fournit toutes les classes principales de java.time, mais dans le paquetage org.threeten.bp. L’API est pratiquement identique à java.time original, ce qui facilite la migration lors du passage à API 26+.
Classes principales :
Les classes auxiliaires sont également prises en charge : Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. Les fuseaux horaires sont fournis avec la bibliothèque (IANA tzdata). La version tzdata dans ThreeTenABP 1.4.0 correspond à 2021a.
À partir d’Android Gradle Plugin 4.0 (2020) et desugar_jdk_libs, les développeurs ont obtenu la possibilité d’utiliser java.time sur toutes les versions d’Android via coreLibraryDesugaring. Le desugaring transforme le bytecode pour que les appels java.time fonctionnent sur les anciennes API sans bibliothèques supplémentaires.
Avantages du desugaring : utilise le paquetage java.time original (pas org.threeten.bp), aucune initialisation requise, intégration complète avec Android Studio. Inconvénients : nécessite AGP 4.0+, augmente le temps de compilation, la taille de l’APK peut augmenter de 2-3 Mo.
ThreeTenABP reste le meilleur choix pour les projets legacy qui ne peuvent pas mettre à jour AGP vers 4.0+, ou lorsque la taille de l’APK est critique. ThreeTenABP est également plus facile à configurer — juste une dépendance et une ligne d’initialisation. Selon Stack Overflow (2024), environ 30 % des projets avec minSdk < 26 utilisent encore ThreeTenABP au lieu de desugaring.
Le premier exemple montre le travail avec les dates en utilisant ThreeTenABP. L’API est identique à java.time, mais les importations proviennent de org.threeten.bp. Cela permet d’écrire du code qui, après la migration, ne nécessite que le remplacement des importations.
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)
}
Le deuxième exemple montre le formatage des dates. DateTimeFormatter de org.threeten.bp fonctionne de la même manière que dans java.time.
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)
}
Le troisième exemple montre le travail avec ZonedDateTime et la conversion entre fuseaux horaires dans ThreeTenABP.
import org.threeten.bp.ZonedDateTime
import org.threeten.bp.ZoneId
fun convertTimeZone(
time: ZonedDateTime,
targetZone: ZoneId
): ZonedDateTime {
return time.withZoneSameInstant(targetZone)
}
En augmentant minSdk à 26, vous pouvez abandonner ThreeTenABP et passer à java.time intégré. Le processus de migration comprend plusieurs étapes et nécessite des tests approfondis.
La première étape consiste à remplacer les importations. Les importations de org.threeten.bp sont changées en java.time. Dans la plupart des cas, les noms de classes correspondent : LocalDate → java.time.LocalDate, ZonedDateTime → java.time.ZonedDateTime. L’exception est DateTimeFormatter — dans ThreeTenABP, il se trouve dans org.threeten.bp.format, dans java.time, il est dans java.time.format.
La deuxième étape consiste à supprimer l’initialisation. La ligne AndroidThreeTen.init(this) n’est plus nécessaire, car java.time est intégré dans Android SDK. Supprimez l’appel de Application.onCreate() et la dépendance de build.gradle.
La troisième étape consiste à remplacer la dépendance par le desugaring, si minSdk reste inférieur à 26. Ajoutez isCoreLibraryDesugaringEnabled = true dans compileOptions et la dépendance desugar_jdk_libs. Cela garantira le fonctionnement de java.time sur les anciennes API sans ThreeTenABP. Selon Google I/O (2023), le desugaring est l’approche préférée pour les nouveaux projets.
// build.gradle — remplacer ThreeTenABP par desugaring
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
// Supprimer : implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
// Ajouter :
"coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}
// Supprimer AndroidThreeTen.init(this) de Application
Foire aux questions
Techniquement — oui, mais cela n’a pas de sens. Si le desugaring est utilisé, java.time intégré est déjà disponible. Utiliser les deux bibliothèques entraînera une duplication de code et une augmentation de la taille de l’APK. Choisissez une approche pour votre projet.
L’initialisation charge l’IANA Time Zone Database depuis assets en mémoire. Sur JDK standard, tzdata est disponible via classpath, mais Android utilise AssetManager. La méthode init() copie les données dans le répertoire système, les rendant disponibles pour ZoneId.
ThreeTenABP prend en charge API 14+ (Android 4.0 Ice Cream Sandwich et supérieur). La compatibilité Java 8 est requise (sourceCompatibility et targetCompatibility dans compileOptions). Sur API 26+, la bibliothèque n’est pas nécessaire — utilisez java.time intégré.
Les fuseaux horaires sont fournis avec la bibliothèque. La version 1.4.0 inclut tzdata 2021a. Pour mettre à jour, vous devez mettre à jour la version de ThreeTenABP ou remplacer manuellement tzdata dans assets. Les dernières versions de tzdata peuvent être obtenues depuis le dépôt IANA ou via ThreeTen-Backport.
Pour les tests unitaires, utilisez AndroidThreeTen.init(context, zoneId) avec une spécification explicite du fuseau. Pour les tests Robolectric — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). Pour les tests JVM purs sans Android — utilisez ThreeTen-Backport directement sans ThreeTenABP.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi