ThreeTenABP: τι είναι, βιβλιοθήκη java.time για Android

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-07-14 Χρόνος ανάγνωσης: 11 λεπ

ThreeTenABP — βιβλιοθήκη-προσαρμογέας για Android, που παρέχει API java.time (πακέτο org.threeten.bp) σε συσκευές με Android κάτω από 8 (API < 26). Σύμφωνα με τις προδιαγραφές Jake Wharton (GitHub, 2023), η βιβλιοθήκη είναι ένα περιτύλιγμα γύρω από το έργο ThreeTen-Backport, προσαρμοσμένο για Android με βελτιστοποίηση πόρων και υποστήριξη tzdata μέσω AssetManager.

Κύρια σημεία

  • ThreeTenABP — προσαρμογέας Android για ThreeTen-Backport, που παρέχει java.time σε API < 26.
  • Συνδέεται μέσω Gradle: implementation “com.jakewharton.threetenabp:threetenabp:1.4.x”.
  • Απαιτεί αρχικοποίηση στο Application.onCreate() μέσω AndroidThreeTen.init(this).
  • Χρησιμοποιεί το πακέτο org.threeten.bp αντί για java.time — το API είναι σχεδόν ταυτόσημο.
  • Με την εμφάνιση του desugaring (AGP 4.0+) το ThreeTenABP έγινε προαιρετικό και χρησιμοποιείται για legacy έργα.

Τι είναι το ThreeTenABP;

ThreeTenABP (ThreeTen Android Backport) — βιβλιοθήκη που δημιουργήθηκε από τον Jake Wharton για χρήση του API ημερομηνίας/ώρας Java 8 σε παλαιότερες εκδόσεις Android. Είναι προσαρμογέας για το έργο ThreeTen-Backport, το οποίο μεταφέρει java.time (JSR-310) σε Java 7 και Android API < 26.

Το κύριο πρόβλημα που λύνει η βιβλιοθήκη: το Android μέχρι την έκδοση 8 (API 26) δεν περιελάμβανε java.time στην τυπική διανομή. Οι προγραμματιστές αναγκάζονταν να χρησιμοποιούν java.util.Date/Calendar ή να προσθέτουν Joda-Time. Το ThreeTenABP παρέχει το ίδιο σύγχρονο API με το ενσωματωμένο java.time, αλλά μέσω του πακέτου org.threeten.bp.

Σύμφωνα με το αποθετήριο GitHub (2023), η βιβλιοθήκη είναι βελτιστοποιημένη για Android: τα δεδομένα tzdata (IANA Time Zone Database) αποθηκεύονται στο assets και φορτώνονται μέσω AssetManager, όχι μέσω classpath όπως στην επιφάνεια εργασίας. Αυτό μειώνει το μέγεθος APK και επιταχύνει τη φόρτωση.

Τελευταία σταθερή έκδοση — 1.4.0 (Αύγουστος 2021). Η βιβλιοθήκη είναι σε λειτουργία υποστήριξης, καθώς με την ευρεία εξάπλωση του desugaring η ανάγκη για αυτήν μειώνεται, αλλά παραμένει σχετική για έργα με ελάχιστο API < 26.

Γιατί χρειάζεται backport java.time;

Πριν από την εμφάνιση του java.time στην Java 8 (2014), οι προγραμματιστές χρησιμοποιούσαν java.util.Date και java.util.Calendar. Αυτές οι κλάσεις έχουν σοβαρά μειονεκτήματα: η Date είναι μεταβλητή, η Calendar χρησιμοποιεί μη διαισθητικές σταθερές (Calendar.JANUARY = 0), και οι δύο κλάσεις δεν είναι thread-safe και είναι επιρρεπείς σε σφάλματα κατά την εργασία με ζώνες ώρας.

Η Joda-Time ήταν το de facto πρότυπο πριν από την Java 8, αλλά ο δημιουργός της Stephen Colebourne σχεδίασε την java.time ως επίσημη αντικατάσταση, βασισμένη στην εμπειρία της Joda-Time και λαμβάνοντας υπόψη τα μειονεκτήματά της. Το πακέτο java.time ενσωματώθηκε στο JDK 8, αλλά το Android δεν το έλαβε μέχρι το API 26.

ThreeTen-Backport — μεταφορά java.time σε Java 7, που δημιουργήθηκε από τον ίδιο συγγραφέα (Stephen Colebourne). Περιλαμβάνει όλες τις κύριες κλάσεις: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. Το ThreeTenABP προσαρμόζει αυτήν τη μεταφορά για Android, προσθέτοντας αρχικοποίηση μέσω AssetsManager και βελτιστοποίηση για κινητές συσκευές.

Έτσι, το ThreeTenABP επιτρέπει τη χρήση σύγχρονου API ημερομηνίας/ώρας σε συσκευές με Android 4.0+ (API 14+) χωρίς να χρειάζεται αναμονή για ενημέρωση λειτουργικού συστήματος.

Σύνδεση ThreeTenABP σε έργο Android

Η σύνδεση γίνεται σε δύο βήματα: προσθήκη εξάρτησης στο build.gradle (app-level) και αρχικοποίηση στην κλάση Application. Σημαντικό: Το ThreeTenABP απαιτεί compileSdk όχι μικρότερο από 21 και Gradle έκδοσης όχι μικρότερης από 4.0.

Η εξάρτηση προστίθεται στην ενότητα dependencies: implementation “com.jakewharton.threetenabp:threetenabp:1.4.0”. Από την κυκλοφορία 1.4.0, η βιβλιοθήκη δεν έχει ενημερωθεί, καθώς είναι σταθερή και καλύπτει όλες τις απαραίτητες περιπτώσεις.

Σύμφωνα με την επίσημη τεκμηρίωση, η βιβλιοθήκη περιλαμβάνει tzdata στο assets. Εάν η εφαρμογή έχει ήδη φάκελο assets με άλλα αρχεία, το ThreeTenABP συνυπάρχει σωστά με αυτά. Το μέγεθος του tzdata είναι περίπου 200 KB σε συμπιεσμένη μορφή.

groovy
// build.gradle (επίπεδο εφαρμογής)
android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
}

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

Αρχικοποίηση ThreeTenABP

Πριν από τη χρήση οποιασδήποτε κλάσης από το org.threeten.bp, πρέπει να αρχικοποιηθεί η βιβλιοθήκη. Η αρχικοποίηση γίνεται μία φορά στο Application.onCreate() μέσω κλήσης AndroidThreeTen.init(this).

Η αρχικοποίηση φορτώνει τα δεδομένα tzdata από το assets και ρυθμίζει το ρολόι συστήματος. Χωρίς κλήση init(), οι μέθοδοι now() θα πετάξουν εξαίρεση IllegalStateException με μήνυμα ότι η βιβλιοθήκη δεν έχει αρχικοποιηθεί.

Για δοκιμές μπορεί να χρησιμοποιηθεί AndroidThreeTen.init(applicationContext, zoneId) — υπερφόρτωση με ρητό καθορισμό ζώνης ώρας. Αυτό είναι χρήσιμο για προβλέψιμη συμπεριφορά δοκιμών. Εάν χρειάζεται μόνο βασική αρχικοποίηση χωρίς tzdata — χρησιμοποιήστε AndroidThreeTen.initWithoutFiles(context).

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

// Χρήση μετά την αρχικοποίηση
val today = LocalDate.now()
val now = LocalDateTime.now()

Ποιες κλάσεις είναι διαθέσιμες;

Το ThreeTenABP παρέχει όλες τις κύριες κλάσεις java.time, αλλά στο πακέτο org.threeten.bp. Το API είναι σχεδόν ταυτόσημο με το αρχικό java.time, γεγονός που απλοποιεί τη μετάβαση σε API 26+.

Κύριες κλάσεις:

  • LocalDate — ημερομηνία χωρίς ώρα και ζώνη ώρας
  • LocalTime — ώρα χωρίς ημερομηνία και ζώνη ώρας
  • LocalDateTime — ημερομηνία και ώρα χωρίς ζώνη ώρας
  • ZonedDateTime — ημερομηνία και ώρα με ζώνη ώρας
  • OffsetDateTime — ημερομηνία και ώρα με σταθερή μετατόπιση
  • OffsetTime — ώρα με σταθερή μετατόπιση
  • Instant — στιγμή χρόνου σε UTC
  • Duration — time-based διάρκεια
  • Period — date-based περίοδος
  • DateTimeFormatter — μορφοποίηση και ανάλυση
  • ZoneId / ZoneOffset — ζώνες ώρας

Υποστηρίζονται επίσης βοηθητικές κλάσεις: Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. Οι ζώνες ώρας παρέχονται μαζί με τη βιβλιοθήκη (IANA tzdata). Η έκδοση tzdata στο ThreeTenABP 1.4.0 αντιστοιχεί στο 2021a.

ThreeTenABP εναντίον desugaring

Από το Android Gradle Plugin 4.0 (2020) και desugar_jdk_libs, οι προγραμματιστές απέκτησαν τη δυνατότητα χρήσης java.time σε όλες τις εκδόσεις Android μέσω coreLibraryDesugaring. Το Desugaring μετασχηματίζει τον bytecode έτσι ώστε οι κλήσεις java.time λειτουργούν σε παλιά API χωρίς πρόσθετες βιβλιοθήκες.

Πλεονεκτήματα desugaring: χρησιμοποιείται το αρχικό πακέτο java.time (όχι org.threeten.bp), δεν απαιτεί αρχικοποίηση, πλήρης ενσωμάτωση με το Android Studio. Μειονεκτήματα: απαιτεί AGP 4.0+, προσθέτει χρόνο μεταγλώττισης, το μέγεθος APK μπορεί να αυξηθεί κατά 2-3 MB.

Το ThreeTenABP παραμένει η καλύτερη επιλογή για legacy έργα που δεν μπορούν να ενημερώσουν το AGP σε 4.0+, ή όπου το μέγεθος APK είναι κρίσιμο. Επίσης, το ThreeTenABP είναι πιο απλό στη ρύθμιση — μία εξάρτηση και μία γραμμή αρχικοποίησης είναι αρκετά. Σύμφωνα με το Stack Overflow (2024), περίπου το 30% των έργων με minSdk < 26 εξακολουθεί να χρησιμοποιεί ThreeTenABP αντί για desugaring.

Παραδείγματα χρήσης

Πρώτο παράδειγμα — εργασία με ημερομηνίες μέσω ThreeTenABP. Το API είναι ταυτόσημο με java.time, αλλά οι εισαγωγές προέρχονται από org.threeten.bp. Αυτό επιτρέπει τη σύνταξη κώδικα που μετά τη μετάβαση απαιτεί μόνο αλλαγή εισαγωγών.

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

Δεύτερο παράδειγμα — μορφοποίηση ημερομηνίας. Το DateTimeFormatter από org.threeten.bp λειτουργεί όπως στο 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)
}

Τρίτο παράδειγμα — εργασία με ZonedDateTime και μετατροπή μεταξύ ζωνών ώρας στο ThreeTenABP.

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

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

Μετάβαση από ThreeTenABP σε ενσωματωμένο java.time

Κατά την αύξηση του minSdk σε 26, μπορείτε να εγκαταλείψετε το ThreeTenABP και να μεταβείτε στο ενσωματωμένο java.time. Η διαδικασία μετάβασης περιλαμβάνει πολλά βήματα και απαιτεί προσεκτική δοκιμή.

Πρώτο βήμα — αντικατάσταση εισαγωγών. Οι εισαγωγές org.threeten.bp αλλάζουν σε java.time. Στις περισσότερες περιπτώσεις, τα ονόματα κλάσεων συμπίπτουν: LocalDate → java.time.LocalDate, ZonedDateTime → java.time.ZonedDateTime. Εξαίρεση αποτελεί το DateTimeFormatter — στο ThreeTenABP είναι στο org.threeten.bp.format, στο java.time — στο java.time.format.

Δεύτερο βήμα — αφαίρεση αρχικοποίησης. Η γραμμή AndroidThreeTen.init(this) δεν χρειάζεται πλέον, καθώς το java.time είναι ενσωματωμένο στο Android SDK. Αφαιρέστε την κλήση από το Application.onCreate() και την εξάρτηση από το build.gradle.

Τρίτο βήμα — αντικατάσταση εξάρτησης με desugaring, εάν το minSdk παραμένει κάτω από 26. Προσθέστε isCoreLibraryDesugaringEnabled = true στο compileOptions και την εξάρτηση desugar_jdk_libs. Αυτό θα εξασφαλίσει τη λειτουργία java.time σε παλιά API χωρίς ThreeTenABP. Σύμφωνα με το Google I/O (2023), το desugaring είναι η προτιμώμενη μέθοδος για νέα έργα.

groovy
// build.gradle — αντικατάσταση ThreeTenABP με desugaring
android {
    compileOptions {
        isCoreLibraryDesugaringEnabled = true
    }
}

dependencies {
    // Αφαίρεση: implementation “com.jakewharton.threetenabp:threetenabp:1.4.0”
    // Προσθήκη:
    "coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}

// Αφαίρεση AndroidThreeTen.init(this) από Application

Συχνές ερωτήσεις

Μπορεί το ThreeTenABP να χρησιμοποιηθεί μαζί με desugaring;

Τεχνικά — ναι, αλλά δεν έχει νόημα. Εάν χρησιμοποιείται desugaring, το ενσωματωμένο java.time είναι ήδη διαθέσιμο. Η χρήση και των δύο βιβλιοθηκών θα οδηγήσει σε διπλασιασμό κώδικα και αύξηση του μεγέθους APK. Επιλέξτε μία προσέγγιση για το έργο.

Γιατί το ThreeTenABP απαιτεί αρχικοποίηση στο Application;

Η αρχικοποίηση φορτώνει τα δεδομένα IANA Time Zone Database από το assets στη μνήμη. Σε τυπικό JDK, το tzdata είναι διαθέσιμο μέσω classpath, αλλά το Android χρησιμοποιεί AssetManager. Η μέθοδος init() αντιγράφει τα δεδομένα στον κατάλογο συστήματος, καθιστώντας τα διαθέσιμα για το ZoneId.

Ποιες εκδόσεις Android υποστηρίζει το ThreeTenABP;

Το ThreeTenABP υποστηρίζει API 14+ (Android 4.0 Ice Cream Sandwich και νεότερες). Για χρήση απαιτείται Java 8 compatibility (sourceCompatibility και targetCompatibility στο compileOptions). Σε API 26+, η βιβλιοθήκη δεν χρειάζεται — χρησιμοποιήστε το ενσωματωμένο java.time.

Πώς ενημερώνονται οι ζώνες ώρας στο ThreeTenABP;

Οι ζώνες ώρας παρέχονται μαζί με τη βιβλιοθήκη. Η έκδοση 1.4.0 περιλαμβάνει tzdata 2021a. Για ενημέρωση, πρέπει να ενημερωθεί η έκδοση ThreeTenABP ή να αντικατασταθεί χειροκίνητα το tzdata στο assets. Οι τελευταίες εκδόσεις tzdata μπορούν να ληφθούν από το αποθετήριο IANA ή μέσω ThreeTen-Backport.

Πώς δοκιμάζεται κώδικας με ThreeTenABP;

Για μοναδιαίες δοκιμές, χρησιμοποιήστε AndroidThreeTen.init(context, zoneId) με ρητό καθορισμό ζώνης. Για δοκιμές Robolectric — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). Για καθαρές δοκιμές JVM χωρίς Android — χρησιμοποιήστε απευθείας ThreeTen-Backport χωρίς ThreeTenABP.

Σύνοψη

  • ThreeTenABP — προσαρμογέας Android για ThreeTen-Backport, που παρέχει API java.time σε συσκευές με Android < 8 (API < 26).
  • Συνδέεται μέσω εξάρτησης Gradle com.jakewharton.threetenabp:threetenabp:1.4.0 και απαιτεί αρχικοποίηση AndroidThreeTen.init(this) στο Application.onCreate().
  • Χρησιμοποιεί το πακέτο org.threeten.bp αντί για java.time — το API είναι σχεδόν ταυτόσημο, γεγονός που απλοποιεί τη μετάβαση σε API 26+.
  • Κύριες κλάσεις: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter — όλες διαθέσιμες στο ThreeTenABP.
  • Με την εμφάνιση desugaring (AGP 4.0+) το ThreeTenABP έγινε προαιρετικό, αλλά παραμένει σχετικό για legacy έργα ή με περιορισμούς μεγέθους APK.
  • Κατά τη μετάβαση σε java.time, αντικαταστήστε τις εισαγωγές org.threeten.bp → java.time, αφαιρέστε το AndroidThreeTen.init() και αντικαταστήστε την εξάρτηση με desugar_jdk_libs.
  • Για δοκιμές, χρησιμοποιήστε AndroidThreeTen.init(context, zoneId) με ρητό καθορισμό ζώνης για προβλέψιμη συμπεριφορά.

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης