交集天数 = max(0, least(end1, end2) - greatest(start1, start2)),即取较晚起始日与较早结束日之差,若为负则无交集,结果需按日期相减规则转换为整数天数。

两个时间段交集天数怎么算?先看核心逻辑
直接结论:交集天数 = MAX(0, LEAST(end1, end2) - GREATEST(start1, start2)),结果单位是「天数差」,需配合日期相减规则(如 PostgreSQL 返回 interval,MySQL/SQL Server 需转为整数)。关键不是套公式,而是理解 GREATEST 和 LEAST 在这里分别取「较晚的起始日」和「较早的结束日」——只有当这个「较晚起始」 ≤ 「较早结束」时,才有交集。
为什么不能直接用 end1 - start2 或类似写法?
常见错误是凭直觉拼日期字段,比如写 end1 - start2,这完全忽略时间范围是否重叠。例如:start1='2024-01-01', end1='2024-01-10',start2='2024-01-15', end2='2024-01-20',此时两段根本无交集,但 end1 - start2 会返回负值或无效天数。
正确做法必须先判断是否存在交集:
-
GREATEST(start1, start2)得到两段中「更靠后的开始时间」——这是潜在交集的起点 -
LEAST(end1, end2)得到两段中「更靠前的结束时间」——这是潜在交集的终点 - 若
LEAST(end1, end2) ,说明无交集,结果应为 0
不同数据库里怎么写成可执行的天数?
日期相减行为因数据库而异,不能直接复用同一句 SQL:
✅ PostgreSQL(支持直接减,返回 interval,需 AVG() 或 EXTRACT):SELECT GREATEST(0, EXTRACT(DAY FROM LEAST(end1, end2) - GREATEST(start1, start2))) AS overlap_days
✅ MySQL(日期相减得天数,但需确保类型是 DATE):SELECT GREATEST(0, DATEDIFF(LEAST(end1, end2), GREATEST(start1, start2))) AS overlap_days
✅ SQL Server(推荐用 DATEDIFF + DATEADD 防止隐式转换出错):SELECT CASE WHEN LEAST(end1, end2) >= GREATEST(start1, start2) THEN DATEDIFF(day, GREATEST(start1, start2), LEAST(end1, end2)) ELSE 0 END AS overlap_days
⚠️ 注意:LEAST/GREATEST 在 SQL Server 2022+ 才原生支持;旧版本得用 CASE WHEN 模拟。
容易被忽略的边界与精度问题
交集计算默认按「日期粒度」,但实际业务常涉及时间戳(如 '2024-01-01 14:00')。如果字段是 TIMESTAMP 或 DATETIME,直接用 DATEDIFF(day, ...) 会截断时间部分,导致「同一天内有重叠也返回 0」。
需要精确到小时或分钟时,得换算单位:
- MySQL:用
DATEDIFF不够,改用TIMESTAMPDIFF(HOUR, ..., ...)再除以 24 - PostgreSQL:用
EXTRACT(EPOCH FROM (LEAST(...) - GREATEST(...))) / 86400.0 - 所有场景下,务必确认字段是否含时区信息——
start1是 UTC、end2是本地时间?混用会导致交集被低估甚至为负
最稳妥的做法:统一转为同一时区的 TIMESTAMP WITHOUT TIME ZONE 再计算,别依赖数据库自动转换。










