Kotlin时间戳转相对时间描述

91 阅读2分钟

前言

本文基于 JDK 的 DateCalendar 实现了一种相对简洁的、用于将时间戳转为相对时间描述串的工具。

问题描述

每个 UGC 内容都有一个发布或修改时间,列表展示数据时,需要根据当前时间与发布时间的时间间隔计算出相对时间描述展示,通常其关系如下表(时间间隔计算要求精确到分钟级):

  1. 间隔小于 5 分钟,相对时间描述为:刚刚
  2. 间隔大于 5 分钟,但不超过 60 分钟:N分钟前,最早为 59 分钟前
  3. 间隔超过 1 个小时,但不超过 24 小时:N小时前,最早到 23 小时前
  4. 间隔超过 24 个小时,但不超过 48 小时,相对时间描述为:昨天
  5. 间隔超过 2 天,但不超过 7 天:N天前
  6. 间隔超过 2 天,但不超过 28 天:N周前
  7. 间隔超过 28 天,但不超过上个月的今天:4周前
  8. 间隔超过上一月的今天,但不超过去年本月的今天:N月前,最早到 11 月前
  9. 比去年今天更早的时间显示yyyy-MM-dd格式的年月日串

代码实现

根据上面的对照表,只需根据时间戳求得时间间隔值,并顺序对比;当间隔值超过 28 天时再利用 Clendar 取上月当日时间对比;对于超过 1 个月的再继续对比求月份,若最终超过了 12 个月则直接返回日期串。

object TimeUtil {
    private const val PER_MIN = 60 * 1000L
    private const val PER_HOUR = 60 * PER_MIN
    private const val PER_DAY = 24 * PER_HOUR
    private const val PER_WEEK = 7 * PER_DAY
    var sCurrent: Date? = null

    fun getRelativeDesc(timestamp: Long): String? {
        val inputDate = Date(timestamp)
        val cur: Date = sCurrent ?: Date()
        val delta: Long = cur.getTime() - inputDate.getTime()
        if (delta <= 5 * PER_MIN) {
            return "刚刚"
        }
        if (delta < PER_HOUR) {
            return (delta / PER_MIN).toString() + "分钟前"
        }
        if (delta < PER_DAY) {
            return (delta / PER_HOUR).toString() + "小时前"
        }
        if (delta < 2 * PER_DAY) {
            return "昨天"
        }
        if (delta < 7 * PER_DAY) {
            return (delta / PER_DAY).toString() + "天前"
        }
        if (delta < 4 * PER_WEEK) {
            return (delta / PER_WEEK).toString() + "周前"
        }
        val calendar = Calendar.getInstance()
        calendar.time = cur
        calendar.add(Calendar.MONTH, -1)
        var compareDelta: Long = cur.getTime() - calendar.time.time
        if (delta < compareDelta) {
            return "4周前"
        }
        for (i in 1..11) {
            calendar.add(Calendar.MONTH, -1)
            compareDelta = cur.getTime() - calendar.time.time
            if (delta < compareDelta) {
                return i.toString() + "月前"
            }
        }
        calendar.time = inputDate
        return calendar[Calendar.YEAR].toString() + '-' + String.format("%02d", calendar[Calendar.MONTH] + 1) +
                '-' + String.format("%02d", calendar[Calendar.DATE])
    }
}

测试驱动

object TimeUtil {

    @JvmStatic
    fun main(args: Array<String>) {
        val current = Calendar.getInstance()
        // 设置当前时间为 2024-4-10 22:45:0
        current[2024, Calendar.APRIL, 10, 22, 45] = 0
        current[Calendar.MILLISECOND] = 0
        TimeUtil.sCurrent = current.time

        val calendar = Calendar.getInstance()
        var y: Int
        var m: Int
        var d: Int
        var h: Int
        var min: Int
        var sec: Int
        var output: String?
        val cin = Scanner(System.`in`)
        // 输入格式形如: 2024 4 10 22 45 0
        while (cin.hasNext()) {
            y = cin.nextInt()
            m = cin.nextInt()
            d = cin.nextInt()
            h = cin.nextInt()
            min = cin.nextInt()
            sec = cin.nextInt()
            calendar[y, m - 1, d, h, min] = sec
            calendar[Calendar.MILLISECOND] = 0
            output = TimeUtil.getRelativeDesc(calendar.time.time)
            println(output)
        }
    }
}