ThreeTenABP es una biblioteca adaptadora para Android que proporciona la API java.time (paquete org.threeten.bp) en dispositivos con Android inferior a 8 (API < 26). Según la especificación de Jake Wharton (GitHub, 2023), la biblioteca es un envoltorio sobre el proyecto ThreeTen-Backport, adaptado para Android con optimización de recursos y soporte de tzdata a través de AssetManager.
Puntos clave
ThreeTenABP (ThreeTen Android Backport) es una biblioteca creada por Jake Wharton para usar la API de fecha/hora de Java 8 en versiones antiguas de Android. Es un adaptador para el proyecto ThreeTen-Backport, que trasplanta java.time (JSR-310) a Java 7 y Android API < 26.
El problema principal que resuelve la biblioteca: Android antes de la versión 8 (API 26) no incluía java.time en la distribución estándar. Los desarrolladores se veían obligados a usar java.util.Date/Calendar o agregar Joda-Time. ThreeTenABP proporciona la misma API moderna que java.time integrado, pero a través del paquete org.threeten.bp.
Según el repositorio de GitHub (2023), la biblioteca está optimizada para Android: los datos tzdata (IANA Time Zone Database) se almacenan en assets y se cargan a través de AssetManager, en lugar de classpath como en el escritorio. Esto reduce el tamaño del APK y acelera la carga.
La última versión estable es 1.4.0 (agosto de 2021). La biblioteca está en modo de mantenimiento, ya que con la adopción generalizada de desugaring, la necesidad de ella disminuye, pero sigue siendo relevante para proyectos con API mínima < 26.
Antes de que java.time se introdujera en Java 8 (2014), los desarrolladores usaban java.util.Date y java.util.Calendar. Estas clases tienen serios inconvenientes: Date es mutable, Calendar usa constantes no intuitivas (Calendar.JANUARY = 0), ambas clases no son thread-safe y son propensas a errores al trabajar con zonas horarias.
Joda-Time fue el estándar de facto antes de Java 8, pero su creador Stephen Colebourne diseñó java.time como el reemplazo oficial, basándose en la experiencia de Joda-Time y abordando sus deficiencias. El paquete java.time se incluyó en JDK 8, pero Android no lo recibió hasta API 26.
ThreeTen-Backport es un trasplante de java.time a Java 7, creado por el mismo autor (Stephen Colebourne). Incluye todas las clases principales: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. ThreeTenABP adapta este trasplante para Android, agregando inicialización a través de AssetsManager y optimización para dispositivos móviles.
Por lo tanto, ThreeTenABP permite usar la API moderna de fecha/hora en dispositivos con Android 4.0+ (API 14+) sin esperar una actualización del sistema operativo.
La incorporación se realiza en dos pasos: agregar la dependencia en build.gradle (nivel de app) e inicializar en la clase Application. Importante: ThreeTenABP requiere compileSdk de al menos 21 y Gradle versión de al menos 4.0.
La dependencia se agrega en la sección de dependencias: implementation "com.jakewharton.threetenabp:threetenabp:1.4.0". Desde el lanzamiento de 1.4.0, la biblioteca no se ha actualizado, ya que es estable y cubre todos los casos necesarios.
Según la documentación oficial, la biblioteca incluye tzdata en assets. Si la aplicación ya tiene una carpeta assets con otros archivos, ThreeTenABP coexiste correctamente con ellos. El tamaño de tzdata es de aproximadamente 200 KB comprimido.
// build.gradle (nivel de app)
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
}
Antes de usar cualquier clase de org.threeten.bp, la biblioteca debe inicializarse. La inicialización se realiza una vez en Application.onCreate() llamando a AndroidThreeTen.init(this).
La inicialización carga los datos tzdata desde assets y configura el reloj del sistema. Sin llamar a init(), los métodos now() lanzarán una excepción IllegalStateException con un mensaje de que la biblioteca no está inicializada.
Para pruebas, puede usar AndroidThreeTen.init(applicationContext, zoneId) — una sobrecarga con especificación explícita de zona horaria. Esto es útil para un comportamiento predecible en las pruebas. Si solo se necesita una inicialización básica sin tzdata, use AndroidThreeTen.initWithoutFiles(context).
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// Uso después de la inicialización
val today = LocalDate.now()
val now = LocalDateTime.now()
ThreeTenABP proporciona todas las clases principales de java.time, pero en el paquete org.threeten.bp. La API es prácticamente idéntica a la java.time original, lo que facilita la migración al pasar a API 26+.
Clases principales:
También se admiten clases auxiliares: Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. Las zonas horarias se incluyen con la biblioteca (IANA tzdata). La versión de tzdata en ThreeTenABP 1.4.0 corresponde a 2021a.
A partir de Android Gradle Plugin 4.0 (2020) y desugar_jdk_libs, los desarrolladores obtuvieron la capacidad de usar java.time en todas las versiones de Android mediante coreLibraryDesugaring. Desugaring transforma el bytecode para que las llamadas a java.time funcionen en API antiguas sin bibliotecas adicionales.
Ventajas de desugaring: usa el paquete java.time original (no org.threeten.bp), no requiere inicialización, integración completa con Android Studio. Desventajas: requiere AGP 4.0+, agrega tiempo de compilación, el tamaño del APK puede aumentar 2-3 MB.
ThreeTenABP sigue siendo la mejor opción para proyectos heredados que no pueden actualizar AGP a 4.0+, o donde el tamaño del APK es crítico. ThreeTenABP también es más fácil de configurar — solo una dependencia y una línea de inicialización. Según Stack Overflow (2024), alrededor del 30% de los proyectos con minSdk < 26 aún usan ThreeTenABP en lugar de desugaring.
El primer ejemplo demuestra el trabajo con fechas usando ThreeTenABP. La API es idéntica a java.time, pero las importaciones provienen de org.threeten.bp. Esto permite escribir código que, después de la migración, solo requiere reemplazar las importaciones.
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)
}
El segundo ejemplo muestra el formateo de fechas. DateTimeFormatter de org.threeten.bp funciona igual que en 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)
}
El tercer ejemplo demuestra el trabajo con ZonedDateTime y la conversión entre zonas horarias en ThreeTenABP.
import org.threeten.bp.ZonedDateTime
import org.threeten.bp.ZoneId
fun convertTimeZone(
time: ZonedDateTime,
targetZone: ZoneId
): ZonedDateTime {
return time.withZoneSameInstant(targetZone)
}
Al aumentar minSdk a 26, puede abandonar ThreeTenABP y cambiar a java.time integrado. El proceso de migración incluye varios pasos y requiere pruebas exhaustivas.
El primer paso es reemplazar las importaciones. Las importaciones de org.threeten.bp se cambian a java.time. En la mayoría de los casos, los nombres de las clases coinciden: LocalDate → java.time.LocalDate, ZonedDateTime → java.time.ZonedDateTime. La excepción es DateTimeFormatter — en ThreeTenABP está en org.threeten.bp.format, en java.time está en java.time.format.
El segundo paso es eliminar la inicialización. La línea AndroidThreeTen.init(this) ya no es necesaria, ya que java.time está integrado en Android SDK. Elimine la llamada de Application.onCreate() y la dependencia de build.gradle.
El tercer paso es reemplazar la dependencia con desugaring, si minSdk permanece por debajo de 26. Agregue isCoreLibraryDesugaringEnabled = true en compileOptions y la dependencia desugar_jdk_libs. Esto garantizará que java.time funcione en API antiguas sin ThreeTenABP. Según Google I/O (2023), desugaring es el enfoque preferido para nuevos proyectos.
// build.gradle — reemplazar ThreeTenABP con desugaring
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
// Eliminar: implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
// Agregar:
"coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}
// Eliminar AndroidThreeTen.init(this) de Application
Preguntas frecuentes
Técnicamente — sí, pero no tiene sentido. Si se usa desugaring, java.time integrado ya está disponible. Usar ambas bibliotecas conducirá a duplicación de código y aumento del tamaño del APK. Elija un enfoque para su proyecto.
La inicialización carga la IANA Time Zone Database desde assets a la memoria. En JDK estándar, tzdata está disponible a través de classpath, pero Android usa AssetManager. El método init() copia los datos al directorio del sistema, haciéndolos disponibles para ZoneId.
ThreeTenABP soporta API 14+ (Android 4.0 Ice Cream Sandwich y superior). Se requiere compatibilidad con Java 8 (sourceCompatibility y targetCompatibility en compileOptions). En API 26+, la biblioteca no es necesaria — use java.time integrado.
Las zonas horarias se incluyen con la biblioteca. La versión 1.4.0 incluye tzdata 2021a. Para actualizar, necesita actualizar la versión de ThreeTenABP o reemplazar manualmente tzdata en assets. Las últimas versiones de tzdata se pueden obtener del repositorio IANA o a través de ThreeTen-Backport.
Para pruebas unitarias, use AndroidThreeTen.init(context, zoneId) con una especificación explícita de zona. Para pruebas Robolectric — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). Para pruebas JVM puras sin Android — use ThreeTen-Backport directamente sin ThreeTenABP.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también