Как исключить определенные часы между двумя разными датами?
Я хочу получить общую разницу в часах между двумя временными метками, но я хочу исключить определенные часы. Я хочу исключить эти часы с 5 вечера до 10 утра каждый день.
from datetime import datetime
def get_total_hours(model_instance):
datetime = model_instance.datetime
now = datetime.now()
diff = now - datetime
total_secs = diff.total_seconds()
hours = total_secs // 3600
return hours
Я бы представил себе проблему геометрически:
day n day n+1 etc...
_______________________________________________________________________
00:00 | | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
EXCLUDED| | | | | |-- t2 ---| |
| | | | | | | |
| | | | | | | |
| | | | | | | |
10:00 |.........|.........|.........|.........|.........|.........|.........|
| |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| | |
| |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| | |
| |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| | |
COUNTED |-- t1 ---|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| | |
|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| | |
|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| | |
|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| | |
17:00 |.........|.........|.........|.........|.........|.........|.........|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
EXCLUDED| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
23:59 |_________|_________|_________|_________|_________|_________|_________|
Какими бы ни были t1 и t2, ваш ответ - площадь прямоугольника (высота x ширина) плюс некоторая обработка крайних случаев на концах.
Сначала проверьте оставшиеся часы для каждой даты.
Затем проверьте разницу в днях между начальной и конечной датами.
import datetime
dt_start = datetime.datetime(year=2022, month=7, day=31, hour=20)
dt_end = datetime.datetime(year=2022, month=8, day=2, hour=10, minute=30)
dt_start_gap_lb = dt_start.replace(hour=10, minute=0, second=0, microsecond=0)
dt_start_gap_ub = dt_start.replace(hour=17, minute=0, second=0, microsecond=0)
dt_end_gap_lb = dt_end.replace(hour=10, minute=0, second=0, microsecond=0)
dt_end_gap_ub = dt_end.replace(hour=17, minute=0, second=0, microsecond=0)
dt_start_remain = dt_start_gap_ub - max(dt_start_gap_lb, dt_start)
dt_end_remain = min(dt_end_gap_ub, dt_end) - dt_end_gap_lb
dt_start_remain_hours = 0 if dt_start_remain.days < 0 else dt_start_remain.seconds / 3600.0
dt_end_remain_hours = 0 if dt_end_remain.days < 0 else dt_end_remain.seconds / 3600.0
gap_hours = max((dt_end_gap_lb - dt_start_gap_ub).days * (17-10) + dt_start_remain_hours + dt_end_remain_hours, 0)
Результаты:
dt_start = datetime.datetime(year=2022, month=7, day=31, hour=20)
dt_end = datetime.datetime(year=2022, month=8, day=2, hour=10, minute=30)
> 7.5
dt_start = datetime.datetime(year=2022, month=7, day=31, hour=16, minute=30)
dt_end = datetime.datetime(year=2022, month=8, day=2, hour=10, minute=30)
> 8.0
dt_start = datetime.datetime(year=2022, month=7, day=31, hour=5, minute= 30)
dt_end = datetime.datetime(year=2022, month=7, day=31, hour=10, minute=30)
> 0.5
Данная модель Foo
с полем timestamp
, и t1
и t2
определены согласно вопросу:
Foo.objects.filter(timestamp__gte=t1, timestamp__lte=t2
).exclude( timestamp__hour__gte=17 # up to 23 by definition
).exclude( timestamp__hour__lte=9 # down to 0 by definition
)
Альтернатива,
.exclude( timestamp__hour__in=[
0,1,2,3,4,5,6,7,8,9,17,18,19,20,21,22,23 ])
В приведенном ниже ответе используется модуль datetime
для определения того, попадает ли время даты в заданный диапазон рабочих часов. Он также рассчитывает прошедшее время с момента начала работы и оставшееся время до конца рабочего дня.
При необходимости я могу доработать этот ответ, чтобы убрать дату и сосредоточиться только на времени.
import datetime
dt = datetime.datetime.now()
work_start_time = dt.replace(hour=9, minute=0, second=0, microsecond=0)
work_end_time = dt.replace(hour=18, minute=0, second=0, microsecond=0)
if work_start_time <= dt <= work_end_time:
print('The time is inside normal work hours')
start_time_diff = dt - work_start_time
end_time_diff = work_end_time - dt
print(f'Workday started {start_time_diff} hours ago')
print(f'Workday ends in {end_time_diff}')
else:
print('The time is outside normal work hours')
from BusinessHours import BusinessHours
import datetime
startTime = datetime.datetime(2022, 5, 1, 21, 35, 15)
endTime = datetime.datetime(2022, 5, 15, 11, 00, 10)
businessHours = BusinessHours(startTime , endTime , worktiming=[9, 18], weekends=[6, 7], holidayfile=None)
print(businessHours.gethours())
Соответствует требованиям в вопросе
- получите общую разницу в часах между двумя временными метками .
- Хотите исключить определенный диапазон часов из каждого дня, например, включить только 0900 - 1800 .
Пример кодового сценария.
Учитывая, что в сутках всего 24 часа, и вы хотите исключить определенные часы из каждого дня в данном примере рассматривается разница в 100 дней между двумя временными метками и исключить часы с 09:00 до 18:00. ожидаемый_ответ = 900 часов
from datetime import datetime, timedelta
HOURS_IN_A_DAY = 24
SECONDS_IN_A_HOUR = 3600
HOURS_IN_A_DAY_TO_EXCLUDE = 9
def convert_seconds_to_hours(seconds):
return seconds / SECONDS_IN_A_HOUR
expected_answer = 900
datetime_from = datetime.utcnow()
datetime_to = datetime_from + timedelta(days=100)
datetime_difference = datetime_to - datetime_from
total_hours_to_exclude = timedelta(hours=(HOURS_IN_A_DAY - HOURS_IN_A_DAY_TO_EXCLUDE) * datetime_difference.days)
datetime_difference_with_excluded_hours = datetime_difference - total_hours_to_exclude
total_datetime_difference_in_hours = convert_seconds_to_hours(datetime_difference_with_excluded_hours.total_seconds())
print(total_datetime_difference_in_hours)
assert total_datetime_difference_in_hours == expected_answer