ThreeTenABP は、Android 8(API < 26)未満のデバイスにjava.time API(org.threeten.bpパッケージ)を提供するAndroid用アダプターライブラリです。Jake Wharton(GitHub、2023)の仕様によると、このライブラリはThreeTen-Backportプロジェクトのラッパーであり、リソース最適化とAssetManagerを通じたtzdataサポートを備えてAndroid向けに適応されています。
重要なポイント
ThreeTenABP(ThreeTen Android Backport)は、Jake Whartonによって作成されたライブラリで、古いAndroidバージョンでJava 8の日時APIを使用するためのものです。これはThreeTen-Backportプロジェクトのアダプターであり、java.time(JSR-310)をJava 7およびAndroid API < 26に移植します。
このライブラリが解決する主な問題:Androidバージョン8(API 26)以前は、java.timeが標準配布に含まれていませんでした。開発者はjava.util.Date/Calendarを使用するか、Joda-Timeを追加する必要がありました。ThreeTenABPは、組み込みのjava.timeと同じ最新のAPIを提供しますが、org.threeten.bpパッケージを介して提供します。
GitHubリポジトリ(2023)によると、このライブラリはAndroid向けに最適化されています:tzdata(IANA Time Zone Database)はassetsに保存され、デスクトップのようにclasspathではなくAssetManagerを介してロードされます。これによりAPKサイズが削減され、ロードが高速化されます。
最新の安定版は1.4.0(2021年8月)です。このライブラリはメンテナンスモードにあり、desugaringの広範な採用に伴い必要性は減少していますが、最小API < 26のプロジェクトでは依然として重要です。
Java 8(2014年)でjava.timeが導入される前、開発者はjava.util.Dateとjava.util.Calendarを使用していました。これらのクラスには深刻な欠点があります:Dateは可変、Calendarは直感的でない定数を使用(Calendar.JANUARY = 0)、両方のクラスはスレッドセーフではなく、タイムゾーンを扱う際にエラーが発生しやすいです。
Joda-TimeはJava 8以前のデファクトスタンダードでしたが、その作成者Stephen Colebourneは、Joda-Timeの経験とその欠点に対処した上で、java.timeを公式の代替として設計しました。java.timeパッケージはJDK 8に含まれていましたが、AndroidはAPI 26までそれを受け取りませんでした。
ThreeTen-Backportは、同じ著者(Stephen Colebourne)によって作成されたjava.timeのJava 7への移植です。主要なクラスをすべて含みます:LocalDate、LocalTime、LocalDateTime、ZonedDateTime、Instant、Duration、Period、DateTimeFormatter。ThreeTenABPはこの移植をAndroid向けに適応し、AssetsManagerを介した初期化とモバイルデバイス向けの最適化を追加します。
したがって、ThreeTenABPを使用すると、OSのアップデートを待つことなく、Android 4.0+(API 14+)のデバイスで最新の日時APIを使用できます。
追加は2つのステップで行います:build.gradle(アプリレベル)に依存関係を追加し、Applicationクラスで初期化します。重要:ThreeTenABPには少なくとも21のcompileSdkと少なくとも4.0のGradleバージョンが必要です。
依存関係はdependenciesセクションに追加されます:implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"。1.4.0のリリース以降、ライブラリは更新されていません。安定しており、必要なすべてのケースをカバーしているためです。
公式ドキュメントによると、ライブラリにはassetsにtzdataが含まれています。アプリにすでに他のファイルを含むassetsフォルダがある場合、ThreeTenABPはそれらと正しく共存します。tzdataのサイズは圧縮状態で約200KBです。
// build.gradle(アプリレベル)
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
}
org.threeten.bpのクラスを使用する前に、ライブラリを初期化する必要があります。初期化はApplication.onCreate()でAndroidThreeTen.init(this)を呼び出して1回実行されます。
初期化はassetsからtzdataデータをロードし、システムクロックを設定します。init()を呼び出さないと、now()メソッドはライブラリが初期化されていないというメッセージとともにIllegalStateExceptionをスローします。
テスト用には、AndroidThreeTen.init(applicationContext, zoneId)を使用できます — 明示的なタイムゾーン指定を伴うオーバーロードです。これはテストで予測可能な動作に役立ちます。tzdataなしで基本的な初期化のみが必要な場合は、AndroidThreeTen.initWithoutFiles(context)を使用してください。
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+への移行を容易にします。
主要なクラス:
ヘルパークラスもサポートされています:Clock、DayOfWeek、Month、Year、YearMonth、MonthDay。タイムゾーンはライブラリにバンドルされています(IANA tzdata)。ThreeTenABP 1.4.0のtzdataバージョンは2021aに対応しています。
Android Gradle Plugin 4.0(2020年)とdesugar_jdk_libs以降、開発者はcoreLibraryDesugaringを介してすべてのAndroidバージョンでjava.timeを使用できるようになりました。Desugaringはバイトコードを変換し、追加のライブラリなしで古いAPIでjava.time呼び出しが機能するようにします。
Desugaringの利点:元のjava.timeパッケージを使用(org.threeten.bpではない)、初期化不要、Android Studioとの完全統合。欠点:AGP 4.0+が必要、ビルド時間が増加、APKサイズが2-3MB増加する可能性があります。
ThreeTenABPは、AGPを4.0+に更新できないレガシープロジェクト、またはAPKサイズが重要な場合に最適な選択肢であり続けています。ThreeTenABPはセットアップも簡単です — たった1つの依存関係と1行の初期化です。Stack Overflow(2024)によると、minSdk < 26のプロジェクトの約30%が今でもdesugaringの代わりにThreeTenABPを使用しています。
最初の例は、ThreeTenABPを使用した日付操作を示しています。APIはjava.timeと同じですが、インポートはorg.threeten.bpからになります。これにより、移行後にインポートの置き換えのみが必要なコードを書くことができます。
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)
}
2番目の例は日付のフォーマットを示しています。org.threeten.bpのDateTimeFormatterはjava.timeと同じように動作します。
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)
}
3番目の例は、ThreeTenABPでのZonedDateTimeの操作とタイムゾーン間の変換を示しています。
import org.threeten.bp.ZonedDateTime
import org.threeten.bp.ZoneId
fun convertTimeZone(
time: ZonedDateTime,
targetZone: ZoneId
): ZonedDateTime {
return time.withZoneSameInstant(targetZone)
}
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にあります。
2番目のステップは初期化の削除です。AndroidThreeTen.init(this)の行はもはや必要ありません。java.timeはAndroid SDKに組み込まれているためです。Application.onCreate()から呼び出しを削除し、build.gradleから依存関係を削除してください。
3番目のステップは、minSdkが26未満のままの場合、依存関係をdesugaringに置き換えることです。compileOptionsでisCoreLibraryDesugaringEnabled = trueとdesugar_jdk_libs依存関係を追加します。これにより、ThreeTenABPなしで古いAPIでjava.timeが動作することが保証されます。Google I/O(2023)によると、desugaringは新しいプロジェクトの推奨アプローチです。
// 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")
}
// ApplicationからAndroidThreeTen.init(this)を削除
よくある質問
技術的には — はい、しかし意味がありません。desugaringが使用されている場合、組み込みのjava.timeはすでに利用可能です。両方のライブラリを使用すると、コードの重複とAPKサイズの増加につながります。プロジェクトに一つのアプローチを選択してください。
初期化は、IANA Time Zone Databaseをassetsからメモリにロードします。標準JDKでは、tzdataはclasspathを介して利用可能ですが、AndroidはAssetManagerを使用します。init()メソッドはデータをシステムディレクトリにコピーし、ZoneIdが利用できるようにします。
ThreeTenABPはAPI 14+(Android 4.0 Ice Cream Sandwich以上)をサポートしています。Java 8互換性が必要です(compileOptionsのsourceCompatibilityとtargetCompatibility)。API 26+では、ライブラリは不要です — 組み込みのjava.timeを使用してください。
タイムゾーンはライブラリにバンドルされています。バージョン1.4.0にはtzdata 2021aが含まれています。更新するには、ThreeTenABPのバージョンを更新するか、assets内のtzdataを手動で置き換える必要があります。最新のtzdataバージョンは、IANAリポジトリまたはThreeTen-Backportから入手できます。
単体テストには、明示的なゾーン指定でAndroidThreeTen.init(context, zoneId)を使用してください。Robolectricテストには — AndroidThreeTen.init(ApplicationProvider.getApplicationContext())。Androidなしの純粋なJVMテストには — ThreeTenABPなしで直接ThreeTen-Backportを使用してください。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。