如何为1-52周的整数范围实现无重叠周期验证?
解决跨年周周期重叠验证的问题
嘿,这个跨年周的重叠验证坑我之前也碰到过!核心问题就是你现有的逻辑只处理了「起始周 ≤ 结束周」的常规连续周期(比如20-40),但碰到起始周 > 结束周的跨年周期(比如33-8,实际覆盖第33周到次年第8周)时,普通的区间重叠判断就完全失效了。
为啥原来的逻辑不管用?
常规的区间重叠判断(比如新起始 ≤ 旧结束 且 新结束 ≥ 旧起始)只适用于两个区间都在同一年度内的情况。但跨年周期其实是两个连续子区间的组合:[起始周, 52]加上[1, 结束周],这时候得换个思路判断重叠。
修复后的完整验证代码
我把逻辑拆成了三种场景,写了个可复用的判断方法,你直接替换原来的验证就行:
class Period < ApplicationRecord validate :period_cannot_overlap private def period_cannot_overlap # 排除当前记录,避免更新时把自己当成重叠周期 existing_periods = Period.where.not(id: id) existing_periods.each do |existing| if periods_overlap?(self, existing) errors.add(:base, "该周期与已存在的 #{existing.start_week}-#{existing.finish_week} 周期重叠") break # 找到一个重叠就停,不用堆一堆错误提示 end end end # 专门封装重叠判断逻辑,可读性更高 def periods_overlap?(current, existing) # 场景1:已有周期是跨年的(比如33-8) if existing.start_week > existing.finish_week # 新周期要么覆盖了[33,52],要么覆盖了[1,8],或者新周期本身也是跨年的(必然重叠) (current.finish_week >= existing.start_week) || (current.start_week <= existing.finish_week) || (current.start_week > current.finish_week) # 场景2:新周期是跨年的,已有周期是常规周期 elsif current.start_week > current.finish_week # 跨年的新周期要么覆盖已有周期的后半段,要么覆盖前半段 current.finish_week >= existing.start_week || current.start_week <= existing.finish_week # 场景3:两个都是常规非跨年周期,用经典的区间重叠判断 else current.start_week <= existing.finish_week && current.finish_week >= existing.start_week end end end
逻辑拆解,帮你理解
跨年周期 vs 常规周期:
- 如果已有周期是跨年的,新周期只要碰得到它的「后半段(33-52)」或者「前半段(1-8)」,或者新周期自己也是跨年的(俩跨年区间肯定有重叠),就算重叠。
- 如果新周期是跨年的,只要它的任意一段和已有常规周期有交集,就算重叠。
- 俩都是常规周期,就用最基础的区间重叠公式:你进我的范围,我进你的范围,就重叠。
排除当前记录:
where.not(id: id)这个很重要——当你更新一个已有周期时,不会把它自己当成“已存在的重叠周期”来判断。
测试一下这些场景
你可以用这些例子验证:
- 已有周期33-8,新周期35-40:触发重叠(碰了33-52的区间)
- 已有周期33-8,新周期5-10:触发重叠(碰了1-8的区间)
- 已有周期33-8,新周期9-32:不触发重叠(完全在中间的空白区间)
- 已有周期20-40,新周期30-35:触发重叠(常规场景正常工作)
这样修改后,跨年周期的重叠验证就没问题啦!
内容的提问来源于stack exchange,提问作者Tommy Tayler
相关产品推荐
相关产品推荐

