Пересечение интервала дат питона
В целом меня интересует, есть ли более элегантный/эффективный способ сделать это. У меня есть функция, которая сравнивает два стартовых/конечных кортежа дат, возвращающих true, если они пересекаются.
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
и др.
Мне интересно узнать, есть ли более pythonic/элегантный/более эффективный/менее подробный/вообще лучше, способ сделать это, возможно, с mxDateTime или какой-нибудь умный взлом с timedelta или set()?
Альтернативной и полезной формой будет функция, чтобы вернуть начальный/конечный кортеж пересечения, если он найден
Спасибо
Ответы
Ответ 1
На самом деле это не более Pythonic, но вы можете просто логикой немного решить вопрос о пересечении. Эти проблемы возникают много:
return (t1start <= t2start <= t1end) or (t2start <= t1start <= t2end)
Чтобы понять, почему это работает, подумайте о различных возможных способах пересечения двух интервалов и посмотрите, что исходная точка должна всегда находиться в пределах диапазона другого.
Ответ 2
Альтернативное и, надеюсь, более понятное решение:
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)
. Обратите внимание, что last_start может быть равен самой ранней_очередной.
Следует отметить, что это предполагает, что A_start <= A_end
и B_start <= B_end
.
Ответ 3
Здесь версия, которая дает вам диапазон пересечений. IMHO, возможно, это не самый оптимизированный из условий, но он ясно показывает, когда t2 перекрывается с t1. Вы можете изменить на основе других ответов, если хотите просто true/false.
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
Ответ 4
Final Comparison: start <= other_finish and other_start <= finish
# All of the conditions below result in overlap I have left out the non overlaps
start <= other_start | start <= other_finish | other_start <= finish | finish <= other_finish
0 1 1 0
0 1 1 1
1 1 1 0
1 1 1 1
Для возврата перекрытия нужно только true start <= other_finish и other_start <= finish.
Ответ 5
if t1end < t2start or t1start > t2end: return False
if t1start <= t2end or t2start <= t1start: return True
return False
Не будет ли это охватывать все пересекающиеся множества?