如何生成避开指定时段的可用TimeSlot列表(Kotlin)
需求与问题
需要实现一个功能:生成从起始时间到结束时间的可用TimeSlot列表,需自动避开指定的休息时段。例如:起始时间09:00、结束时间17:00,每个时段15分钟,避开12:00-12:30,最终列表应包含09:00到12:00的所有15分钟时段,以及12:30到17:00的所有15分钟时段。
我使用java.time.LocalTime编写了Kotlin代码,但运行效果不符合预期,代码如下:
现有代码
TimeSlot数据类
data class TimeSlot( val startTime: LocalTime, val endTime: LocalTime, )
时段生成函数
private fun initializeSlots( slots: ArrayList<TimeSlot>, startTimeShift: LocalTime, appointmentDuration: Long, amountOfWorkingHours: Long, breakTime: LocalTime, breakDuration: Long ) { slots.add(TimeSlot(startTime = startTimeShift, endTime = startTimeShift.plusMinutes(appointmentDuration))) val possibleTotalAppointments = (amountOfWorkingHours * appointmentDuration) - 2 // -2 because index starts at 0 and first timeslot is already added. for (i in 0..(amountOfWorkingHours * appointmentDuration).toInt()) { if (slots[i].endTime == breakTime) { val endTimeOfBreak = breakTime.plusMinutes(breakDuration) val isTargetWithinTimeFrame = (!breakTime.isBefore(slots[i].startTime) && breakTime.isBefore(endTimeOfBreak)) if (isTargetWithinTimeFrame) { slots.remove(slots[i]) continue } } else { slots.add(TimeSlot(startTime = slots[i].endTime, endTime = slots[i].endTime.plusMinutes(appointmentDuration))) } } }
现有代码的问题
- 循环逻辑错误:用
amountOfWorkingHours * appointmentDuration作为循环上限完全不合理,无法准确计算实际应生成的时段数量,会导致生成过多或过少的时段。 - 休息时段处理逻辑缺陷:仅判断
slots[i].endTime == breakTime过于死板,若休息时间不是刚好卡在某个时段的结束时间,就无法正确识别并跳过;且删除列表元素后继续循环会引发索引越界问题。 - 参数设计不合理:使用
amountOfWorkingHours不如直接传入结束时间,既直观又能避免因工时计算导致的误差。
优化后的代码
调整参数为更直观的起始/结束时间,同时优化时段生成与休息跳过逻辑:
data class TimeSlot( val startTime: LocalTime, val endTime: LocalTime, ) private fun generateAvailableSlots( startTime: LocalTime, endTime: LocalTime, slotDurationMinutes: Long, breakStartTime: LocalTime, breakDurationMinutes: Long ): List<TimeSlot> { val slots = mutableListOf<TimeSlot>() val breakEndTime = breakStartTime.plusMinutes(breakDurationMinutes) var currentTime = startTime // 循环生成时段,直到当前时段结束时间超过工作结束时间 while (currentTime.plusMinutes(slotDurationMinutes) <= endTime) { val nextSlotEnd = currentTime.plusMinutes(slotDurationMinutes) // 检查当前时段是否与休息时段重叠 val overlapsWithBreak = currentTime < breakEndTime && nextSlotEnd > breakStartTime if (overlapsWithBreak) { // 跳过休息时段,直接将当前时间设置为休息结束时间 currentTime = breakEndTime } else { slots.add(TimeSlot(currentTime, nextSlotEnd)) currentTime = nextSlotEnd } } return slots }
代码说明
- 通过
while循环逐步推进当前时间,确保每个时段都在工作时间范围内。 - 每次生成时段前检查是否与休息时段重叠,重叠则直接跳到休息结束时间,避免生成无效时段。
- 参数设计更清晰,直接传入工作开始/结束时间,减少不必要的计算和错误。
内容的提问来源于stack exchange,提问作者xBullet
相关产品推荐
相关产品推荐

