ThreeTenABP: چیست، کتابخانه java.time برای Android

نویسنده: IT Sectr منتشر شده: 2026-07-14 زمان مطالعه: 11 دقیقه

ThreeTenABP — کتابخانه آداپتور برای Android، ارائه‌دهنده API java.time (بسته org.threeten.bp) در دستگاه‌های با Android زیر ۸ (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) دارد.
  • به جای java.time از بسته org.threeten.bp استفاده می‌کند — 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 تا نسخه ۸ (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 relevant است.

چرا به 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 کمتر از ۲۱ و Gradle نسخه کمتر از ۴.۰ نیاز دارد.

وابستگی در بخش dependencies اضافه می‌شود: implementation «com.jakewharton.threetenabp:threetenabp:1.4.0». از زمان انتشار 1.4.0 کتابخانه به‌روزرسانی نشده است، زیرا پایدار است و تمام موارد لازم را پوشش می‌دهد.

بر اساس مستندات رسمی، کتابخانه شامل tzdata در assets است. اگر برنامه از قبل پوشه assets با فایل‌های دیگر دارد، ThreeTenABP به درستی با آنها همزیستی می‌کند. اندازه tzdata حدود ۲۰۰ کیلوبایت در حالت فشرده است.

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) استفاده کرد — overload با مشخص کردن صریح منطقه زمانی. این برای رفتار قابل پیش‌بینی تست‌ها مفید است. اگر فقط مقداردهی اولیه پایه بدون 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 — مدت زمان بر اساس زمان
  • Period — مدت زمان بر اساس تاریخ
  • 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 بایت‌کد را به گونه‌ای تبدیل می‌کند که فراخوانی‌های java.time در APIهای قدیمی بدون کتابخانه‌های اضافی کار کنند.

مزایای desugaring: استفاده از بسته اصلی java.time (نه org.threeten.bp)، عدم نیاز به مقداردهی اولیه، یکپارچگی کامل با Android Studio. معایب: نیاز به AGP 4.0+، افزایش زمان ساخت، اندازه APK ممکن است ۲-۳ مگابایت افزایش یابد.

ThreeTenABP بهترین انتخاب برای پروژه‌های legacy باقی می‌ماند که نمی‌توانند AGP را به ۴.۰+ به‌روزرسانی کنند، یا جایی که اندازه APK بحرانی است. همچنین ThreeTenABP در تنظیمات ساده‌تر است — یک وابستگی و یک خط مقداردهی اولیه کافی است. طبق Stack Overflow (2024)، حدود ۳۰٪ از پروژه‌های با minSdk < 26 هنوز از ThreeTenABP به جای desugaring استفاده می‌کنند.

نمونه‌های استفاده

اولین نمونه — کار با تاریخ‌ها از طریق ThreeTenABP. API مشابه java.time است، اما importها از org.threeten.bp می‌آیند. این امکان نوشتن کدی را فراهم می‌کند که پس از مهاجرت فقط نیاز به تغییر importها دارد.

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 به ۲۶ می‌توان از ThreeTenABP صرف نظر کرده و به java.time داخلی مهاجرت کرد. فرآیند مهاجرت شامل چند مرحله است و نیاز به تست دقیق دارد.

اولین مرحله — جایگزینی importها. importهای 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 زیر ۲۶ باقی بماند. 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 قابل دسترس می‌سازد.

ThreeTenABP از چه نسخه‌های Android پشتیبانی می‌کند؟

ThreeTenABP از API 14+ (Android 4.0 Ice Cream Sandwich و بالاتر) پشتیبانی می‌کند. برای استفاده Java 8 compatibility (sourceCompatibility و targetCompatibility در compileOptions) لازم است. در API 26+ کتابخانه نیاز نیست — از java.time داخلی استفاده کنید.

چگونه مناطق زمانی را در ThreeTenABP به‌روز کنیم؟

مناطق زمانی به همراه کتابخانه ارائه می‌شوند. نسخه ۱.۴.۰ شامل 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 همچنان relevant است.
  • در مهاجرت به java.time، importهای org.threeten.bp → java.time را جایگزین کنید، AndroidThreeTen.init() را حذف کرده و وابستگی را به desugar_jdk_libs تغییر دهید.
  • برای تست از AndroidThreeTen.init(context, zoneId) با مشخص کردن صریح منطقه برای رفتار قابل پیش‌بینی استفاده کنید.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید