用Kotlin Duration来优化时间运算

用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.dayslong.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开发的各个知识点。
img
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题

图片

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值