ThreeTenABP: co to jest, biblioteka java.time dla Android

Autor: IT Sectr Opublikowano: 2026-07-14 Czas czytania: 11 min

ThreeTenABP — biblioteka-adapter dla Android, udostępniająca API java.time (pakiet org.threeten.bp) na urządzeniach z Androidem poniżej 8 (API < 26). Według specyfikacji Jake Wharton (GitHub, 2023), biblioteka jest nakładką na projekt ThreeTen-Backport, zaadaptowaną dla Android z uwzględnieniem optymalizacji zasobów i obsługi tzdata przez AssetManager.

Najważniejsze

  • ThreeTenABP — adapter Androida dla ThreeTen-Backport, udostępniający java.time na API < 26.
  • Podłącza się przez Gradle: implementation „com.jakewharton.threetenabp:threetenabp:1.4.x”.
  • Wymaga inicjalizacji w Application.onCreate() przez AndroidThreeTen.init(this).
  • Używa pakietu org.threeten.bp zamiast java.time — API jest praktycznie identyczne.
  • Wraz z pojawieniem się desugaring (AGP 4.0+) ThreeTenABP stał się opcjonalny i jest używany w projektach legacy.

Czym jest ThreeTenABP?

ThreeTenABP (ThreeTen Android Backport) — biblioteka stworzona przez Jake’a Whartona do używania API daty/czasu Java 8 na starszych wersjach Androida. Jest adapterem dla projektu ThreeTen-Backport, który przenosi java.time (JSR-310) na Java 7 i Android API < 26.

Główny problem, który rozwiązuje biblioteka: Android przed wersją 8 (API 26) nie zawierał java.time w standardowym zestawie. Deweloperzy byli zmuszeni używać java.util.Date/Calendar lub podłączać Joda-Time. ThreeTenABP zapewnia ten sam nowoczesny API co wbudowany java.time, ale przez pakiet org.threeten.bp.

Według repozytorium GitHub (2023), biblioteka jest zoptymalizowana dla Android: dane tzdata (IANA Time Zone Database) są przechowywane w assets i ładowane przez AssetManager, a nie przez classpath jak na desktopie. Zmniejsza to rozmiar APK i przyspiesza ładowanie.

Ostatnia stabilna wersja to 1.4.0 (sierpień 2021). Biblioteka jest w trybie wsparcia, ponieważ wraz z powszechnym rozpowszechnieniem desugaring zapotrzebowanie na nią maleje, ale pozostaje aktualna dla projektów z minimalnym API < 26.

Dlaczego potrzebny jest backport java.time?

Przed pojawieniem się java.time w Java 8 (2014) deweloperzy używali java.util.Date i java.util.Calendar. Klasy te mają poważne wady: Date jest mutowalny, Calendar używa nieintuicyjnych stałych (Calendar.JANUARY = 0), obie klasy nie są thread-safe i są podatne na błędy przy pracy ze strefami czasowymi.

Joda-Time była de facto standardem przed Java 8, ale jej twórca Stephen Colebourne zaprojektował java.time jako oficjalny zamiennik, oparty na doświadczeniach Joda-Time i uwzględniający jej wady. Pakiet java.time wszedł w skład JDK 8, ale Android nie otrzymał go aż do API 26.

ThreeTen-Backport to port java.time na Java 7, stworzony przez tego samego autora (Stephen Colebourne). Obejmuje wszystkie główne klasy: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. ThreeTenABP adaptuje ten port dla Android, dodając inicjalizację przez AssetsManager i optymalizację dla urządzeń mobilnych.

Tak więc ThreeTenABP umożliwia używanie nowoczesnego API daty/czasu na urządzeniach z Android 4.0+ (API 14+) bez konieczności oczekiwania na aktualizację systemu.

Podłączenie ThreeTenABP w projekcie Android

Podłączenie odbywa się w dwóch krokach: dodanie zależności w build.gradle (app-level) i inicjalizacja w klasie Application. Ważne: ThreeTenABP wymaga compileSdk nie niższego niż 21 i Gradle w wersji nie niższej niż 4.0.

Zależność dodaje się w sekcji dependencies: implementation „com.jakewharton.threetenabp:threetenabp:1.4.0”. Od wydania 1.4.0 biblioteka nie była aktualizowana, ponieważ jest stabilna i pokrywa wszystkie potrzebne przypadki.

Według oficjalnej dokumentacji, biblioteka zawiera tzdata w assets. Jeśli aplikacja ma już folder assets z innymi plikami, ThreeTenABP poprawnie z nimi współistnieje. Rozmiar tzdata to około 200 KB w postaci skompresowanej.

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

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

Inicjalizacja ThreeTenABP

Przed użyciem dowolnej klasy z org.threeten.bp należy zainicjalizować bibliotekę. Inicjalizacja odbywa się raz w Application.onCreate() przez wywołanie AndroidThreeTen.init(this).

Inicjalizacja ładuje dane tzdata z assets i konfiguruje zegar systemowy. Bez wywołania init() metody now() będą zgłaszać wyjątek IllegalStateException z informacją, że biblioteka nie została zainicjalizowana.

Do testów można użyć AndroidThreeTen.init(applicationContext, zoneId) — przeciążenie z jawnym określeniem strefy czasowej. Jest to przydatne do przewidywalnego zachowania testów. Jeśli potrzebna jest tylko podstawowa inicjalizacja bez tzdata — użyj AndroidThreeTen.initWithoutFiles(context).

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

// Użycie po inicjalizacji
val today = LocalDate.now()
val now = LocalDateTime.now()

Jakie klasy są dostępne?

ThreeTenABP udostępnia wszystkie główne klasy java.time, ale w pakiecie org.threeten.bp. API jest praktycznie identyczne z oryginalnym java.time, co ułatwia migrację przy przejściu na API 26+.

Główne klasy:

  • LocalDate — data bez czasu i strefy czasowej
  • LocalTime — czas bez daty i strefy czasowej
  • LocalDateTime — data i czas bez strefy czasowej
  • ZonedDateTime — data i czas ze strefą czasową
  • OffsetDateTime — data i czas ze stałym przesunięciem
  • OffsetTime — czas ze stałym przesunięciem
  • Instant — chwila czasu w UTC
  • Duration — time-based czas trwania
  • Period — date-based okres
  • DateTimeFormatter — formatowanie i parsowanie
  • ZoneId / ZoneOffset — strefy czasowe

Obsługiwane są również klasy pomocnicze: Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. Strefy czasowe są dostarczane wraz z biblioteką (IANA tzdata). Wersja tzdata w ThreeTenABP 1.4.0 odpowiada 2021a.

ThreeTenABP vs desugaring

Począwszy od Android Gradle Plugin 4.0 (2020) i desugar_jdk_libs, deweloperzy otrzymali możliwość używania java.time na wszystkich wersjach Androida przez coreLibraryDesugaring. Desugaring transformuje kod bajtowy w taki sposób, że wywołania java.time działają na starych API bez dodatkowych bibliotek.

Zalety desugaring: używany jest oryginalny pakiet java.time (a nie org.threeten.bp), nie wymaga inicjalizacji, pełna integracja z Android Studio. Wady: wymaga AGP 4.0+, zwiększa czas budowania, rozmiar APK może wzrosnąć o 2–3 MB.

ThreeTenABP pozostaje najlepszym wyborem dla projektów legacy, które nie mogą zaktualizować AGP do 4.0+, lub gdzie krytyczny jest rozmiar APK. ThreeTenABP jest również łatwiejszy w konfiguracji — wystarczy jedna zależność i jedna linia inicjalizacji. Według Stack Overflow (2024), około 30% projektów z minSdk < 26 nadal używa ThreeTenABP zamiast desugaring.

Przykłady użycia

Pierwszy przykład — praca z datami przez ThreeTenABP. API jest identyczne z java.time, ale importy pochodzą z org.threeten.bp. Pozwala to pisać kod, który po migracji wymaga tylko zmiany importów.

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

Drugi przykład — formatowanie daty. DateTimeFormatter z org.threeten.bp działa tak samo jak w 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)
}

Trzeci przykład — praca z ZonedDateTime i konwersja między strefami czasowymi w ThreeTenABP.

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

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

Migracja z ThreeTenABP na wbudowany java.time

Po podniesieniu minSdk do 26 można zrezygnować z ThreeTenABP i przejść na wbudowany java.time. Proces migracji obejmuje kilka kroków i wymaga dokładnego testowania.

Pierwszy krok — zamiana importów. Importy org.threeten.bp zmieniają się na java.time. W większości przypadków nazwy klas są zgodne: LocalDate → java.time.LocalDate, ZonedDateTime → java.time.ZonedDateTime. Wyjątkiem jest DateTimeFormatter — w ThreeTenABP jest w org.threeten.bp.format, w java.time — w java.time.format.

Drugi krok — usunięcie inicjalizacji. Linia AndroidThreeTen.init(this) nie jest już potrzebna, ponieważ java.time jest wbudowany w Android SDK. Usuń wywołanie z Application.onCreate() i zależność z build.gradle.

Trzeci krok — zamiana zależności na desugaring, jeśli minSdk pozostaje poniżej 26. Dodaj isCoreLibraryDesugaringEnabled = true w compileOptions i zależność desugar_jdk_libs. Zapewni to działanie java.time na starych API bez ThreeTenABP. Według Google I/O (2023), desugaring to preferowany sposób dla nowych projektów.

groovy
// build.gradle — zastąp ThreeTenABP desugaring
android {
    compileOptions {
        isCoreLibraryDesugaringEnabled = true
    }
}

dependencies {
    // Usuń: implementation „com.jakewharton.threetenabp:threetenabp:1.4.0”
    // Dodaj:
    "coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}

// Usuń AndroidThreeTen.init(this) z Application

Często zadawane pytania

Czy można używać ThreeTenABP razem z desugaring?

Technicznie — tak, ale nie ma to sensu. Jeśli używany jest desugaring, wbudowany java.time jest już dostępny. Używanie obu bibliotek doprowadzi do duplikacji kodu i zwiększenia rozmiaru APK. Wybierz jedno podejście dla projektu.

Dlaczego ThreeTenABP wymaga inicjalizacji w Application?

Inicjalizacja ładuje dane IANA Time Zone Database z assets do pamięci. Na standardowym JDK tzdata jest dostępna przez classpath, ale Android używa AssetManager. Metoda init() kopiuje dane do katalogu systemowego, udostępniając je dla ZoneId.

Jakie wersje Androida obsługuje ThreeTenABP?

ThreeTenABP obsługuje API 14+ (Android 4.0 Ice Cream Sandwich i nowsze). Do użycia wymagana jest Java 8 compatibility (sourceCompatibility i targetCompatibility w compileOptions). Na API 26+ biblioteka nie jest potrzebna — używaj wbudowanego java.time.

Jak zaktualizować strefy czasowe w ThreeTenABP?

Strefy czasowe są dostarczane wraz z biblioteką. Wersja 1.4.0 zawiera tzdata 2021a. Do aktualizacji należy zaktualizować wersję ThreeTenABP lub ręcznie zastąpić tzdata w assets. Najnowsze wersje tzdata można uzyskać z repozytorium IANA lub przez ThreeTen-Backport.

Jak testować kod z ThreeTenABP?

Do testów jednostkowych używaj AndroidThreeTen.init(context, zoneId) z jawnym określeniem strefy. Do testów Robolectric — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). Do testów JVM bez Androida — używaj ThreeTen-Backport bezpośrednio bez ThreeTenABP.

Podsumowanie

  • ThreeTenABP — adapter Androida dla ThreeTen-Backport, udostępniający API java.time na urządzeniach z Android < 8 (API < 26).
  • Podłącza się przez zależność Gradle com.jakewharton.threetenabp:threetenabp:1.4.0 i wymaga inicjalizacji AndroidThreeTen.init(this) w Application.onCreate().
  • Używa pakietu org.threeten.bp zamiast java.time — API jest praktycznie identyczne, co ułatwia migrację przy przejściu na API 26+.
  • Główne klasy: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter — wszystkie dostępne w ThreeTenABP.
  • Wraz z pojawieniem się desugaring (AGP 4.0+) ThreeTenABP stał się opcjonalny, ale pozostaje aktualny dla projektów legacy lub przy ograniczeniach rozmiaru APK.
  • Przy migracji na java.time zamień importy org.threeten.bp → java.time, usuń AndroidThreeTen.init() i zamień zależność na desugar_jdk_libs.
  • Do testowania używaj AndroidThreeTen.init(context, zoneId) z jawnym określeniem strefy dla przewidywalnego zachowania.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również