ThreeTenABP: qué es, biblioteca java.time para Android

Autor: IT Sectr Publicado: 2026-07-14 Tiempo de lectura: 11 min

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 es un adaptador Android para ThreeTen-Backport, que proporciona java.time en API < 26.
  • Se agrega mediante Gradle: implementation "com.jakewharton.threetenabp:threetenabp:1.4.x".
  • Requiere inicialización en Application.onCreate() mediante AndroidThreeTen.init(this).
  • Utiliza el paquete org.threeten.bp en lugar de java.time — la API es prácticamente idéntica.
  • Con la llegada de desugaring (AGP 4.0+), ThreeTenABP se ha vuelto opcional y se usa para proyectos heredados.

¿Qué es ThreeTenABP?

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.

¿Por qué se necesita un backport de java.time?

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.

Agregar ThreeTenABP a un proyecto Android

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.

groovy
// 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"
}

Inicialización de ThreeTenABP

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).

kotlin
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()

¿Qué clases están disponibles?

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:

  • LocalDate — fecha sin hora ni zona horaria
  • LocalTime — hora sin fecha ni zona horaria
  • LocalDateTime — fecha y hora sin zona horaria
  • ZonedDateTime — fecha y hora con zona horaria
  • OffsetDateTime — fecha y hora con desplazamiento fijo
  • OffsetTime — hora con desplazamiento fijo
  • Instant — momento en el tiempo en UTC
  • Duration — duración basada en tiempo
  • Period — duración basada en fecha
  • DateTimeFormatter — formateo y análisis
  • ZoneId / ZoneOffset — zonas horarias

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.

ThreeTenABP vs desugaring

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.

Ejemplos de uso

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.

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)
}

El segundo ejemplo muestra el formateo de fechas. DateTimeFormatter de org.threeten.bp funciona igual que en 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)
}

El tercer ejemplo demuestra el trabajo con ZonedDateTime y la conversión entre zonas horarias en ThreeTenABP.

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

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

Migración de ThreeTenABP a java.time integrado

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.

groovy
// 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

¿Se puede usar ThreeTenABP junto con desugaring?

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.

¿Por qué ThreeTenABP requiere inicialización en Application?

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.

¿Qué versiones de Android soporta ThreeTenABP?

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.

¿Cómo actualizar las zonas horarias en ThreeTenABP?

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.

¿Cómo probar código con ThreeTenABP?

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

  • ThreeTenABP es un adaptador Android para ThreeTen-Backport, que proporciona la API java.time en dispositivos con Android < 8 (API < 26).
  • Se agrega mediante dependencia Gradle com.jakewharton.threetenabp:threetenabp:1.4.0 y requiere inicialización AndroidThreeTen.init(this) en Application.onCreate().
  • Usa el paquete org.threeten.bp en lugar de java.time — la API es prácticamente idéntica, simplificando la migración al pasar a API 26+.
  • Clases principales: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter — todas disponibles en ThreeTenABP.
  • Con la llegada de desugaring (AGP 4.0+), ThreeTenABP se ha vuelto opcional pero sigue siendo relevante para proyectos heredados o cuando el tamaño del APK es limitado.
  • Al migrar a java.time, reemplace importaciones org.threeten.bp → java.time, elimine AndroidThreeTen.init() y reemplace la dependencia con desugar_jdk_libs.
  • Para pruebas, use AndroidThreeTen.init(context, zoneId) con una especificación explícita de zona para un comportamiento predecible.

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.

Discutir el proyecto

Lea también