versiones guia español descargar actualizar python date date-range

python - guia - qgis manual



¿Cálculo de superposición de rango de fechas eficiente en python? (5)

Tengo dos intervalos de fechas donde cada rango está determinado por una fecha de inicio y finalización (obviamente, instancias datetime.date ()). Los dos rangos pueden superponerse o no. Necesito el número de días de la superposición. Por supuesto, puedo precompletar dos conjuntos con todas las fechas dentro de ambos rangos y realizar una intersección establecida, pero esto posiblemente sea ineficiente ... ¿hay una mejor manera aparte de otra solución que utiliza una sección larga if-elif que cubra todos los casos?


Implementé una clase TimeRange como puede ver a continuación.

El get_overlapped_range primero niega todas las opciones no superpuestas por una condición simple, y luego calcula el rango superpuesto considerando todas las opciones posibles.

para obtener la cantidad de días que necesitará para tomar el valor TimeRange que se devolvió desde get_overlapped_range y dividir la duración entre 60 * 60 * 24 (:

clase TimeRange (objeto):

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]])


Las llamadas a funciones son más costosas que las operaciones aritméticas.

La forma más rápida de hacer esto implica 2 restas y 1 min ():

min(r1.end - r2.start, r2.end - r1.start).days + 1

en comparación con el siguiente mejor que necesita 1 resta, 1 min () y un máximo ():

(min(r1.end, r2.end) - max(r1.start, r2.start)).days + 1

Por supuesto, con ambas expresiones, aún necesita verificar si hay una superposición positiva.


Pseudocódigo:

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


  • Determine la última de las dos fechas de inicio y la primera de las dos fechas de finalización.
  • Calcule el timedelta restándolo.
  • Si el delta es positivo, ese es el número de días de superposición.

Aquí hay un cálculo de ejemplo:

>>> 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