python 中两个日期范围之间的重叠日期
overlapping dates between two date ranges in python
我正在寻找两个日期范围之间的重叠日期,如下所示:
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 个日期。
我发现 this post 它有助于确定重叠日期的数量,但我想知道我是否可以在不使用长 if/else 语句的情况下获得实际日期?
提前致谢!
当你还没有使用 Python3 并且因此不能使用内存高效的 range
对象时,你可以创建一个 namedtuple,如 the answer you link to 所示(否则你也可以使用新的 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
的方法也可以(其中一种方法在这个答案的编辑历史中),但通常效率较低,因为它必须有 all 内存中的日期,即使是那些不在交集的日期。
我建议生成两个范围内的每个日期,然后选择两个集合之间的交集。这样做的片段可能如下所示:
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
。
我最近为此写了一个小函数,returns是否有重叠,然后是from-to range
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)
显然输出格式可以根据需要进行调整。
我正在寻找两个日期范围之间的重叠日期,如下所示:
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 个日期。
我发现 this post 它有助于确定重叠日期的数量,但我想知道我是否可以在不使用长 if/else 语句的情况下获得实际日期?
提前致谢!
当你还没有使用 Python3 并且因此不能使用内存高效的 range
对象时,你可以创建一个 namedtuple,如 the answer you link to 所示(否则你也可以使用新的 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
的方法也可以(其中一种方法在这个答案的编辑历史中),但通常效率较低,因为它必须有 all 内存中的日期,即使是那些不在交集的日期。
我建议生成两个范围内的每个日期,然后选择两个集合之间的交集。这样做的片段可能如下所示:
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
。
我最近为此写了一个小函数,returns是否有重叠,然后是from-to range
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)
显然输出格式可以根据需要进行调整。