需求背景:
需求是用戶要創建一個任務計劃在未來執行,要求在創建任務計劃的時候判斷選擇的時間是否符合要求,否則不允許創建,創建的任務類型有兩種,一種是單次,任務只執行一次;另一種是周期,從周一到周日,任務可以重復執行。如果選擇單次執行,在選擇時間的時候要判斷選擇的時間是否大于當前時間,如果小于當前時間那么當前任務將不在當天執行而是第二天的同一時間執行,反之是在當天執行。確定好哪一天執行之后還要判斷那一天是否有已經創建的任務,如果有再判斷同一天的兩個時間點是否相差15分鐘,如果在15分鐘以內則時間發生碰撞不允許創建。如果選擇周期執行,也要和已經創建的單次任務或者周期任務進行時間檢查,另外兩個任務如果不在同一天執行,還要判斷在跨天時間點上是否相差15分鐘,比如周一晚上23:55和周二凌晨00:05相差10分鐘,也是屬于時間沖突,那么基于這個需求寫一下時間沖突的邏輯判斷。
最終調用函數獲取結果代碼:
val checkResult = mViewModel.checkTime(DateUtil.convertTimeToMinutes(startTimeStr),StringUtil.convertStringToList(cycleDay),vehReservationStandListBean,mPreBean?.keyId,)if (!checkResult.first) {"任務時間沖突,任務名稱: ${checkResult.second}, 請重新選擇時間點".showToast()return false}
具體檢查時間沖突邏輯:
(入參格式:newStartTime="11:30" --> 11*60+30,代表字符串格式hh:mm轉成分鐘數?
? newCycleDay = 0,1,2,3,4,5,6,7的list集合,list代表一個已經創建的任務數據體集合)
/*** 時間和周期是否允許創建 */fun checkTime(newStartTime: Int?,newCycleDay: List<Int>?,list: List<ReservationStandSetOperationBean>?,): Pair<Boolean, String?> {if (newStartTime == null || newCycleDay == null) {return Pair(false, "")}// 獲取新任務的時間段val newTimeSlots = DateUtil.getTimeSlots(newCycleDay, newStartTime)for (model in list ?: emptyList()) {val existingStartTime = DateUtil.convertTimeToMinutes(model.carReadyTime)val existingCycleDay = StringUtil.convertStringToList(model.cycleDay)if (existingStartTime == null || existingCycleDay == null) {continue}// 獲取已存在任務的時間段val existingTimeSlots = DateUtil.getTimeSlots(existingCycleDay, existingStartTime)// 檢查時間段是否重疊for (newSlot in newTimeSlots) {for (existingSlot in existingTimeSlots) {if (DateUtil.isTimeOverlap(newSlot, existingSlot)) {return Pair(false, model.planName)}}}}return Pair(true, "")}
?返回需要執行時間碰撞的數據集合:
// 獲取任務的執行日期和時間段fun getTimeSlots(days: List<Int>, startTime: Int): List<Triple<Int, Int, Int>> {val result = mutableListOf<Triple<Int, Int, Int>>()val minutesInDay = 24 * 60val calendar = Calendar.getInstance()val now = Date()val currentTime =calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE)val weekday = calendar.get(Calendar.DAY_OF_WEEK)val today = if (weekday == Calendar.SUNDAY) 7 else weekday - 1for (day in days) {//任務執行的日期var adjustedDay = day// 如果是單次任務 需要判斷是否需要加一天if (days == listOf(0)) {// 如果任務的開始時間小于當前時間,推遲到明天if (startTime <= currentTime) {adjustedDay = if (today == 7) 1 else today + 1} else {adjustedDay = today}}val endTime = startTime + 15// 如果任務跨天if (endTime >= minutesInDay) {// 當天的時間段 日期,起始時間,終止時間result.add(Triple(adjustedDay, startTime, minutesInDay))// 第二天的時間段 日期,起始時間,終止時間result.add(Triple(if (adjustedDay == 7) 1 else adjustedDay + 1,0,endTime - minutesInDay))} else {// 不跨天的時間段 日期,起始時間,終止時間result.add(Triple(adjustedDay, startTime, endTime))}}return result}
判斷兩個數據集合是否時間段有重疊:?
// 檢查時間段是否重疊fun isTimeOverlap(slot1: Triple<Int, Int, Int>, slot2: Triple<Int, Int, Int>): Boolean {// 如果日期不同,則不重疊if (slot1.first != slot2.first) {return false}// 檢查時間段是否重疊return slot1.second < slot2.third && slot2.second < slot1.third}
結語:實際項目中用到的算法邏輯大多不復雜,這種需要動態計算任務執行時間,還要考慮跨天的邏輯比較少見,這里做個記錄方便以后有類似邏輯可以做個代碼參考。