Есть ли эффективный способ определить количество часов на временной интервал между двумя датами в Python?

#python

#python

Вопрос:

Я написал некоторый код для определения количества часов на временной интервал между двумя датами. Мой код очень большой / сложный, хотя заранее я ожидал, что он будет относительно коротким / простым. У кого-нибудь есть предложения по написанию более короткого / быстрого / лучшего кода, чтобы получить те же результаты?

Логика

Я хочу суммировать часы на временной интервал между двумя датами времени, называемыми началом и окончанием. Они могут быть разделены днями или находиться в пределах одного часа, но никогда не совпадают. Временные интервалы предопределены и различаются для рабочих и выходных дней. Время начала и окончания не обязательно должно быть равно началу или окончанию временных интервалов.

Рабочие дни состоят из 5 слотов разного размера, которые:

  • слот 1: 00:00ч — 05:00ч
  • интервал 2: 05:00ч — 10:00ч
  • интервал 3: 10:00 — 14:00ч
  • слот 4: 14:00 — 20:00ч
  • интервал 5: 20:00ч — 24:00ч

Выходные дни существуют из 3 слотов разного размера, будучи:

  • интервал 1: 00:00ч — 08:00ч
  • интервал 2: 08:00ч — 19:00ч
  • интервал 3: 19:00 — 24:00ч

Требуемый результат

Когда я ввожу следующую начальную и конечную дату-время,

  • начало = 01-04-2019 12:00h
  • end = 10-04-2019 14:00h

Я ожидаю получить следующий результат:

  • временной_слот_век_день_1 = 35
  • временной_слот_век_день_2 = 35
  • временный_слот_век_день_3 = 30
  • time_slot_week_day_4 = 42
  • time_slot_week_day_5 = 28
  • тайм_слот_выходной_день_1 = 16
  • time_slot_weekend_day_2 = 22
  • тайм_слот_выходной_день_3 = 10

Мой код до сих пор

 class MyDateRange:
    def __init__(self, name, start_datetime, end_datetime):
        self.name = name
        self.start_datetime = start_datetime
        self.end_datetime = end_datetime


def hours_per_timeslot(date_range):
    # time-slots week days
    time_slots_week = {
        1: {"begin": datetime.time(hour=0), "end": datetime.time(hour=5), "diff": datetime.timedelta(hours=5)},
        2: {"begin": datetime.time(hour=5), "end": datetime.time(hour=10), "diff": datetime.timedelta(hours=5)},
        3: {"begin": datetime.time(hour=10), "end": datetime.time(hour=14), "diff": datetime.timedelta(hours=4)},
        4: {"begin": datetime.time(hour=14), "end": datetime.time(hour=20), "diff": datetime.timedelta(hours=6)},
        5: {"begin": datetime.time(hour=20), "end": datetime.time(hour=23, minute=59, second=59, microsecond=999999),
            "diff": datetime.timedelta(hours=4)}
    }

    # time-slots weekend days
    time_slots_weekend = {
        1: {"begin": datetime.time(hour=0), "end": datetime.time(hour=8), "diff": datetime.timedelta(hours=8)},
        2: {"begin": datetime.time(hour=8), "end": datetime.time(hour=19), "diff": datetime.timedelta(hours=11)},
        3: {"begin": datetime.time(hour=19), "end": datetime.time(hour=23, minute=59, second=59, microsecond=999999),
            "diff": datetime.timedelta(hours=5)}
    }

    # dictionary to store outcome of week days
    dict_week = {
        1: datetime.timedelta(),
        2: datetime.timedelta(),
        3: datetime.timedelta(),
        4: datetime.timedelta(),
        5: datetime.timedelta(),
    }

    # dictionary to store outcome of weekend days
    dict_weekend = {
        1: datetime.timedelta(),
        2: datetime.timedelta(),
        3: datetime.timedelta(),
    }

    begin = date_range.start_datetime
    end = date_range.end_datetime
    delta = end - begin

    # calculate the hours per time-slot when begin and en are on the same date.
    if begin.date() == end.date():
        day = calendar.day_name[begin.weekday()]
        # in case it is weekend.
        if day in ["Saturday", "Sunday"]:
            for k, v in time_slots_weekend.items():
                # in case begin and end are in the same time-slot
                if v["begin"] <= begin.time() < v["end"] and v["begin"] <= end.time() < v["end"]:
                    dict_weekend[k] = end - begin
                # in case they are not in the same time-slot
                elif v["begin"] <= begin.time() < v["end"]:
                    dict_weekend[k] = datetime.datetime.combine(begin.date(), v["end"]) - begin
                    while True:
                        k  = 1
                        v = time_slots_weekend[k]
                        if v["begin"] <= end.time() < v["end"]:
                            dict_weekend[k] = end - datetime.datetime.combine(end.date(), v["begin"])
                            break
                        else:
                            dict_weekend[k] = time_slots_week[k]["diff"]

        # in case it is week.
        else:
            for k, v in time_slots_week.items():
                if v["begin"] <= begin.time() < v["end"] and v["begin"] <= end.time() < v["end"]:
                    dict_week[k] = end - begin
                elif v["begin"] <= begin.time() < v["end"]:
                    dict_week[k] = datetime.datetime.combine(begin.date(), v["end"]) - begin
                    while True:
                        k  = 1
                        v = time_slots_week[k]
                        if v["begin"] <= end.time() < v["end"]:
                            dict_week[k] = end - datetime.datetime.combine(end.date(), v["begin"])
                            break
                        else:
                            dict_week[k] = time_slots_week[k]["diff"]

    # calculate the hours per time-slot when begin and end are on different date.
    else:
        # calculate the hours per time-slot for begin time until end of day
        day_begin = calendar.day_name[begin.weekday()]
        # in case it is weekend.
        if day_begin in ["Saturday", "Sunday"]:
            for k, v in time_slots_weekend.items():
                if v["begin"] <= end.time() < v["end"]:
                    dict_weekend[k]  = (datetime.datetime.combine(begin.date(), v["end"])-begin)
                    k  = 1
                    while k <= 3:
                        dict_weekend[k]  = time_slots_weekend[k]["diff"]
                        k  = 1
        # in case it is week.
        else:
            for k, v in time_slots_week.items():
                if v["begin"] <= end.time() < v["end"]:
                    dict_week[k]  = datetime.datetime.combine(begin.date(), v["end"]) - begin
                    k  = 1
                    while k <= 5:
                        dict_week[k]  = time_slots_week[k]["diff"]
                        k  = 1

        # calculate the hours per time-slot for beginning of day until end time
        day_end = calendar.day_name[end.weekday()]
        # in case it is weekend.
        if day_end in ["Saturday", "Sunday"]:
            for k, v in time_slots_weekend.items():
                if v["begin"] <= end.time() < v["end"]:
                    dict_weekend[k]  = end - datetime.datetime.combine(end.date(), v["begin"])
                    k -= 1
                    while k > 0:
                        dict_weekend[k]  = time_slots_weekend[k]["diff"]
                        k -= 1
        # in case it is week.
        else:
            for k, v in time_slots_week.items():
                if v["begin"] <= end.time() < v["end"]:
                    dict_week[k]  = end - datetime.datetime.combine(end.date(), v["begin"])
                    k -= 1
                    while k > 0:
                        dict_week[k]  = time_slots_week[k]["diff"]
                        k -= 1

        # in case there are days between begin and end,
        if delta.days > 1:
            counted_days = {}
            for i in range(delta.days-1):
                day = calendar.day_name[(begin   datetime.timedelta(days=i   1)).weekday()]
                counted_days[day] = counted_days[day]   1 if day in counted_days else 1
            for k1, v1 in counted_days.items():
                if k1 in ["Saturday", "Sunday"]:
                    for k2 in dict_weekend.keys():
                        dict_weekend[k2]  = (time_slots_weekend[k2]["diff"] * v1)
                else:
                    for k2 in dict_week.keys():
                        dict_week[k2]  = (time_slots_week[k2]["diff"] * v1)

    # put the results together and convert them into hours.
    results = {}
    for k, v in dict_week.items():
        results["time_slot_week_day_" str(k)] = v.seconds/60/60

    for k, v in dict_weekend.items():
        results["time_slot_weekend_day_" str(k)] = v.seconds/60/60

    return results


dr = MyDateRange("test", datetime.datetime(year=2019, month=4, day=21, hour=8), datetime.datetime(year=2019, month=4, day=27, hour=15))
print(hours_per_timeslot(dr))
  

Комментарии:

1. Можете ли вы обновить свой вопрос, включив в него то, как должны выглядеть ваши входные данные и ожидаемый результат? Это облегчит ответ на вопрос!

Ответ №1:

используя модули time, datetime? и вычислить секунды, а затем преобразовать их обратно, нет? Или я упускаю причину, по которой вы не хотите это использовать?

 from datetime import datetime, time
def date_diff_in_Seconds(dt2, dt1):
timedelta = dt2 - dt1
return timedelta.days * 24 * 3600   timedelta.seconds
#Specified date
date1 = datetime.strptime('2018-01-01 01:00:00', '%Y-%m-%d %H:%M:%S')
#Current date
date2 = datetime.now()
print("n%d seconds" %(date_diff_in_Seconds(date2, date1)))
print()
  

Комментарии:

1. Я хочу получить количество часов на временной интервал, которое я определил. Я добавил требуемый результат в свой вопрос. Надеюсь, это прояснит ситуацию.