ThreeTenABP: 그것이 무엇인가, Android용 java.time 라이브러리

저자: IT Sectr 게시일: 2026-07-14 읽는 시간: 11 분

ThreeTenABP는 Android 8(API < 26) 미만 기기에서 java.time API(org.threeten.bp 패키지)를 제공하는 Android용 어댑터 라이브러리입니다. Jake Wharton(GitHub, 2023)의 사양에 따르면, 이 라이브러리는 ThreeTen-Backport 프로젝트의 래퍼로, 리소스 최적화와 AssetManager를 통한 tzdata 지원을 갖추어 Android에 맞게 적용되었습니다.

주요 사항

  • ThreeTenABP는 ThreeTen-Backport용 Android 어댑터로, API < 26에서 java.time을 제공합니다.
  • 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는 선택 사항이 되었으며 레거시 프로젝트에 사용됩니다.

ThreeTenABP란 무엇인가?

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.time 백포트가 필요한 이유는?

Java 8(2014)에서 java.time이 도입되기 전, 개발자는 java.util.Datejava.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를 사용할 수 있습니다.

Android 프로젝트에 ThreeTenABP 추가

추가는 두 단계로 이루어집니다: 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입니다.

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)를 호출하여 한 번 수행됩니다.

초기화는 assets에서 tzdata 데이터를 로드하고 시스템 시계를 설정합니다. 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 — 시간 기반 기간
  • Period — 날짜 기반 기간
  • DateTimeFormatter — 포맷팅 및 파싱
  • ZoneId / ZoneOffset — 시간대

헬퍼 클래스도 지원됩니다: Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. 시간대는 라이브러리에 번들로 포함됩니다(IANA tzdata). ThreeTenABP 1.4.0의 tzdata 버전은 2021a에 해당합니다.

ThreeTenABP vs desugaring

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는 설정도 더 쉽습니다 — 단 하나의 의존성과 한 줄의 초기화만 있으면 됩니다. Stack Overflow(2024)에 따르면, minSdk < 26인 프로젝트의 약 30%가 여전히 desugaring 대신 ThreeTenABP를 사용합니다.

사용 예제

첫 번째 예제는 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)
}

두 번째 예제는 날짜 포맷팅을 보여줍니다. org.threeten.bp의 DateTimeFormatter는 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)
}

세 번째 예제는 ThreeTenABP에서 ZonedDateTime 작업과 시간대 간 변환을 보여줍니다.

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에서 의존성을 제거하세요.

세 번째 단계는 minSdk가 26 미만으로 유지되는 경우 의존성을 desugaring으로 대체하는 것입니다. compileOptions에 isCoreLibraryDesugaringEnabled = true와 desugar_jdk_libs 의존성을 추가하세요. 이렇게 하면 ThreeTenABP 없이 오래된 API에서 java.time이 작동합니다. 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")
}

// Application에서 AndroidThreeTen.init(this) 제거

자주 묻는 질문

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 호환성이 필요합니다(compileOptions의 sourceCompatibility 및 targetCompatibility). API 26+에서는 라이브러리가 필요하지 않습니다 — 내장 java.time을 사용하세요.

ThreeTenABP에서 시간대를 어떻게 업데이트하나요?

시간대는 라이브러리에 번들로 포함됩니다. 버전 1.4.0에는 tzdata 2021a가 포함되어 있습니다. 업데이트하려면 ThreeTenABP 버전을 업데이트하거나 assets에서 tzdata를 수동으로 교체해야 합니다. 최신 tzdata 버전은 IANA 저장소 또는 ThreeTen-Backport를 통해 얻을 수 있습니다.

ThreeTenABP로 코드를 어떻게 테스트하나요?

단위 테스트의 경우 명시적 영역 지정과 함께 AndroidThreeTen.init(context, zoneId)를 사용하세요. Robolectric 테스트의 경우 — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). Android 없이 순수 JVM 테스트의 경우 — ThreeTenABP 없이 직접 ThreeTen-Backport를 사용하세요.

요약

  • ThreeTenABP는 ThreeTen-Backport용 Android 어댑터로, Android < 8(API < 26) 기기에서 java.time API를 제공합니다.
  • Gradle 의존성 com.jakewharton.threetenabp:threetenabp:1.4.0을 통해 추가되며 Application.onCreate()에서 AndroidThreeTen.init(this) 초기화가 필요합니다.
  • java.time 대신 org.threeten.bp 패키지 사용 — API가 거의 동일하여 API 26+로의 마이그레이션이 간단합니다.
  • 주요 클래스: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter — 모두 ThreeTenABP에서 사용 가능합니다.
  • desugaring(AGP 4.0+)의 등장으로 ThreeTenABP는 선택 사항이 되었지만 레거시 프로젝트나 APK 크기 제약이 있는 경우 여전히 중요합니다.
  • java.time으로 마이그레이션할 때 임포트 org.threeten.bp → java.time으로 변경, AndroidThreeTen.init() 제거, 의존성을 desugar_jdk_libs로 대체하세요.
  • 테스트를 위해 예측 가능한 동작을 위해 명시적 영역 지정과 함께 AndroidThreeTen.init(context, zoneId)를 사용하세요.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기