用Kotlin Duration来优化时间运算
kotlin.time.Duration
是 Kotlin 标准库中的一个类,用于表示时间度量,它可以用于计算时间差等场景。该类提供了一些方便的方法来创建、比较和操作时间间隔。 先带入一个需求看看Duration
是如何简单的优雅的实现的:
计算3天后的时间戳
//不使用Duration
@Test
fun time_millis() {
val currentTimeMillis = System.currentTimeMillis()
//1天24小时 每小时60分钟 1分钟60秒 每秒1000毫秒
val millisOfOneDay: Long = 24 * 3600 * 1000
println("format:${currentTimeMillis + 3 * millisOfOneDay}")
}
//使用Duration
@Test
fun time_millis_duration() {
val milliseconds: Duration = System.currentTimeMillis().milliseconds
val feature = milliseconds + 3.days
println("format:${feature.toLong(DurationUnit.MILLISECONDS)}")
}
这样一对比Duration简化了时间单位换算的过程。尤其是较为复杂的时间运算和换算中会让你非常惊喜。一起来学习下kotlin的时间度量api吧。
如何创建Duration
创建Duration最方便是使用Int, Long, Double
的扩展属性: nanoseconds, microseconds, milliseconds, seconds, minutes, hours, days
。Duration 可以是正、负、零、正无穷大或负无穷大。示例:
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执行单位换算
DurationUnit
kotlin标准库中定义了DurationUnit
枚举类,表示支持的时间度量的单位
- NANOSECONDS
- MICROSECONDS
- MILLISECONDS
- SECONDS
- MINUTES
- HOURS
- DAYS
Duration 类中的一些方法可以接受DurationUnit
作为参数,以便在不同的时间单位之间进行转换。例如,可以使用toLong
方法将一个Duration对象转换为指定的时间单位(注意 时间戳 Duration.toInt
可能会精度不够),如下所示30分钟转换秒:
fun main() {
val duration = 30.minutes
val seconds = duration.toLong(DurationUnit.SECONDS)
println(seconds)
// 1800
}
inWhole 系列函数执行换算
当然kotlin还有更简单的实现方案,inWhole
系列扩展属性,正好应上面DurationUnit转换的单位,也是对上面的toLong(DurationUnit)
封装。
- inWholeNanoseconds
- inWholeMicroseconds
- inWholeMilliseconds
- inWholeSeconds
- inWholeMinutes
- inWholeHours
- inWholeDays
fun main() {
val duration = 30.minutes
println(duration.inWholeHours)
// 0
println(duration.inWholeSeconds)
// 1800
}
Duration执行运算
Duration支持四则运算和逻辑运算,先看看官方四则运算示例。
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对象无论当前是什么单位都可以互现运算
Duration对象无论当前是什么单位都可以互现运算
Duration对象无论当前是什么单位都可以互现运算
回头看看开头的例子,3.days
和long.milliseconds
可以直接相加而去计算时间戳,这确实大大简化了不同时间运算中单位换算的工作,太好用啦。
逻辑运算
比较 Duration 对象,使用比较运算符 (<, >,==)
:
fun main() {
val thirtyMinutes: Duration = 30.minutes
val halfHour: Duration = 0.5.hours
println(thirtyMinutes == halfHour)
// true
println(3000.microseconds < 25000.nanoseconds)
// false
}
分解计算
duration需要转换为其他对象时候,可以使用toComponents
来获得分解值来构造其他对象
val duration: Duration
val result = duration.toComponents { seconds, nanoseconds -> ... }
duration.toComponents { minutes, seconds, nanoseconds -> }
duration.toComponents { hours, minutes, seconds, nanoseconds -> }
duration.toComponents { days, hours, minutes, seconds, nanoseconds -> }
下面的示例是把时间转换为字符串 时分格式
@Test
fun kotlin_time_setup3() {
val thirtyMinutes: Duration = 78.minutes
println(thirtyMinutes.toComponents { hours, minutes, _, _ -> "${hours}h:${minutes}m" })
// 1h:18m
}
在lambda 表达式中未使用的参数可以用
_
来消除,当然了IDE也会提示你的。
获取字符串形式
获取字符串表示形式,以便您可以打印、序列化、传输或存储它。支持国际标准化组织的日期和时间的表示方法ISO 8601。为什么不叫格式化,因为不像DateFormatter支持Locale.setDefault()
之后可以输出多语言格式。
要获取字符串表示形式,请使用 .toString() 函数。 默认情况下,使用现有的每个单位报告时间。 例如:1h 0m 45.677s 或 -(6d 5h 5m 28.284s) 要配置输出,请使用 .toString(...)
函数,并将所需的 DurationUnit 和小数位数作为函数参数。.toIsoString()
输出_ISO 8601_时间格式:
@Test
fun kotlin_time_setup4() {
// Print in seconds with 2 decimal places
println(5887.milliseconds.toString(DurationUnit.SECONDS, 2))
// 5.89s
println(86420.seconds.toIsoString())
//PT24H0M20S
}
输出单位和对应的字符串代码源码如下:
internal fun DurationUnit.shortName(): String = when (this) {
DurationUnit.NANOSECONDS -> "ns"
DurationUnit.MICROSECONDS -> "us"
DurationUnit.MILLISECONDS -> "ms"
DurationUnit.SECONDS -> "s"
DurationUnit.MINUTES -> "m"
DurationUnit.HOURS -> "h"
DurationUnit.DAYS -> "d"
else -> error("Unknown unit: $this")
}
字符串形式转Duration
通过.toString(...)
和.toIsoString()
输出的字符串,可以通过parse
系列函数转为Duration。parseOrNull和parseIsoStringOrNull
可以保证解析失败时候空安全不会抛出异常。
@Test
fun kotlin_time_setup4() {
val duration = Duration.parse("5.89s")
println(duration.inWholeSeconds)
//5
val durationNullable = Duration.parseOrNull("5.89s")
durationNullable?.inWholeSeconds
val durationIso = Duration.parseIsoString("PT24H0M20S")
val durationIsoNullable = Duration.parseIsoStringOrNull("PT24H0M20S")
println(durationIso.inWholeSeconds)
//86420
}
实战案例
我们经常在社交APP中看到对发布内容的时间显示功能:“刚刚,2周前,2个月前”。那么这个功能在Duration来实现就非常简单了,这里就不讨论闰年和2月特殊情况。
@Test
fun kotlin_time_setup5() {
val serviceApiMillis = 1689015000000 //发布时的时间戳
val currentTimeMillis = System.currentTimeMillis()
val format = (currentTimeMillis - serviceApiMillis).milliseconds
.toComponents { days, hours, minutes, _, _ ->
when {
days > 365 -> "${days / 365}年前"
days > 30 -> "${days / 30}个月前"
days > 7 -> "${days / 7}周前"
days > 0 -> "${days}天前"
hours > 0 -> "${hours}小时前"
minutes > 0 -> "${minutes}分钟前"
else -> "刚刚"
}
}
println("format:$format")
}
总结
通过学习和实战总结一波,kotlin.time.Duration
可以帮助我们更简单的实现时间运算和转换,所以在工作中如果遇到时间换算和运算问题,第一时间先试试Duration
吧。
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)