時間の測定
Kotlin標準ライブラリには、さまざまな単位で時間を計算し測定するためのツールが用意されています。 正確な時間測定は、以下のようなアクティビティにとって重要です。
- スレッドやプロセスの管理
- 統計情報の収集
- タイムアウトの検出
- デバッグ
デフォルトでは、時間は単調増加するタイムソース(monotonic time source)を使用して測定されますが、他のタイムソースも設定可能です。 詳細は「タイムソースの作成」を参照してください。
期間の計算
時間の量を表現するために、標準ライブラリにはDurationクラスがあります。Durationは、DurationUnit enumクラスの以下の単位で表現できます。
NANOSECONDSMICROSECONDSMILLISECONDSSECONDSMINUTESHOURSDAYS
Durationは、正、負、ゼロ、正の無限大、負の無限大のいずれかになります。
期間の作成
Durationを作成するには、Int、Long、Double型で利用可能な拡張プロパティであるnanoseconds、microseconds、milliseconds、seconds、minutes、hours、daysを使用します。
日(Days)は24時間の期間を指します。カレンダー上の日付ではありません。
例:
import kotlin.time.*
import kotlin.time.Duration.Companion.nanoseconds
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.days
fun main() {
val fiveHundredMilliseconds: Duration = 500.milliseconds
val zeroSeconds: Duration = 0.seconds
val tenMinutes: Duration = 10.minutes
val negativeNanosecond: Duration = (-1).nanoseconds
val infiniteDays: Duration = Double.POSITIVE_INFINITY.days
val negativeInfiniteDays: Duration = Double.NEGATIVE_INFINITY.days
println(fiveHundredMilliseconds) // 500ms
println(zeroSeconds) // 0s
println(tenMinutes) // 10m
println(negativeNanosecond) // -1ns
println(infiniteDays) // Infinity
println(negativeInfiniteDays) // -Infinity
}Durationオブジェクトを使って基本的な算術演算を行うこともできます。
import kotlin.time.*
import kotlin.time.Duration.Companion.seconds
fun main() {
val fiveSeconds: Duration = 5.seconds
val thirtySeconds: Duration = 30.seconds
println(fiveSeconds + thirtySeconds)
// 35s
println(thirtySeconds - fiveSeconds)
// 25s
println(fiveSeconds * 2)
// 10s
println(thirtySeconds / 2)
// 15s
println(thirtySeconds / fiveSeconds)
// 6.0
println(-thirtySeconds)
// -30s
println((-thirtySeconds).absoluteValue)
// 30s
}文字列表現の取得
Durationの文字列表現を持つことは、それを印刷、シリアライズ、転送、または保存できるため、有用です。
文字列表現を取得するには、.toString()関数を使用します。デフォルトでは、時間は存在する各単位を使用して報告されます。例: 1h 0m 45.677s または -(6d 5h 5m 28.284s)
出力を設定するには、.toString()関数で目的のDurationUnitと小数点以下の桁数を関数パラメータとして使用します。
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.DurationUnit
fun main() {
// Print in seconds with 2 decimal places
println(5887.milliseconds.toString(DurationUnit.SECONDS, 2))
// 5.89s
}ISO-8601互換の文字列を取得するには、toIsoString()関数を使用します。
import kotlin.time.Duration.Companion.seconds
fun main() {
println(86420.seconds.toIsoString()) // PT24H0M20S
}期間の変換
Durationを異なるDurationUnitに変換するには、以下のプロパティを使用します。
inWholeNanosecondsinWholeMicrosecondsinWholeSecondsinWholeMinutesinWholeHoursinWholeDays
例:
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes
fun main() {
val thirtyMinutes: Duration = 30.minutes
println(thirtyMinutes.inWholeSeconds)
// 1800
}あるいは、目的のDurationUnitを以下の拡張関数の関数パラメータとして使用することもできます。
.toInt().toDouble().toLong()
例:
import kotlin.time.Duration.Companion.seconds
import kotlin.time.DurationUnit
fun main() {
println(270.seconds.toDouble(DurationUnit.MINUTES))
// 4.5
}期間の比較
Durationオブジェクトが等しいかどうかを確認するには、等価演算子(==)を使用します。
import kotlin.time.Duration
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes
fun main() {
val thirtyMinutes: Duration = 30.minutes
val halfHour: Duration = 0.5.hours
println(thirtyMinutes == halfHour)
// true
}Durationオブジェクトを比較するには、比較演算子(<、>)を使用します。
import kotlin.time.Duration.Companion.microseconds
import kotlin.time.Duration.Companion.nanoseconds
fun main() {
println(3000.microseconds < 25000.nanoseconds)
// false
}期間をコンポーネントに分解する
Durationをその時間コンポーネントに分解し、さらにアクションを実行するには、toComponents()関数のオーバーロードを使用します。目的のアクションを関数またはラムダ式として関数パラメータに追加します。
例:
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes
fun main() {
val thirtyMinutes: Duration = 30.minutes
println(thirtyMinutes.toComponents { hours, minutes, _, _ -> "${hours}h:${minutes}m" })
// 0h:30m
}この例では、ラムダ式は、未使用のsecondsとnanosecondsパラメータに対してアンダースコア(_)を使用して、hoursとminutesを関数パラメータとして持ちます。この式は、文字列テンプレートを使用して連結された文字列を返し、hoursとminutesの目的の出力形式を取得します。
時間の測定
時間の経過を追跡するために、標準ライブラリは以下のことを簡単に行えるツールを提供します。
- 目的のタイムユニットでコードの実行にかかる時間を測定します。
- ある時点をマークします。
- 2つの時点を比較および減算します。
- 特定の時点からどれくらいの時間が経過したかを確認します。
- 現在の時間が特定の時点を過ぎたかどうかを確認します。
コード実行時間の測定
コードブロックの実行にかかる時間を測定するには、measureTimeインライン関数を使用します。
import kotlin.time.measureTime
fun main() {
val timeTaken = measureTime {
Thread.sleep(100)
}
println(timeTaken) // e.g. 103 ms
}コードブロックの実行にかかる時間を測定し、そのコードブロックの値を返すには、インライン関数measureTimedValueを使用します。
例:
import kotlin.time.measureTimedValue
fun main() {
val (value, timeTaken) = measureTimedValue {
Thread.sleep(100)
42
}
println(value) // 42
println(timeTaken) // e.g. 103 ms
}デフォルトでは、どちらの関数も単調増加するタイムソースを使用します。
時点をマークする
特定の時点をマークするには、TimeSourceインターフェースとmarkNow()関数を使用してTimeMarkを作成します。
import kotlin.time.*
fun main() {
val timeSource = TimeSource.Monotonic
val mark = timeSource.markNow()
}時間の差を測定する
同じタイムソースからのTimeMarkオブジェクト間の差を測定するには、減算演算子(-)を使用します。
同じタイムソースからのTimeMarkオブジェクトを比較するには、比較演算子(<、>)を使用します。
例:
import kotlin.time.*
fun main() {
val timeSource = TimeSource.Monotonic
val mark1 = timeSource.markNow()
Thread.sleep(500) // Sleep 0.5 seconds.
val mark2 = timeSource.markNow()
repeat(4) { n ->
val mark3 = timeSource.markNow()
val elapsed1 = mark3 - mark1
val elapsed2 = mark3 - mark2
println("Measurement 1.${n + 1}: elapsed1=$elapsed1, elapsed2=$elapsed2, diff=${elapsed1 - elapsed2}")
}
println(mark2 > mark1) // This is true, as mark2 was captured later than mark1.
// true
}期限が過ぎたか、タイムアウトに達したかを確認するには、hasPassedNow()とhasNotPassedNow()拡張関数を使用します。
import kotlin.time.*
import kotlin.time.Duration.Companion.seconds
fun main() {
val timeSource = TimeSource.Monotonic
val mark1 = timeSource.markNow()
val fiveSeconds: Duration = 5.seconds
val mark2 = mark1 + fiveSeconds
// It hasn't been 5 seconds yet
println(mark2.hasPassedNow())
// false
// Wait six seconds
Thread.sleep(6000)
println(mark2.hasPassedNow())
// true
}タイムソース
デフォルトでは、時間は単調増加するタイムソースを使用して測定されます。単調増加するタイムソースは、常に前方へ進み、タイムゾーンのような変動の影響を受けません。単調増加する時間(monotonic time)の代替として、経過実時間(elapsed real time)があり、これはウォールクロック時間(wall-clock time)とも呼ばれます。経過実時間は、別の時点を基準として測定されます。
プラットフォームごとのデフォルトタイムソース
この表は、各プラットフォームにおける単調増加する時間のデフォルトソースについて説明しています。
| プラットフォーム | ソース |
|---|---|
| Kotlin/JVM | System.nanoTime() |
| Kotlin/JS (Node.js) | process.hrtime() |
| Kotlin/JS (browser) | window.performance.now() or Date.now() |
| Kotlin/Native | std::chrono::high_resolution_clock or std::chrono::steady_clock |
タイムソースの作成
異なるタイムソースを使用したい場合もあるでしょう。例えばAndroidでは、System.nanoTime()はデバイスがアクティブな間のみ時間をカウントします。デバイスがディープスリープに入ると、時間の追跡ができなくなります。デバイスがディープスリープ中でも時間を追跡し続けるには、SystemClock.elapsedRealtimeNanos()を使用するタイムソースを作成できます。
object RealtimeMonotonicTimeSource : AbstractLongTimeSource(DurationUnit.NANOSECONDS) {
override fun read(): Long = SystemClock.elapsedRealtimeNanos()
}次に、そのタイムソースを使用して時間測定を行うことができます。
fun main() {
val elapsed: Duration = RealtimeMonotonicTimeSource.measureTime {
Thread.sleep(100)
}
println(elapsed) // e.g. 103 ms
}kotlin.timeパッケージの詳細については、標準ライブラリAPIリファレンスを参照してください。
