feiyu02
2025-03-27 bde043c8fd1a076f44c402dd56c62d401afbfb16
src/main/kotlin/com/flightfeather/uav/common/utils/TimeUtil.kt
@@ -1,34 +1,152 @@
package com.flightfeather.uav.common.utils
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.time.Duration
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
import kotlin.math.max
import kotlin.math.min
/**
 * @author riku
 * Date: 2019/9/16
 */
class TimeUtil {
object TimeUtil {
    companion object {
        /**
         * 是否是第二天或更新的时间
         */
        fun isNextDay(oldTime: Date, newTime: Date): Boolean {
            val oldC = Calendar.getInstance().apply {
                time = oldTime
            }
            val newC = Calendar.getInstance().apply {
                time = newTime
            }
    /**
     * 是否是第二天或更新的时间
     */
    fun isNextDay(oldTime: Date, newTime: Date): Boolean {
        val oldC = Calendar.getInstance().apply {
            time = oldTime
        }
        val newC = Calendar.getInstance().apply {
            time = newTime
        }
            return when {
                newC[Calendar.YEAR] > oldC[Calendar.YEAR] -> true
                newC[Calendar.YEAR] == oldC[Calendar.YEAR] -> newC[Calendar.DAY_OF_YEAR] > oldC[Calendar.DAY_OF_YEAR]
                else -> false
            }
        return when {
            newC[Calendar.YEAR] > oldC[Calendar.YEAR] -> true
            newC[Calendar.YEAR] == oldC[Calendar.YEAR] -> newC[Calendar.DAY_OF_YEAR] > oldC[Calendar.DAY_OF_YEAR]
            else -> false
        }
    }
    /**
     * 获取某段时间在每日中的时段
     * "凌晨 0 - 6", "早上 6 - 9", "上午 9 - 12", "中午 12 - 14", "下午 14 - 17", "傍晚 17 - 20", "夜间 20 - 0"
     * 当这段时间跨越了时段时,按照60%的时间所在时段为最终时段,否则采用后一个时段
     * @return 时段和时段的起止时间 <时段, 开始时间, 结束时间>
     */
    fun getDayTimeTag(start: Date, end: Date): Triple<String, Date, Date>? {
        var sLocal = LocalDateTime.ofInstant(start.toInstant(), ZoneId.systemDefault())
        var eLocal = LocalDateTime.ofInstant(end.toInstant(), ZoneId.systemDefault())
        val duration = Duration.between(sLocal, eLocal)
        if (duration.toDays() > 1) return null
        if (duration.isNegative) {
            val temp = sLocal
            sLocal = eLocal
            eLocal = temp
        }
        val sDay = sLocal.dayOfMonth
        val eDay = eLocal.dayOfMonth
        val ranges = listOf(
            Triple(0, 6, "凌晨"), Triple(6, 9, "早上"),
            Triple(9, 12, "上午"), Triple(12, 14, "中午"),
            Triple(14, 17, "下午"), Triple(17, 20, "傍晚"), Triple(20, 24, "夜间")
        )
        val periodList = mutableListOf<Pair<Triple<String, Date, Date>, Long>>()
        if (sDay < eDay) {
            val dayStart = sLocal.plusDays(1).withHour(0).withMinute(0).withSecond(0)
            val firstRange = sLocal to dayStart
            val secondRange = dayStart to eLocal
            ranges.forEachIndexed { i, r ->
                // 判断时间范围是否和该时段有交集
                checkPeriodTime(firstRange.first, firstRange.second, r.first to r.second)?.let {
                    val t = firstRange.first.withMinute(0).withSecond(0)
                    periodList.add(
                        Triple(
                            r.third,
                            Date.from(t.withHour(r.first).atZone(ZoneId.systemDefault()).toInstant()),
                            if (r.second == 24) {
                                Date.from(
                                    t.withHour(0).plusDays(1).minusSeconds(1)
                                        .atZone(ZoneId.systemDefault()).toInstant()
                                )
                            } else {
                                Date.from(t.withHour(r.second).atZone(ZoneId.systemDefault()).toInstant())
                            }
                        ) to it.toMinutes()
                    )
                }
                checkPeriodTime(secondRange.first, secondRange.second, r.first to r.second)?.let {
                    val t = secondRange.first.withMinute(0).withSecond(0)
                    periodList.add(
                        Triple(
                            r.third,
                            Date.from(t.withHour(r.first).atZone(ZoneId.systemDefault()).toInstant()),
                            if (r.second == 24) {
                                Date.from(
                                    t.withHour(0).plusDays(1).minusSeconds(1)
                                        .atZone(ZoneId.systemDefault()).toInstant()
                                )
                            } else {
                                Date.from(t.withHour(r.second).atZone(ZoneId.systemDefault()).toInstant())
                            }
                        ) to it.toMinutes()
                    )
                }
            }
        } else {
            val range = sLocal to eLocal
            ranges.forEachIndexed { i, r ->
                // 判断时间范围是否和该时段有交集
                checkPeriodTime(range.first, range.second, r.first to r.second)?.let {
                    val t = range.first.withMinute(0).withSecond(0)
                    periodList.add(
                        Triple(
                            r.third,
                            Date.from(t.withHour(r.first).atZone(ZoneId.systemDefault()).toInstant()),
                            if (r.second == 24) {
                                Date.from(
                                    t.withHour(0).plusDays(1).minusSeconds(1)
                                        .atZone(ZoneId.systemDefault()).toInstant()
                                )
                            } else {
                                Date.from(t.withHour(r.second).atZone(ZoneId.systemDefault()).toInstant())
                            }
                        ) to it.toMinutes()
                    )
                }
            }
        }
        if (periodList.isEmpty()) return null
        periodList.sortByDescending { it.second }
        val maxOne = periodList.first()
        return maxOne.first
    }
    private fun checkPeriodTime(start: LocalDateTime, end: LocalDateTime, hourRange: Pair<Int, Int>): Duration? {
        return if (start.hour in hourRange.first..hourRange.second) {
            Duration.between(
                start,
                end.withHour(min(hourRange.second, end.hour)).withMinute(0).withSecond(0)
            )
        } else if (start.hour < hourRange.first && end.hour > hourRange.second) {
            Duration.between(
                start.withHour(hourRange.first).withMinute(0).withSecond(0),
                end.withHour(hourRange.second).withMinute(0).withSecond(0),
            )
        } else if (end.hour in hourRange.first..hourRange.second) {
            Duration.between(
                start.withHour(max(hourRange.first, start.hour)).withMinute(0).withSecond(0),
                end,
            )
        } else {
            null
        }
    }
}