Python中两个日期范围之间的重叠日期

7

我希望找到两个日期范围之间的重叠日期,如下所示:

range1 = start(2016-06-01) end (2016-06-20)
range2 = start(2016-06-10) end (2016-06-13)

这里的结果是4个日期(2016-06-10,2016-06-11,2016-06-12,2016-06-13)。 另一个例子:

 range1 = start(2016-06-01) end (2016-06-20) range2 = start(2016-06-18)
 end (2016-06-25)

这里的结果是3个日期(2016-06-18,2016-06-19,2016-06-20)。如果没有日期发生重叠,那么结果就是0个日期。

我找到了这篇文章,它有助于确定重叠日期的数量,但我想知道是否可以不使用长的if / else语句获取实际日期?

提前感谢!

3个回答

3
我建议在两个范围内分别生成日期,然后选择两个集合的交集。一个实现此功能的代码片段可能如下所示:
from datetime import date, timedelta


def f(d1, d2):
    delta = d2 - d1
    return set([d1 + timedelta(days=i) for i in range(delta.days + 1)])

range1 = [date(2016, 6, 1), date(2016, 6, 20)]
range2 = [date(2016, 6, 10), date(2016, 6, 13)]

print f(*range1) & f(*range2)

为了提高性能,您在生成给定范围内的日期时还可以将d1 + timedelta(days=i)转换为str


谢谢Kardaj!我只是想知道性能方面的问题,为什么将其转换为字符串会提高性能? - tkyass
因为如果你要生成很多日期,你会更喜欢存储一个较简单的数据结构,比如字符串,这种情况下不会导致信息丢失。 - kardaj

2

如果您还没有开始使用Python3,因此无法使用内存高效的range对象,则可以创建一个如您链接到的答案中所示的namedtuple(否则您也可以使用新的range对象)。从那里开始,您需要做的就是在重叠的日期范围上使用datetime.date.fromordinal

>>> from datetime import date
>>> from collections import namedtuple
>>> Range = namedtuple('Range', ['start', 'end'])
>>> r1 = Range(start=date(2016, 1, 1), end=date(2016, 2, 5))
>>> r2 = Range(start=date(2016, 1, 28), end=date(2016, 2, 28))
>>> latest_start = max(r1.start, r2.start)
>>> earliest_end = min(r1.end, r2.end)
>>> overlap = (earliest_end - latest_start).days + 1
>>> overlapping_dates = [] # default
>>> if overlap > 0:
...     overlapping_dates = range(latest_start.toordinal(), earliest_end.toordinal() + 1) # as numbers
...     overlapping_dates = [ date.fromordinal(x) for x in overlapping_dates ] # back to datetime.date objects
...
>>> overlapping_dates
[datetime.date(2016, 1, 28),
 datetime.date(2016, 1, 29),
 datetime.date(2016, 1, 30),
 datetime.date(2016, 1, 31),
 datetime.date(2016, 2, 1),
 datetime.date(2016, 2, 2),
 datetime.date(2016, 2, 3),
 datetime.date(2016, 2, 4),
 datetime.date(2016, 2, 5)]

还有一种方法是使用set(在此答案的编辑历史记录中有其中一种方法),但通常效率较低,因为它必须将所有日期都存储在内存中,即使这些日期不在交集中也是如此。


1

最近我写了一个小函数,它返回是否存在重叠以及重叠的起止范围。

def date_overlap(start1, end1, start2, end2):
    overlaps = start1 <= end2 and end1 >= start2
    if not overlaps:
        return False, None, None
    return True, max(start1, start2), min(end1, end2)

显然,输出格式可以根据需要进行调整。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接