KotlinのDurationについて

採用はこちら

Kotlin の Duration は、時間の長さ(経過時間)を 型安全かつ可読性高く 扱うために設計された標準ライブラリのクラスです。

Android、サーバーサイド、Coroutine を用いた非同期処理において、現在では 事実上の標準 と言ってよい存在になっています。

本記事では、単なる使い方紹介に留まらず、

  • Duration が解決する問題
  • 正確な内部仕様(誤解されやすいポイント)
  • Coroutine・Java との関係
  • 実務での注意点・落とし穴

まで踏み込んで解説します。

目次

Duration とは何か

Durationkotlin.time パッケージ に含まれるクラスで、「◯秒」「◯分」といった 時間の長さそのもの を表します。

import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

なぜ Duration が必要なのか

従来のコードでは、以下のような問題がありました。

Thread.sleep(1000)
  • 1000 は「秒」なのか「ミリ秒」なのか分からない
  • 単位の取り違えが起こりやすい
  • 型安全でない(Long や Int のまま渡してしまう)

Duration単位を型として持たせる ことで、これらの問題を根本から解決します。

Duration の基本的な生成方法

拡張プロパティ(最も一般的)

val d1 = 1.seconds
val d2 = 500.milliseconds
val d3 = 2.minutes
val d4 = 1.hours

利用できる主な単位は以下の通りです。

単位プロパティ
ナノ秒nanoseconds
マイクロ秒microseconds
ミリ秒milliseconds
seconds
minutes
時間hours
days

1.seconds のように コードを読めば意味が分かる ことが、Duration 最大のメリットです。

文字列からの生成(設定ファイル向け)

val d = Duration.parse("1h 30m")
  • "10s", "500ms", "1h 30m" などが利用可能
  • toString() が出力する形式と互換

※ Kotlin 1.6 以降で安定利用可能です。

Duration の内部表現(重要)

Duration は「単純にナノ秒数を Long で持っている」わけではありません。

正確な説明

  • Duration1つの Long にエンコードされた内部表現を持つ
  • 値の大きさに応じて
    • ナノ秒精度
    • ミリ秒精度
      を自動的に切り替えて保持する
  • 表現可能な範囲を超えると Duration.INFINITE として扱われる

この設計により、

  • 小さい時間は高精度に
  • 非常に大きい時間も効率的に

扱えるようになっています。

Duration の計算(四則演算)

加算・減算

val total = 1.seconds + 500.milliseconds
val remain = 5.minutes - 30.seconds

乗算・除算

val doubled = 2.seconds * 2
val half = 10.seconds / 2

比較

if (1.seconds > 500.milliseconds) {
    println("長い")
}

すべて 単位を意識せず安全に計算可能 です。

単位変換

val d = 1500.milliseconds

d.inSeconds        // 1.5 (Double)
d.inWholeSeconds   // 1   (Long)
d.inMilliseconds   // 1500

注意点

  • inSecondsDouble(小数あり)
  • inWholeSeconds は切り捨て Long
  • Duration.INFINITE を変換すると
    Long.MAX_VALUE / Long.MIN_VALUE が返る場合がある

Coroutine との統合(必須知識)

Duration は Coroutine API と完全に統合 されています。

delay

delay(1.seconds)

withTimeout

withTimeout(3.seconds) {
    // 処理
}

withTimeoutOrNull

val result = withTimeoutOrNull(2.seconds) {
    heavyTask()
}

注意点

  • withTimeout0 以下の Duration を渡すと即タイムアウト
  • 処理がキャンセル可能である必要がある

Java との相互運用

Kotlin Duration と Java Duration は別物

KotlinJava
kotlin.time.Durationjava.time.Duration
拡張プロパティありなし
Coroutine と親和性高低い

相互変換

import java.time.Duration as JavaDuration

val kotlinDuration = 5.seconds
val javaDuration = kotlinDuration.toJavaDuration()

val back = javaDuration.toKotlinDuration()

重要な注意点

  • ±146年以内:ナノ秒精度で変換
  • それ以上:ミリ秒精度に丸めが発生する可能性あり

特殊な Duration 値

Duration.ZERO
Duration.INFINITE
(-5).seconds
  • ZERO:0秒
  • INFINITE:無限時間(タイムアウト無効化などに使用)
  • 負の Duration:比較・計算可能だが用途は慎重に

実務でよくある利用例

リトライ処理

val retryInterval = 500.milliseconds

repeat(3) {
    if (tryConnect()) return
    delay(retryInterval)
}

キャッシュの有効期限

val ttl = 10.minutes

if (now - cacheTime > ttl) {
    refresh()
}

よくある落とし穴

Double 経由で Thread.sleep する

Thread.sleep(duration.inSeconds.toLong()) // 危険

正しい方法

Thread.sleep(duration.inWholeMilliseconds)

days の注意点(見落とされがち)

1.days

これは 常に 24時間 を意味します。

  • 暦日
  • サマータイム(DST)
  • 日付境界

などは一切考慮されません。

「日付」ではなく「時間長」として理解する必要があります。

Duration を使うべき理由まとめ

  • 単位ミスを防げる
  • 可読性が圧倒的に高い
  • Coroutine と自然に連携できる
  • 保守性・レビュー性が向上する

まとめ

Kotlin の Duration は単なる便利クラスではなく、

  • 型安全な時間表現
  • 非同期処理の基盤
  • Java との橋渡し

という重要な役割を担っています。

以上、KotlinのDurationについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次