前言
本文基于 JDK 的
Date和Calendar实现了一种相对简洁的、用于将时间戳转为相对时间描述串的工具。
问题描述
每个 UGC 内容都有一个发布或修改时间,列表展示数据时,需要根据当前时间与发布时间的时间间隔计算出相对时间描述展示,通常其关系如下表(时间间隔计算要求精确到分钟级):
- 间隔小于 5 分钟,相对时间描述为:
刚刚 - 间隔大于 5 分钟,但不超过 60 分钟:
N分钟前,最早为 59 分钟前 - 间隔超过 1 个小时,但不超过 24 小时:
N小时前,最早到 23 小时前 - 间隔超过 24 个小时,但不超过 48 小时,相对时间描述为:
昨天 - 间隔超过 2 天,但不超过 7 天:
N天前 - 间隔超过 2 天,但不超过 28 天:
N周前 - 间隔超过 28 天,但不超过上个月的今天:
4周前 - 间隔超过上一月的今天,但不超过去年本月的今天:
N月前,最早到 11 月前 - 比去年今天更早的时间显示
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)
}
}
}