Рассчитать свободные периоды времени (datetime) вне календарных встреч в Python
Я получаю встречи через Exchange EWS API и создаю массивы json, содержащие начальную / конечную занятость (дата / время). Я хочу изменить эти данные, чтобы получить список свободных периодов времени в день.
Начало рабочего дня - 8:00. Окончание рабочего дня - 6:00.
Наконец, я нашел решение для арифметической задачи о том, как вычислять свободные периоды времени из кортежей занятых периодов времени. Ниже приведен упрощенный код, как я это сделал.
from datetime import datetime, timedelta
import pprint
pp = pprint.PrettyPrinter()
tstart = datetime.strptime('08:00:00', '%H:%M:%S')
tstop = datetime.strptime('18:00:00', '%H:%M:%S')
appointments = ([
{
'start' : datetime.strptime('08:30:00', '%H:%M:%S'),
'end' : datetime.strptime('10:00:00', '%H:%M:%S')
},
{
'start' : datetime.strptime('09:30:00', '%H:%M:%S'),
'end' : datetime.strptime('11:00:00', '%H:%M:%S')
},
{
'start' : datetime.strptime('12:30:00', '%H:%M:%S'),
'end' : datetime.strptime('14:00:00', '%H:%M:%S')
},
{
'start' : datetime.strptime('15:30:00', '%H:%M:%S'),
'end' : datetime.strptime('16:00:00', '%H:%M:%S')
},
{
'start' : datetime.strptime('16:00:00', '%H:%M:%S'),
'end' : datetime.strptime('17:00:00', '%H:%M:%S')
},
])
"""
CORRECT FREE PERIODS ARE:
8:00 - 8:30
11:00 - 12:30
14:00 - 15:30
17:00 - 18:00
"""
tp = [(tstart , tstart)]
free_time = []
for t in appointments:
tp.append( ( t['start'] , t['end'] ) )
tp.append( (tstop , tstop) )
for i,v in enumerate(tp):
if i > 0:
if (tp[i][0] - tp[i-1][1]) > timedelta(seconds=0):
tf_start = tp[i-1][1]
delta = tp[i][0] - tp[i-1][1]
tf_end = tf_start + delta
free_time.append( (tf_start ,tf_end ) )
for tp in free_time:
print tp
1 ответ
Ваш код помог нам создать проект! Спасибо. Однако я обнаружил крайний случай, когда приведенный выше алгоритм ошибочно регистрирует свободное время при перекрывающихся событиях:
Пример: событие с 7 до 8 и событие с 7:30 до 9 сломают его.
Я немного добавил в ваш код, чтобы исправить эту проблему. Вот что я использовал:
a_busy = [
{'start': datetime.datetime(2020, 1, 1, 6), 'end': datetime.datetime(2020, 1, 1, 6, 30)},
{'start': datetime.datetime(2020, 1, 1, 7), 'end': datetime.datetime(2020, 1, 1, 8)},
{'start': datetime.datetime(2020, 1, 1, 7, 30), 'end': datetime.datetime(2020, 1, 1, 9, 30)},
{'start': datetime.datetime(2020, 1, 1, 11), 'end': datetime.datetime(2020, 1, 1, 12, 30)},
{'start': datetime.datetime(2020, 1, 1, 15), 'end': datetime.datetime(2020, 1, 1, 15, 45)},
{'start': datetime.datetime(2020, 1, 1, 16, 45), 'end': datetime.datetime(2020, 1, 1, 17, 30)}
]
b_busy = [
{'start': datetime.datetime(2020, 1, 1, 5, 45), 'end': datetime.datetime(2020, 1, 1, 6, 30)},
{'start': datetime.datetime(2020, 1, 1, 7, 30), 'end': datetime.datetime(2020, 1, 1, 8)},
{'start': datetime.datetime(2020, 1, 1, 8), 'end': datetime.datetime(2020, 1, 1, 9)},
{'start': datetime.datetime(2020, 1, 1, 10, 30), 'end': datetime.datetime(2020, 1, 1, 13)},
{'start': datetime.datetime(2020, 1, 1, 14), 'end': datetime.datetime(2020, 1, 1, 15)},
{'start': datetime.datetime(2020, 1, 1, 15, 30), 'end': datetime.datetime(2020, 1, 1, 16, 30)}
]
# free times: 6:30-7, 9:30-10:30, 13:00-14:00, 16:30-16:45
tstart = datetime.datetime(2020, 1, 1, 6)
tstop = datetime.datetime(2020, 1, 1, 17)
together = sorted(a_busy + b_busy, key=lambda k: k['start'])
tp = [(tstart, tstart)]
free_time = []
for t in together:
tp.append((t['start'], t['end']))
tp.append((tstop, tstop))
# This section added to resolve the case mentioned above
i = 1
while i < len(tp):
if tp[i][0] < tp[i - 1][1]:
start_times = [tp[i - 1][0], tp[i][0]]
end_times = [tp[i - 1][1], tp[i][1]]
tp[i - 1] = (min(start_times), max(end_times))
tp.pop(i)
else:
i += 1
for i, v in enumerate(tp):
if i > 0:
if (tp[i][0] - tp[i - 1][1]) > datetime.timedelta(seconds=0):
tf_start = tp[i - 1][1]
delta = tp[i][0] - tp[i - 1][1]
tf_end = tf_start + delta
free_time.append(tup)