ThreeTenABP: o que é, biblioteca java.time para Android

Autor: IT Sectr Publicado: 2026-07-14 Tempo de leitura: 11 min

ThreeTenABP é uma biblioteca adaptadora para Android que fornece a API java.time (pacote org.threeten.bp) em dispositivos com Android inferior ao 8 (API < 26). De acordo com a especificação de Jake Wharton (GitHub, 2023), a biblioteca é um wrapper sobre o projeto ThreeTen-Backport, adaptado para Android com otimização de recursos e suporte a tzdata através do AssetManager.

Pontos principais

  • ThreeTenABP é um adaptador Android para ThreeTen-Backport, fornecendo java.time na API < 26.
  • Adicionado via Gradle: implementation "com.jakewharton.threetenabp:threetenabp:1.4.x".
  • Requer inicialização em Application.onCreate() através de AndroidThreeTen.init(this).
  • Usa o pacote org.threeten.bp em vez de java.time — a API é praticamente idêntica.
  • Com o advento do desugaring (AGP 4.0+), o ThreeTenABP tornou-se opcional e é usado para projetos legados.

O que é ThreeTenABP?

ThreeTenABP (ThreeTen Android Backport) é uma biblioteca criada por Jake Wharton para usar a API de data/hora do Java 8 em versões antigas do Android. É um adaptador para o projeto ThreeTen-Backport, que porta java.time (JSR-310) para Java 7 e Android API < 26.

O principal problema que a biblioteca resolve: o Android antes da versão 8 (API 26) não incluía java.time na distribuição padrão. Os desenvolvedores eram forçados a usar java.util.Date/Calendar ou adicionar Joda-Time. O ThreeTenABP fornece a mesma API moderna que o java.time integrado, mas através do pacote org.threeten.bp.

De acordo com o repositório GitHub (2023), a biblioteca é otimizada para Android: os dados tzdata (IANA Time Zone Database) são armazenados em assets e carregados via AssetManager, em vez de classpath como no desktop. Isso reduz o tamanho do APK e acelera o carregamento.

A última versão estável é 1.4.0 (agosto de 2021). A biblioteca está em modo de manutenção, pois com a adoção generalizada do desugaring, a necessidade dela diminui, mas permanece relevante para projetos com API mínima < 26.

Por que é necessário um backport do java.time?

Antes do java.time ser introduzido no Java 8 (2014), os desenvolvedores usavam java.util.Date e java.util.Calendar. Essas classes têm sérias desvantagens: Date é mutável, Calendar usa constantes não intuitivas (Calendar.JANUARY = 0), ambas as classes não são thread-safe e são propensas a erros ao trabalhar com fusos horários.

Joda-Time era o padrão de facto antes do Java 8, mas seu criador Stephen Colebourne projetou java.time como a substituição oficial, baseado na experiência do Joda-Time e abordando suas deficiências. O pacote java.time foi incluído no JDK 8, mas o Android não o recebeu até a API 26.

ThreeTen-Backport é uma porta do java.time para Java 7, criada pelo mesmo autor (Stephen Colebourne). Inclui todas as principais classes: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. O ThreeTenABP adapta esta porta para Android, adicionando inicialização através de AssetsManager e otimização para dispositivos móveis.

Assim, o ThreeTenABP permite usar a API moderna de data/hora em dispositivos com Android 4.0+ (API 14+) sem esperar por uma atualização do sistema operacional.

Adicionar ThreeTenABP a um projeto Android

A adição é feita em duas etapas: adicionar a dependência no build.gradle (nível do app) e inicializar na classe Application. Importante: o ThreeTenABP requer compileSdk de pelo menos 21 e versão do Gradle de pelo menos 4.0.

A dependência é adicionada na seção de dependências: implementation "com.jakewharton.threetenabp:threetenabp:1.4.0". Desde o lançamento da 1.4.0, a biblioteca não foi atualizada, pois é estável e cobre todos os casos necessários.

De acordo com a documentação oficial, a biblioteca inclui tzdata em assets. Se o aplicativo já tiver uma pasta assets com outros arquivos, o ThreeTenABP coexiste corretamente com eles. O tamanho do tzdata é de aproximadamente 200 KB compactado.

groovy
// build.gradle (nível do app)
android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
}

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

Inicialização do ThreeTenABP

Antes de usar qualquer classe do org.threeten.bp, a biblioteca deve ser inicializada. A inicialização é realizada uma vez em Application.onCreate() chamando AndroidThreeTen.init(this).

A inicialização carrega os dados tzdata dos assets e configura o relógio do sistema. Sem chamar init(), os métodos now() lançarão uma IllegalStateException com uma mensagem de que a biblioteca não foi inicializada.

Para testes, você pode usar AndroidThreeTen.init(applicationContext, zoneId) — uma sobrecarga com especificação explícita de fuso horário. Isso é útil para comportamento previsível em testes. Se apenas a inicialização básica sem tzdata for necessária, use AndroidThreeTen.initWithoutFiles(context).

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

// Uso após a inicialização
val today = LocalDate.now()
val now = LocalDateTime.now()

Quais classes estão disponíveis?

O ThreeTenABP fornece todas as principais classes do java.time, mas no pacote org.threeten.bp. A API é praticamente idêntica ao java.time original, facilitando a migração ao mudar para API 26+.

Classes principais:

  • LocalDate — data sem hora e fuso horário
  • LocalTime — hora sem data e fuso horário
  • LocalDateTime — data e hora sem fuso horário
  • ZonedDateTime — data e hora com fuso horário
  • OffsetDateTime — data e hora com deslocamento fixo
  • OffsetTime — hora com deslocamento fixo
  • Instant — momento no tempo em UTC
  • Duration — duração baseada em tempo
  • Period — duração baseada em data
  • DateTimeFormatter — formatação e análise
  • ZoneId / ZoneOffset — fusos horários

Classes auxiliares também são suportadas: Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. Os fusos horários são fornecidos com a biblioteca (IANA tzdata). A versão do tzdata no ThreeTenABP 1.4.0 corresponde a 2021a.

ThreeTenABP vs desugaring

A partir do Android Gradle Plugin 4.0 (2020) e desugar_jdk_libs, os desenvolvedores obtiveram a capacidade de usar java.time em todas as versões do Android através de coreLibraryDesugaring. O desugaring transforma o bytecode para que as chamadas java.time funcionem em APIs antigas sem bibliotecas adicionais.

Vantagens do desugaring: usa o pacote java.time original (não org.threeten.bp), não requer inicialização, integração completa com o Android Studio. Desvantagens: requer AGP 4.0+, aumenta o tempo de compilação, o tamanho do APK pode aumentar em 2-3 MB.

O ThreeTenABP continua sendo a melhor escolha para projetos legados que não podem atualizar o AGP para 4.0+, ou onde o tamanho do APK é crítico. O ThreeTenABP também é mais fácil de configurar — apenas uma dependência e uma linha de inicialização. De acordo com o Stack Overflow (2024), cerca de 30% dos projetos com minSdk < 26 ainda usam ThreeTenABP em vez de desugaring.

Exemplos de uso

O primeiro exemplo demonstra o trabalho com datas usando o ThreeTenABP. A API é idêntica ao java.time, mas as importações vêm do org.threeten.bp. Isso permite escrever código que, após a migração, requer apenas a substituição das importações.

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

O segundo exemplo mostra a formatação de datas. O DateTimeFormatter do org.threeten.bp funciona da mesma forma que no 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)
}

O terceiro exemplo demonstra o trabalho com ZonedDateTime e a conversão entre fusos horários no ThreeTenABP.

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

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

Migração do ThreeTenABP para java.time integrado

Ao aumentar o minSdk para 26, você pode abandonar o ThreeTenABP e mudar para o java.time integrado. O processo de migração inclui várias etapas e requer testes completos.

O primeiro passo é substituir as importações. As importações de org.threeten.bp são alteradas para java.time. Na maioria dos casos, os nomes das classes coincidem: LocalDate → java.time.LocalDate, ZonedDateTime → java.time.ZonedDateTime. A exceção é o DateTimeFormatter — no ThreeTenABP está em org.threeten.bp.format, no java.time está em java.time.format.

O segundo passo é remover a inicialização. A linha AndroidThreeTen.init(this) não é mais necessária, pois o java.time está integrado ao Android SDK. Remova a chamada de Application.onCreate() e a dependência do build.gradle.

O terceiro passo é substituir a dependência pelo desugaring, se o minSdk permanecer abaixo de 26. Adicione isCoreLibraryDesugaringEnabled = true em compileOptions e a dependência desugar_jdk_libs. Isso garantirá que o java.time funcione em APIs antigas sem o ThreeTenABP. De acordo com o Google I/O (2023), o desugaring é a abordagem preferida para novos projetos.

groovy
// build.gradle — substituir ThreeTenABP por desugaring
android {
    compileOptions {
        isCoreLibraryDesugaringEnabled = true
    }
}

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

// Remover AndroidThreeTen.init(this) de Application

Perguntas frequentes

É possível usar o ThreeTenABP junto com desugaring?

Tecnicamente — sim, mas não faz sentido. Se o desugaring for usado, o java.time integrado já está disponível. Usar ambas as bibliotecas levará à duplicação de código e aumento do tamanho do APK. Escolha uma abordagem para o seu projeto.

Por que o ThreeTenABP requer inicialização no Application?

A inicialização carrega o IANA Time Zone Database dos assets para a memória. No JDK padrão, o tzdata está disponível via classpath, mas o Android usa AssetManager. O método init() copia os dados para o diretório do sistema, tornando-os disponíveis para o ZoneId.

Quais versões do Android o ThreeTenABP suporta?

O ThreeTenABP suporta API 14+ (Android 4.0 Ice Cream Sandwich e superior). É necessária compatibilidade com Java 8 (sourceCompatibility e targetCompatibility em compileOptions). Na API 26+, a biblioteca não é necessária — use o java.time integrado.

Como atualizar os fusos horários no ThreeTenABP?

Os fusos horários são fornecidos com a biblioteca. A versão 1.4.0 inclui tzdata 2021a. Para atualizar, você precisa atualizar a versão do ThreeTenABP ou substituir manualmente o tzdata em assets. As versões mais recentes do tzdata podem ser obtidas do repositório IANA ou através do ThreeTen-Backport.

Como testar código com ThreeTenABP?

Para testes unitários, use AndroidThreeTen.init(context, zoneId) com uma especificação explícita de zona. Para testes Robolectric — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). Para testes JVM puros sem Android — use o ThreeTen-Backport diretamente sem o ThreeTenABP.

Resumo

  • ThreeTenABP é um adaptador Android para ThreeTen-Backport, fornecendo a API java.time em dispositivos com Android < 8 (API < 26).
  • Adicionado via dependência Gradle com.jakewharton.threetenabp:threetenabp:1.4.0 e requer inicialização AndroidThreeTen.init(this) em Application.onCreate().
  • Usa o pacote org.threeten.bp em vez de java.time — a API é praticamente idêntica, simplificando a migração ao mudar para API 26+.
  • Classes principais: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter — todas disponíveis no ThreeTenABP.
  • Com o advento do desugaring (AGP 4.0+), o ThreeTenABP tornou-se opcional, mas permanece relevante para projetos legados ou quando o tamanho do APK é limitado.
  • Ao migrar para java.time, substitua as importações org.threeten.bp → java.time, remova AndroidThreeTen.init() e substitua a dependência por desugar_jdk_libs.
  • Para testes, use AndroidThreeTen.init(context, zoneId) com uma especificação explícita de zona para comportamento previsível.

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também