From bde043c8fd1a076f44c402dd56c62d401afbfb16 Mon Sep 17 00:00:00 2001
From: feiyu02 <risaku@163.com>
Date: 星期四, 27 三月 2025 17:29:48 +0800
Subject: [PATCH] 1. 新增卫星遥测网格热力图计算逻辑

---
 src/main/kotlin/com/flightfeather/uav/common/utils/TimeUtil.kt |  156 +++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 137 insertions(+), 19 deletions(-)

diff --git a/src/main/kotlin/com/flightfeather/uav/common/utils/TimeUtil.kt b/src/main/kotlin/com/flightfeather/uav/common/utils/TimeUtil.kt
index c02eb83..aa189e6 100644
--- a/src/main/kotlin/com/flightfeather/uav/common/utils/TimeUtil.kt
+++ b/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
+        }
+    }
 }
\ No newline at end of file

--
Gitblit v1.9.3