Kotlin 标准库为你提供了一些工具, 使用不同的单位计算和测量时间. 精确的时间测量对下面这些活动是非常重要的:
计算持续时间
为了代表一段时间, 标注库提供了 Duration
类. 一个 Duration
可以使用 DurationUnit
枚举类中的下面这些单位来表达:
NANOSECONDS
MICROSECONDS
MILLISECONDS
SECONDS
MINUTES
HOURS
DAYS
一个 Duration
可以是正值, 负值, 0, 正无穷, 或负无穷.
创建持续时间
要创建一个 Duration
, 请使用 Int
, Long
, 和 Double
类型的 扩展属性: nanoseconds
, microseconds
, milliseconds
, seconds
, minutes
, hours
, 和 days
.
示例:
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() {
//sampleStart
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
//sampleEnd
}
你也可以对 Duration
对象进行基本的算数运算:
import kotlin.time.*
import kotlin.time.Duration.Companion.seconds
fun main() {
//sampleStart
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
//sampleEnd
}
获取字符串表达
得到 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() {
//sampleStart
// 使用秒单位, 2 位小数
println(5887.milliseconds.toString(DurationUnit.SECONDS, 2))
// 输出结果为 5.89s
//sampleEnd
}
要得到 ISO-8601 兼容 的字符串, 请使用 toIsoString()
函数:
import kotlin.time.Duration.Companion.seconds
fun main() {
//sampleStart
println(86420.seconds.toIsoString()) // 输出结果为 PT24H0M20S
//sampleEnd
}
转换持续时间
要把你的 Duration
转换为不同的 DurationUnit
, 请使用以下属性:
inWholeNanoseconds
inWholeMicroseconds
inWholeSeconds
inWholeMinutes
inWholeHours
inWholeDays
示例:
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes
fun main() {
//sampleStart
val thirtyMinutes: Duration = 30.minutes
println(thirtyMinutes.inWholeSeconds)
// 输出结果为 1800
//sampleEnd
}
或者, 你也可以使用下面的扩展函数, 以你希望的 DurationUnit
作为函数参数:
.toInt()
.toDouble()
.toLong()
示例:
import kotlin.time.Duration.Companion.seconds
import kotlin.time.DurationUnit
fun main() {
//sampleStart
println(270.seconds.toDouble(DurationUnit.MINUTES))
// 输出结果为 4.5
//sampleEnd
}
比较持续时间
要检查 Duration
对象是否相等, 请使用相等操作符 (==
):
import kotlin.time.Duration
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes
fun main() {
//sampleStart
val thirtyMinutes: Duration = 30.minutes
val halfHour: Duration = 0.5.hours
println(thirtyMinutes == halfHour)
// 输出结果为 true
//sampleEnd
}
要比较 Duration
对象, 请使用比较操作符 (<
, >
):
import kotlin.time.Duration.Companion.microseconds
import kotlin.time.Duration.Companion.nanoseconds
fun main() {
//sampleStart
println(3000.microseconds < 25000.nanoseconds)
// 输出结果为 false
//sampleEnd
}
将持续时间分解为不同的部分
要将一个 Duration
分解为不同的时间组成部分, 并进行后续的操作, 请使用 toComponents()
函数的重载版本. 将你希望执行的后续操作, 以函数或 Lambda 表达式的形式, 作为 toComponents()
函数的参数.
示例:
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes
fun main() {
//sampleStart
val thirtyMinutes: Duration = 30.minutes
println(thirtyMinutes.toComponents { hours, minutes, _, _ -> "${hours}h:${minutes}m" })
// 输出结果为 0h:30m
//sampleEnd
}
在上面的示例中, Lambda 表达式使用 hours
和 minutes
作为参数, 另外还有下划线 (_
) 对用于未使用的参数 seconds
和 nanoseconds
. Lambda 表达式使用 字符串模板, 得到所需要的 hours
和 minutes
的输出格式, 最后返回拼接的字符串.
测量时间
为了跟踪时间的流逝, 标准库提供了工具, 以便你可以轻松的完成以下任务:
测量代码的执行时间
要测量执行一段代码消耗的时间, 请使用内联函数 measureTime
:
import kotlin.time.measureTime
fun main() {
//sampleStart
val timeTaken = measureTime {
Thread.sleep(100)
}
println(timeTaken) // 例如 103 ms
//sampleEnd
}
要测量执行一段代码消耗的时间, 并且 返回这段代码的执行结果, 请使用内联函数 measureTimedValue
.
示例:
import kotlin.time.measureTimedValue
fun main() {
//sampleStart
val (value, timeTaken) = measureTimedValue {
Thread.sleep(100)
42
}
println(value) // 输出结果为 42
println(timeTaken) // 例如 103 ms
//sampleEnd
}
默认情况下, 这两个函数使用一个单调时间源(monotonic time source).
标记一个时刻
要标记一个特定的时刻, 请使用 TimeSource
接口, 和 markNow()
函数 来创建一个 TimeMark
:
import kotlin.time.*
fun main() {
val timeSource = TimeSource.Monotonic
val mark = timeSource.markNow()
}
测量时刻之间的差异
要测量来自同一个时间源的 TimeMarks
对象之间的差异, 请使用减法操作符 (-
).
要比较来自同一个时间源的 TimeMark
对象, 请使用比较操作符 (<
, >
).
示例:
import kotlin.time.*
fun main() {
//sampleStart
val timeSource = TimeSource.Monotonic
val mark1 = timeSource.markNow()
Thread.sleep(500) // 睡眠 0.5 秒.
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) // 比较结果为 true, 因为 mark2 是在 mark1 之后捕获的.
// 输出结果为 true
//sampleEnd
}
要检查是否已经经过了某个截止时刻, 或者是否已经到达超时时间, 请使用 hasPassedNow()
和 hasNotPassedNow()
扩展函数:
import kotlin.time.*
import kotlin.time.Duration.Companion.seconds
fun main() {
//sampleStart
val timeSource = TimeSource.Monotonic
val mark1 = timeSource.markNow()
val fiveSeconds: Duration = 5.seconds
val mark2 = mark1 + fiveSeconds
// 还没有经过 5 秒
println(mark2.hasPassedNow())
// 输出结果为 false
// 等待 6 秒
Thread.sleep(6000)
println(mark2.hasPassedNow())
// 输出结果为 true
//sampleEnd
}
时间源
默认情况下, 会使用一个单调时间源(monotonic time source)测量时间. 单调时间源只会向前移动, 不会受系统变化的影响, 比如时区变化. 单调时间的替代方案是流逝的真实时间(elapsed real time), 也叫做挂钟时间(wall-clock time). 流逝的真实时间是相对于另一个时间点来测量的.
各个平台的默认时间源
下表是各个平台的默认单调时间源:
平台 | 时间源 |
---|
Kotlin/JVM | System.nanoTime()
|
Kotlin/JS (Node.js) | process.hrtime()
|
Kotlin/JS (browser) | window.performance.now() 或 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) // 例如 103 ms
}
关于 kotlin.time
包, 更多详情请参见我们的 标准库 API 参考文档.