🐾

[Kotlin]kotlinx-datetime v0.7.0の対応について

に公開

kotlinx.datetime v0.7.0

kotlinx-datetimeのv0.7.0がリリースされました。
リリースノートにある通り破壊的変更があるのでその対応方法についてメモします。

kotlinx.datetime.Instantkotlinx.datetime.Clockのエイリアスが追加されているので、v0.7.0からv0.7.1と段階的に移行するより一気にv0.7.1にアップデートする方が移行しやすいかと思います。
この記事ではv0.7.1について記載していきます。

主な変更点は以下です。

  • kotlinx.datetime.Instantkotlinx.datetime.Clockが非推奨になった
  • kotlin.time.Instantkotlin.time.Clockに変更する必要がある

kotlinx.datetime.Instantをゴリゴリに使っていたら変更点が多く移行は大変かと思いますが頑張っていきましょう。

注意点

kotlinx.serializationを同一プロジェクトで使用しており、kotlinx.datetime.InstantのJSONシリアライズなどをしている場合は、kotlinx.serialization1.9.0以上にしないといけません。
また、Androidで使う場合、2025年8月13日現在では最新のAndroid Gradle Pluginのバージョンは8.12.0となっており、対応するKotlinのバージョンは2.1.20となっています。
https://developer.android.com/build/releases/gradle-plugin?hl=ja

plugins {
    id("com.android.application") version "8.12.0" apply false
    id("com.android.library") version "8.12.0" apply false
    id("org.jetbrains.kotlin.android") version "2.1.20" apply false
}

kotlinx.serialization1.9.0はKotlinのバージョンが2.2以降が必須とされているので、KotlinやAGPのアップグレードが難しい場合はkotlinx-datetimev0.7.0以上にはしない方がいいかもしれません。

対応内容

バージョン指定

kotlinx-datetimeのバージョンを0.7.1にします。

VersionCatalog

[versions]
kotlinxDatetime = "0.7.1"
kotlinxSerializationJson = "1.9.0"

[libraries]
kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }

Gradle

implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")

筆者の環境ではkotlinx.serializationも使用しているためそちらも記載しました。

変更したら Sync Project with Gradle Files をします。

importの移行

import kotlinx.datetime.Instant // これを kotlin.time.Instant にreplace
import kotlinx.datetime.Clock // これを kotlin.time.Clock にreplace

IDEにAndroidStudioを使用している方は一括でreplace可能かと思います。
その後 BuildClean and Assemble Project with Testsを実行するとオプトインのエラーがでるかと思います。

ExperimentalTimeアノテーションの対応

Kotlinではまだ安定版ではないAPIを使う場合はアノテーションをオプトインする必要があります。
kotlin.time.Instantkotlin.time.Clockにはまだ安定版ではない時間関連のAPIとして@ExperimentalTimeがついています。
しかし、これらはすでに安定版としてリリースされており段階的に削除されるようです。
今はまだ残っているのでオプトインしないとコンパイルエラーになります。

設定方法としては以下の3種類があります。

// 1.ktファイル全体でオプトイン
@file:OptIn(ExperimentalTime::class) // .ktファイルの先頭1行目に書く

// 2. 関数レベルでオプトイン
@OptIn(ExperimentalTime::class)
fun someFunction(
    time: kotlin.time.Instant
) {
    val duration = measureTime {
        // 何らかの処理
    }
}

// 3. モジュール単位でオプトイン
// build.gradle.kts(ルート以外)
kotlinOptions {
    jvmTarget = "17"
    freeCompilerArgs += listOf(
        "-opt-in=kotlin.time.ExperimentalTime"
    )
}

実装箇所が少なければ1や2で済むかと思います。
たくさんある場合は3のモジュール単位でオプトインする方法が楽かと思います。
いずれKotlinのバージョンを上げたときにbuild.grale.ktsで非推奨の警告がでたら削除してください。

kotlinx.datetime.Instant

kotlinx.datetime.Instantの関連処理はkotlin.time.Instantには存在しないので移行する必要があります。

任意のパターンの文字列をInstant型に変換する処理で使われるFormatStringsInDatetimeFormatsを受け取るInstant.parse()は以下のように変更します。

// Before
@OptIn(FormatStringsInDatetimeFormats::class)
fun toInstant(
    time: String,
    pattern: String,
): Instant {
    val format = DateTimeComponents.Format { byUnicodePattern(pattern) }
    return Instant.parse(time, format)
}

// After
@OptIn(FormatStringsInDatetimeFormats::class)
fun toInstant(
    time: String,
    pattern: String,
): Instant {
    val format = LocalDateTime.Format { byUnicodePattern(pattern) } // DateTimeComponents を LocalDateTime に
    val ldt = LocalDateTime.parse(time, format) // LocalDateTimeに変換してからInstantにする
    return ldt.toInstant(TimeZone.currentSystemDefault())
}

StringLocalDateTimeに変換してkotlin.time.Instantに変換します。

kotlinx.datetime.LocalDate と LocalDateTime

fun toLocalDateTime(
    localDate: LocalDate,
): LocalDateTime {
    return LocalDateTime(
        year = localDate.year,
        monthNumber = localDate.monthNumber, // `month = localDate.month.number,` にする
        dayOfMonth = localDate.dayOfMonth, // `day = localDate.day,` にする
        hour = 0,
        minute = 0,
        second = 0,
        nanosecond = 0,
    )
}

kotlinx.serializationのkotlin.time.Instant対応

kotlinx.datetimeライブラリはKotlin standard library(kotlin.time.Instant)へ移行したのでkotlin.time.Instantのシリアライザは存在しません。
そのためkotlinx.serialization@Serializableが定義されているクラスのkotlin.time.Instantはそのままではシリアライズできません。

このあたりの詳しい内容はリリースノートに記載されています。
https://github.com/Kotlin/kotlinx.serialization/releases/tag/v1.9.0

例えば以下のようにkotlinx.serializationを使ったHTTPレスポンスでJSONを受け取りKotlinオブジェクトに変換するクラスが定義されている場合はこのように変更しないとコンパイルエラーになります。

// Before
@Serializable
data class HttpResponseGet(
    @SerialName(value = "id")
    val id: Int,
    @SerialName(value = "name")
    val name: String,
    @SerialName(value = "createdAt")
    val createdAt: kotlin.time.Instant,
)

// After
@Serializable
data class HttpResponseGet(
    @SerialName(value = "id")
    val id: Int,
    @SerialName(value = "name")
    val name: String,
    @SerialName(value = "createdAt")
    @Serializable(with = InstantComponentSerializer::class) // ←を追加する
    val createdAt: kotlin.time.Instant,
)

記事の最初の方でも記載してありますが、
AGP 8.12.0に対応しているKotlinのバージョンは2.1.20です。
しかし、kotlin.time.Instantのシリアライザ(InstantComponentSerializer)が含まれているのはkotlinx-serialization1.9.0です。
これにはKotlinのバージョンは2.2が必須とされています。
そのため現時点(2025年8月13日)のAndroidではまだこれらのライブラリのアップデートはしない方が無難かと思われます。

参考リンク

まとめ

以上でkotlinx-datetimeのアップデートはできるかと思います。
何か間違っているところやご意見などありましたらコメントいただけると助かります!

Discussion