Swift中如何检测字符串格式的日期范围是否重叠?
核心问题解答
1. 是否需要将字符串转为日期对象?
必须转,直接比较字符串存在严重的可靠性问题:
- 只有严格符合「年-月-日-时-分-秒」固定长度、固定时区、无格式变体的字符串才能按字符顺序对齐比较,只要出现格式差异(比如部分带毫秒、部分带时区、日期写为月/日/年格式),字符串比较结果会完全错误
- Date类型原生支持日期区间计算、时差计算等操作,不需要自己解析字符串逻辑,出错概率低
2. 重叠检测实现步骤
步骤1:统一处理日期转换
建议在JSON解析阶段就将字符串转为Date类型,避免后续重复转换消耗性能。如果确实要保留String类型的属性,可以加计算属性做转换:
import Foundation struct Event { let title: String let startDate: String let endDate: String // 全局共用同一个Formatter避免重复创建消耗性能 private static let dateFormatter: ISO8601DateFormatter = { let formatter = ISO8601DateFormatter() // 如果是自定义日期格式,换成DateFormatter并设置对应参数 // let formatter = DateFormatter() // formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" // formatter.timeZone = TimeZone(identifier: "Asia/Shanghai") // formatter.locale = Locale(identifier: "zh_CN_POSIX") return formatter }() var startDateValue: Date? { Self.dateFormatter.date(from: startDate) } var endDateValue: Date? { Self.dateFormatter.date(from: endDate) } }
步骤2:按开始日期排序
先过滤掉日期转换失败的异常数据,再按startDate升序排列:
let validEvents = originalEvents.filter { $0.startDateValue != nil && $0.endDateValue != nil } .sorted { $0.startDateValue! < $1.startDateValue! }
步骤3:检测重叠事件
因为已经按开始日期排序,只需要逐个和前一个事件比较即可,时间复杂度为O(n):
var overlappingPairs: [(Event, Event)] = [] // 事件数小于2不需要检测 guard validEvents.count > 1 else { return } for i in 1..<validEvents.count { let preEvent = validEvents[i-1] let currentEvent = validEvents[i] // 重叠判断逻辑:当前事件的开始时间 < 前一个事件的结束时间 // 如果允许首尾相接(比如A18:00结束 B18:00开始不算重叠)就用<,否则用<= if currentEvent.startDateValue! < preEvent.endDateValue! { overlappingPairs.append((preEvent, currentEvent)) } }
逻辑说明
通用的两个时间区间重叠的判断条件为:区间A的开始 < 区间B的结束 && 区间B的开始 < 区间A的结束,可以覆盖所有重叠场景:
- 前一个事件未结束,后一个就开始
- 后一个事件完全包含在前一个事件内
- 两个事件完全重合
如果需要在UITableView中展示重叠警告,可以在上述遍历过程中给涉及重叠的事件加上重叠标记,后续cellForRow时直接读取标记展示对应的警告样式即可,不需要每次滚动都重复计算。
内容的提问来源于stack exchange,提问作者Fernando Ivan Perez Ruiz
相关产品推荐
相关产品推荐

