档期冲突怎么判:区间重叠与六态状态机
租期不是日期,是一段时间。把两个区间放进同一条轴,冲突退化成一次布尔运算——难的是后面那六个状态怎么收口。
第一版我把它写成了「开始日期相等才冲突」。测试当天就漏了一单:10 月 30 日租出,11 月 2 日归还,下一单 11 月 1 日开始——日期不相等,区间却是重叠的。
把租期当成半开区间 [start, end) 之后,问题才变成一句可以直接写进 SQL 的话:两段有交集,当且仅当各自的开头都早于对方的结尾。
def overlaps(a_start, a_end, b_start, b_end):
# 结束当天可以紧接着下一次开始,所以用开区间比较
return a_start < b_end and b_start < a_end为什么是半开
用了闭区间,归还日和下一次取货日同一天就会误判成冲突——这在相机租赁里几乎天天发生。半开区间把「当天还、当天借」让出给下一单,代价是数据库里必须统一口径。
A · 10.30 → 11.02B · 11.01 → 11.05
图 1 · 两段区间重叠的三天(红),12 格为一个月
六个状态不是拍脑袋来的
待确认、已确认、已出库、已归还、已取消、逾期——每加一个状态,都要回答「从这个状态还能去哪」。状态机画不出来的时候,说明业务本身还没想清楚,这时加字段只会把问题往后推。
最后落在 SQLite 上的约束只有一条:同一台机器,不存在两段确认中的区间相交。这条约束写在触发器里,应用层再算一遍只是为了让报错好看。