Python 日期区间交集

20 投票
7 回答
19558 浏览
提问于 2025-04-16 04:11

出于一般兴趣,我想知道有没有更优雅或更高效的方法来实现这个功能。我有一个函数,它比较两个日期的开始和结束时间,如果它们有交集就返回真。

from datetime import date
def date_intersection(t1, t2):
    t1start, t1end = t1[0], t1[1]
    t2start, t2end = t2[0], t2[1]

    if t1end < t2start: return False
    if t1end == t2start: return True
    if t1start == t2start: return True
    if t1start < t2start and t2start < t1end: return True
    if t1start > t2start and t1end < t2end: return True
    if t1start < t2start and t1end > t2end: return True
    if t1start < t2end and t1end > t2end: return True
    if t1start > t2start and t1start < t2end: return True
    if t1start == t2end: return True
    if t1end == t2end: return True 
    if t1start > t2end: return False

比如说,如果:

d1 = date(2000, 1, 10)
d2 = date(2000, 1, 11)
d3 = date(2000, 1, 12)
d4 = date(2000, 1, 13)

那么:

>>> date_intersection((d1,d2),(d3,d4))
False
>>> date_intersection((d1,d2),(d2,d3))
True
>>> date_intersection((d1,d3),(d2,d4))
True

等等。

我很好奇,是否有更符合Python风格、更优雅、更高效、代码更简洁的方法来实现这个功能,可能可以用mxDateTime库,或者用timedelta或set()做一些聪明的处理?

另外,如果函数能返回交集的开始和结束时间的元组,那也是一种有用的形式。

谢谢!

7 个回答

7

这里有一个版本,可以让你看到两个范围的交集。依我看,这可能不是条件数量最优的写法,但它清楚地展示了 t2 是如何与 t1 重叠的。如果你只想要一个真假值,可以根据其他答案进行修改。

if (t1start <= t2start <= t2end <= t1end):
    return t2start,t2end
elif (t1start <= t2start <= t1end):
    return t2start,t1end
elif (t1start <= t2end <= t1end):
    return t1start,t2end
elif (t2start <= t1start <= t1end <= t2end):
    return t1start,t1end
else:
    return None
20

这里有一个替代方案,希望能更容易理解:

def has_overlap(a_start, a_end, b_start, b_end):
    latest_start = max(a_start, b_start)
    earliest_end = min(a_end, b_end)
    return latest_start <= earliest_end

我们可以很简单地找到重叠的时间段,它是 (latest_start, earliest_end)。需要注意的是,latest_start 可能等于 earliest_end。

还要说明的是,这个假设是 a_start <= a_endb_start <= b_end

30

这其实并不是更符合Python风格,但你可以稍微简化一下判断两个区间是否相交的逻辑。这个问题经常会出现:

return (t1start <= t2start <= t1end) or (t2start <= t1start <= t2end)

要理解为什么这样做有效,可以想想两个区间相交的不同情况,发现其中一个区间的起始点必须总是在另一个区间的范围内。

撰写回答