Skip to content

时间测量与 Duration API

源:Kotlin standard library - Duration

长期以来,Java 开发者习惯使用 System.currentTimeMillis()System.nanoTime() 来处理时间间隔和性能测量。这些 API 返回原始的 long 类型,单位不明确(毫秒?纳秒?),且容易混淆。

Kotlin 标准库引入了 kotlin.time 包,提供了一套类型安全、直观且强大的时间处理 API。

性能计时 (Measuring Time)

这是最常用的功能。不再需要手动记录 startend 然后相减。

measureTime

测量代码块执行的耗时。返回的是 Duration 对象。

kotlin
import kotlin.time.measureTime

val timeTaken = measureTime {
    // 模拟耗时操作
    Thread.sleep(100)
    performHeavyCalculation()
}

println("操作耗时: $timeTaken") 
// 输出会自动格式化,例如: "105.4ms" 或 "2.1s"

measureTimedValue

如果你不仅想知道耗时,还想获取代码块的返回值,请使用此函数。

kotlin
import kotlin.time.measureTimedValue

val (result, duration) = measureTimedValue {
    // 计算并返回结果
    calculatePrimeNumber(1000)
}

println("计算结果: $result, 耗时: $duration")

单调时钟 (Monotonic Clock)

这些函数默认使用 TimeSource.Monotonic。这意味着它们不受系统时间调整(如用户修改时间、NTP 同步)的影响,保证了测量的准确性。

持续时间 (Duration)

Duration 是一个内联类(Value Class),用于表示两个时间点之间的时间量。它彻底解决了单位混乱的问题。

创建 Duration

利用 Kotlin 的扩展属性,创建时间变得非常符合直觉。

kotlin
import kotlin.time.Duration.Companion.seconds
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.milliseconds

val timeout = 30.seconds
val refreshRate = 500.milliseconds
val longPeriod = 1.5.minutes

算术运算

Duration 支持加减乘除和比较运算。

kotlin
val totalTime = 10.seconds + 500.milliseconds
val doubleTime = totalTime * 2

if (totalTime < 1.minutes) {
    println("Within a minute")
}

获取组件与转换

kotlin
val d = 65.minutes

println(d.inWholeHours)         // 1
println(d.inWholeMinutes)       // 65
println(d.inWholeSeconds)       // 3900

// 转换为特定单位的 Double 值
println(d.toDouble(DurationUnit.HOURS)) // 1.0833...

时间源 (TimeSource)

TimeSource 是时间的抽象来源。

标记时间点 (TimeMark)

除了测量一段代码,你也可以手动标记时间点。

kotlin
import kotlin.time.TimeSource

val clock = TimeSource.Monotonic
val mark = clock.markNow() // 记录当前时刻

// ... 执行一些操作 ...
Thread.sleep(200)

println("距离标记点已过去: ${mark.elapsedNow()}")

// 检查是否已过超时时间
val deadline = mark + 5.seconds
if (deadline.hasPassedNow()) {
    println("Timeout!")
}

与 Java 时间互操作

如果你在使用 Java 8+ 的 java.time API,Kotlin 提供了便捷的扩展函数进行转换。

kotlin
import kotlin.time.toJavaDuration
import kotlin.time.toKotlinDuration

val kDuration = 10.seconds
val jDuration: java.time.Duration = kDuration.toJavaDuration()

val backToKotlin = jDuration.toKotlinDuration()

最佳实践

  1. 废弃 Long 类型时间:在 API 设计中,凡是表示“持续时间”或“超时”的参数,一律使用 Duration 类型,而不是 Long。这消除了“这个 Long 是毫秒还是秒?”的歧义。
  2. 使用 Monotonic:进行性能打点、超时计算时,始终依赖 measureTimeTimeSource.Monotonic,避免使用 System.currentTimeMillis(),后者可能会回拨。