I'm trying to calculate the total time in a list of date ranges in Python, and if there is an intersection between the ranges, it should merge to be calculated as if it were a new range.
Interval 1:
intervalos = [
{'inicio': datetime(2014, 11, 26, 10, 0, 0), 'fim': datetime(2014, 11, 26, 12, 0, 0)},
{'inicio': datetime(2014, 11, 26, 11, 0, 0), 'fim': datetime(2014, 11, 26, 13, 0, 0)},
]
self.assertEqual(calcular_tempo(intervalos), 10800)
Interval 2:
intervalos = [
{'inicio': datetime(2014, 11, 26, 10, 0, 0), 'fim': datetime(2014, 11, 26, 11, 0, 0)},
{'inicio': datetime(2014, 11, 26, 10, 30, 0), 'fim': datetime(2014, 11, 26, 11, 30, 0)},
{'inicio': datetime(2014, 11, 26, 12, 0, 0), 'fim': datetime(2014, 11, 26, 12, 30, 0)},
{'inicio': datetime(2014, 11, 26, 9, 0, 0), 'fim': datetime(2014, 11, 26, 13, 0, 0)},
]
self.assertEqual(calcular_tempo(intervalos), 14400)
Interval 3:
intervalos = [
{'inicio': datetime(2014, 11, 26, 10, 0, 0), 'fim': datetime(2014, 11, 26, 11, 0, 0)},
{'inicio': datetime(2014, 11, 26, 10, 30, 0), 'fim': datetime(2014, 11, 26, 11, 30, 0)},
{'inicio': datetime(2014, 11, 26, 12, 0, 0), 'fim': datetime(2014, 11, 26, 12, 30, 0)},
{'inicio': datetime(2014, 11, 26, 12, 40, 0), 'fim': datetime(2014, 11, 26, 12, 50, 0)},
{'inicio': datetime(2014, 11, 26, 5, 0, 0), 'fim': datetime(2014, 11, 26, 10, 1, 0)},
]
self.assertEqual(calcular_tempo(intervalos), 25860)
I created a method to perform the calculation, however the result is failing for some tests the code works but the logic is weak.
The method:
def calcular_tempo(objetos):
intervalos = []
intervalos_add = []
intervalos_del = []
for objeto in objetos:
if intervalos:
for intervalo in intervalos:
if intervalo['inicio'] < objeto['inicio'] < intervalo['fim']:
if objeto['fim'] > intervalo['fim']:
intervalos_del.append(intervalo)
intervalos_add.append({'inicio': intervalo['inicio'], 'fim': objeto['fim']})
elif intervalo['fim'] > objeto['fim'] > intervalo['inicio']:
if objeto['inicio'] < intervalo['inicio']:
intervalos_del.append(intervalo)
intervalos_add.append({'inicio': objeto['inicio'], 'fim': intervalo['fim']})
elif objeto['inicio'] < intervalo['inicio'] and objeto['fim'] > intervalo['fim']:
intervalos_del.append(intervalo)
intervalos_add.append(objeto)
elif objeto['inicio'] != intervalo['inicio'] and objeto['fim'] != intervalo['fim']:
intervalos_add.append(objeto)
else:
intervalos.append(objeto)
for deletar in intervalos_del:
intervalos.remove(deletar)
intervalos_sem_repeticoes = []
for add in intervalos_add:
if add not in intervalos_sem_repeticoes:
intervalos_sem_repeticoes.append(add)
intervalos = intervalos + intervalos_sem_repeticoes
intervalos_add = []
intervalos_del = []
segundos_totais = 0
for intervalo in intervalos:
segundos_totais += (intervalo['fim'] - intervalo['inicio']).total_seconds()
return segundos_totais
I think I'm redundant in logic and not wanting to check the intervals. I was not going to put the method that I did not influence, it would be interesting if they did this logic from scratch, because it should be simpler than the algorithm I made.