J'ai deux plages de dates où chaque plage est déterminée par une date de début et de fin (évidemment, les instances datetime.date ()). Les deux plages peuvent se chevaucher ou non. J'ai besoin du nombre de jours de chevauchement. Bien sûr, je peux pré-remplir deux ensembles avec toutes les dates dans les deux plages et effectuer une intersection d'ensemble, mais cela est peut-être inefficace ... y a-t-il un meilleur moyen en dehors d'une autre solution en utilisant une longue section if-Elif couvrant tous les cas?
Voici un exemple de calcul:
>>> from datetime import datetime
>>> from collections import namedtuple
>>> Range = namedtuple('Range', ['start', 'end'])
>>> r1 = Range(start=datetime(2012, 1, 15), end=datetime(2012, 5, 10))
>>> r2 = Range(start=datetime(2012, 3, 20), end=datetime(2012, 9, 15))
>>> latest_start = max(r1.start, r2.start)
>>> earliest_end = min(r1.end, r2.end)
>>> delta = (earliest_end - latest_start).days + 1
>>> overlap = max(0, delta)
>>> overlap
52
Les appels de fonction sont plus chers que les opérations arithmétiques.
Le moyen le plus rapide de le faire implique 2 soustractions et 1 min ():
min(r1.end - r2.start, r2.end - r1.start).days + 1
par rapport au meilleur suivant qui nécessite 1 soustraction, 1 min () et un max ():
(min(r1.end, r2.end) - max(r1.start, r2.start)).days + 1
Bien sûr, avec les deux expressions, vous devez toujours vérifier un chevauchement positif.
J'ai implémenté une classe TimeRange comme vous pouvez le voir ci-dessous.
Get_overlapped_range annule d'abord toutes les options non superposées par une simple condition, puis calcule la plage superposée en considérant toutes les options possibles.
Pour obtenir le nombre de jours, vous devrez prendre la valeur TimeRange renvoyée par get_overlapped_range et diviser la durée par 60 * 60 * 24.
class TimeRange(object):
def __init__(self, start, end):
self.start = start
self.end = end
self.duration = self.end - self.start
def is_overlapped(self, time_range):
if max(self.start, time_range.start) < min(self.end, time_range.end):
return True
else:
return False
def get_overlapped_range(self, time_range):
if not self.is_overlapped(time_range):
return
if time_range.start >= self.start:
if self.end >= time_range.end:
return TimeRange(time_range.start, time_range.end)
else:
return TimeRange(time_range.start, self.end)
Elif time_range.start < self.start:
if time_range.end >= self.end:
return TimeRange(self.start, self.end)
else:
return TimeRange(self.start, time_range.end)
def __repr__(self):
return '{0} ------> {1}'.format(*[time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(d))
for d in [self.start, self.end]])
Pseudocode:
1 + max( -1, min( a.dateEnd, b.dateEnd) - max( a.dateStart, b.dateStart) )
def get_overlap(r1,r2):
latest_start=max(r1[0],r2[0])
earliest_end=min(r1[1],r2[1])
delta=(earliest_end-latest_start).days
if delta>0:
return delta+1
else:
return 0