时间测量与 Duration API
源:Kotlin standard library - Duration
长期以来,Java 开发者习惯使用 System.currentTimeMillis() 或 System.nanoTime() 来处理时间间隔和性能测量。这些 API 返回原始的 long 类型,单位不明确(毫秒?纳秒?),且容易混淆。
Kotlin 标准库引入了 kotlin.time 包,提供了一套类型安全、直观且强大的时间处理 API。
性能计时 (Measuring Time)
这是最常用的功能。不再需要手动记录 start 和 end 然后相减。
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()最佳实践
- 废弃 Long 类型时间:在 API 设计中,凡是表示“持续时间”或“超时”的参数,一律使用
Duration类型,而不是Long。这消除了“这个 Long 是毫秒还是秒?”的歧义。 - 使用 Monotonic:进行性能打点、超时计算时,始终依赖
measureTime或TimeSource.Monotonic,避免使用System.currentTimeMillis(),后者可能会回拨。