虎の穴ラボ技術ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

Kotlinマルチプラットフォーム対応のDateTimeライブラリ「kotlinx-datetime」

こんにちは、虎の穴ラボの磯江です。
虎の穴ラボ Advent Calendar 2020 - Qiita2日目の記事になります。
1日目は奥谷さんがNuxtの記事を書いているので、読んでみてください。 toranoana-lab.hatenablog.com 3日目は大場さんのSEOについての記事です。 qiita.com

今回はKotlinマルチプラットフォームに対応したDateTimeAPIとして「kotlinx-datetime」ライブラリを紹介します。

github.com

2020年12月「kotlinx-datetime」は実験的なライブラリです。今後、APIの内容は変更される可能性があります。

Kotlin/JVMで日時や日付を扱う場合、java.timeパッケージのLocalDateTimeやLocalDateを利用するのが一般的です。

import java.time.LocalDate
import java.time.LocalDateTime

fun main() {
   val currentDateTime: LocalDateTime = LocalDateTime.now()
   val currentDate: LocalDate = LocalDate.now()

   println("Current DateTime: $currentDateTime")
   println("Current Date: $currentDate")
}

しかし、Kotlin/NativeやKotlin/JSではjava.timeAPIは利用できないため、プロジェクト毎に日付を扱うライブラリが異なるのが現状です。
そこで新しいDateTimeAPI「kotlinx-datetime」がKotlin1.4.0のリリースに合わせて公開されました。

プロジェクトに導入する

GradleとMavenを利用して「kotlinx-datetime」をプロジェクトに導入することができます。 2020年12月時点ではjCenterで公開されていないため、独自リポジトリを設定する必要があります。

Gradleを利用する場合

repositories {
   maven(url = "https://kotlin.bintray.com/kotlinx/")
}
dependencies {
  implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.1.1")
}

※Kotlin/JSプラットフォームではデフォルトでSYSTEMタイムゾーンのみ使用できます。すべてのタイムゾーンを利用したい場合はjs-jodaを利用する必要があります。

kotlin {
    sourceSets {
        val jsMain by getting {
            dependencies {
                implementation(npm("@js-joda/timezone", "2.3.0"))
            }
        }
    }
}

Mevenを利用する場合

<repositories>
   <repository>
       <snapshots>
           <enabled>false</enabled>
       </snapshots>
       <id>kotlinx</id>
       <name>kotlinx</name>
       <url>https://kotlin.bintray.com/kotlinx/</url>
   </repository>
</repositories>
<dependencies>
   <dependency>
       <groupId>org.jetbrains.kotlinx</groupId>
       <artifactId>kotlinx-datetime-jvm</artifactId>
       <version>0.1.1</version>
   </dependency>
</dependencies>

現在日時を取得する

import kotlinx.datetime.Clock

fun main() {
   val currentMoment = Clock.System.now()
   println(currentMoment) // 2020-12-02T06:25:22.008Z
}

Clock.System.now()を呼び出すことでUTC(世界標準時)を取得できます。

タイムゾーンを指定した日時を取得する

import kotlinx.datetime.*

fun main() {
   val currentMoment: Instant = Clock.System.now()
   val datetimeInUtc: LocalDateTime = currentMoment.toLocalDateTime(TimeZone.UTC)
   val datetimeInSystemZone: LocalDateTime = currentMoment.toLocalDateTime(TimeZone.currentSystemDefault())

   println("LocalDateTimeInUTC:$datetimeInUtc") // LocalDateTimeInUTC:2020-12-02T06:57:16.812
   println("LocalDateTimeInSystemZone:$datetimeInSystemZone") // LocalDateTimeInSystemZone:2020-12-12T15:57:16.812
}

先程利用したClock.System.now()で取得したInstantクラスのtoLocalDateTimeメソッドを利用することで、タイムゾーンを指定した日時(LocalDateTime)に変換することができます。
任意のタイムゾーンを指定したい場合にはTimeZoneクラスを利用して、タイムゾーン指定を行います。

import kotlinx.datetime.*

fun main() {
   val currentMoment: Instant = Clock.System.now()
   val tzBerlin = TimeZone.of("Europe/Berlin")
   val datetimeInBerlin = currentMoment.toLocalDateTime(tzBerlin)

   println("LocalDateTimeInBerlin:$datetimeInBerlin") // LocalDateTimeInBerlin:2020-12-02T08:57:11.125
}

任意の日時を取得する

import kotlinx.datetime.*

fun main() {
   val kotlinReleaseDateTime = LocalDateTime(2016, 2, 15, 16, 57, 0, 0)
   println("KotlinReleaseDateTime:$kotlinReleaseDateTime")  // KotlinReleaseDateTime:2016-02-15T16:57
}

LocalDateTimeクラスには年月日時分秒ミリ秒を指定可能なコンストラクタが用意されています。
また、Stringクラスが拡張されており、ISO-8601形式で記述した日時の文字列をLocalDateTimeに変換することもできます。

import kotlinx.datetime.*

fun main() {
   val dateTimeFromString = "2010-06-01T22:19:44".toLocalDateTime()
   println("DateTimeFromString:$dateTimeFromString") // DateTimeFromString:2010-06-01T22:19:44
}

現在日付を取得する

現在日付を取得するにはLocalDateクラスを利用します。

import kotlinx.datetime.*

fun main() {
   val today: LocalDate = Clock.System.todayAt(TimeZone.currentSystemDefault())
   println("Today is $today") // Today is 2020-12-02
}

任意の日付を取得する

LocalDateTimeと同様にLocalDateクラスにも年月日を指定可能なコンストラクタが用意されています。

import kotlinx.datetime.*

fun main() {
   val knownDate = LocalDate(2020, 2, 21)
   println("KnownDate:$knownDate") // KnownDate:2020-02-21
}

ISO-8601形式で記述した日付の文字列をLocalDateTに変換するStringの拡張メソッドもあります。

import kotlinx.datetime.*

fun main() {
   val localDateFromString = "2010-06-01".toLocalDate()
   println("LocalDateFromString:$localDateFromString")  // LocalDateFromString:2010-06-01
}

日時計算をする

LocalDateTimeクラスには日時計算用にplusメソッドが用意されています。

import kotlinx.datetime.*

fun main() {
   val now = Clock.System.now()
   val systemTZ = TimeZone.currentSystemDefault()
   val tomorrow = now.plus(1, DateTimeUnit.DAY, systemTZ)
   val threeYearsAndAMonthLater = now.plus(DateTimePeriod(years = 3, months = 1), systemTZ)
   println("Now:$now, Tomorrow:$tomorrow, ThreeYearsAndMonthLater:$threeYearsAndAMonthLater")
   // Now:2020-12-02T09:19:05.999Z, Tomorrow:2020-12-02T09:19:05.999Z, ThreeYearsAndMonthLater:2024-01-02T09:19:05.999Z
}

期間を表すDateTimePeriodクラスを利用した日付計算も可能です。

日付計算をする

LocalDateクラスにもplusメソッドが用意されています。

import kotlinx.datetime.*

fun main() {
   val today = Clock.System.todayAt(TimeZone.currentSystemDefault())
   val yesterday = today.plus(-1, DateTimeUnit.DAY)
   val threeYearsAndAMonthBefore = today.plus(DatePeriod(years = -3, months = -1))
   println("Now:$today, Yesterday:$yesterday, ThreeYearsAndAMonthBefore:$threeYearsAndAMonthBefore")
   // Now:2020-12-02, Yesterday:2020-12-01, ThreeYearsAndAMonthBefore:2017-11-02
}

まとめ

  • kotlinx-datetimeライブラリの最新バージョンはv0.1.1
    • API変更の可能性があるのでプロダクトでの利用はまだ早い
  • いつかはこのライブラリを利用するのがスタンダードになる(かも)
    • 今のうちにチェックしておくと、正式リリース後の導入がスムーズに?