Swift中自定义DateComponents Comparable实现为何失效?
DateComponents 实现Comparable协议的错误原因分析
开发App时,我需要用DateComponents作为时分处理的桥梁,并且让它遵循Comparable协议以支持范围判断。最初我写了如下自定义实现:
extension DateComponents: Comparable { public static func < (lhs: DateComponents, rhs: DateComponents) -> Bool { return lhs.hour! < rhs.hour! || lhs.minute! < rhs.minute! } }
测试后发现,这个实现仅对整点的范围判断有效,包含分钟的时间(比如00:01、12:30、14:59等)无法被正确判定在设定范围内。改用基于Calendar的实现后问题解决:
extension DateComponents: Comparable { public static func < (lhs: DateComponents, rhs: DateComponents) -> Bool { let now = Date() let calendar = Calendar.current return calendar.date(byAdding: lhs, to: now)! < calendar.date(byAdding: rhs, to: now)! } }
原实现的错误原因
原实现的核心问题是时分比较的逻辑完全错误:
- 你用逻辑或(
||)连接小时和分钟的比较,这意味着只要小时小于对方,或者分钟小于对方,就判定当前DateComponents更小,完全违背了真实的时间先后规则。 - 举个反例:当
lhs是14:30、rhs是13:50时,lhs.hour(14)并不小于rhs.hour(13),但lhs.minute(30)小于rhs.minute(50),此时原逻辑会返回true,错误地认为14:30 < 13:50。 - 再比如
lhs是00:01、rhs是23:59,原逻辑会因为01 < 59返回true,但实际00:01是次日凌晨,时间上晚于23:59。
正确的时分比较逻辑应该是先比较小时,只有当小时相等时,再比较分钟,示例写法如下:
public static func < (lhs: DateComponents, rhs: DateComponents) -> Bool { guard let lhsHour = lhs.hour, let rhsHour = rhs.hour else { // 处理未设置小时的异常情况 return false } if lhsHour != rhsHour { return lhsHour < rhsHour } guard let lhsMinute = lhs.minute, let rhsMinute = rhs.minute else { // 处理未设置分钟的异常情况 return false } return lhsMinute < rhsMinute }
不过这种手动比较的写法仍存在隐患(比如强制解包的崩溃风险),而基于Calendar的实现借助系统日历的成熟逻辑,既正确处理了时间先后关系,又避免了手动写比较逻辑的漏洞。
内容的提问来源于stack exchange,提问作者Jordan Niedzielski
相关产品推荐
相关产品推荐

