예제 #1
0
def working_datetime_ranges_of_date(d,
                                    special_working_hours={},
                                    week_working_hours={},
                                    merge_tomorrow=True):
    """
    Returns a list of datetimes tuples (datetime_range),
    indicating contiguous working periods of given date, if merge_tomorrow
    check if first period of tomorrow is contiguous and merge
    with last of today.
    """

    # curried on working hours
    whs_by_date = partial(working_hours_of_date,
                          special_working_hours=special_working_hours,
                          week_working_hours=week_working_hours)
    # curried on date
    whs_to_dt_ranges = partial(working_hours_to_datetime_ranges, d)

    today_working_hours = whs_by_date(d)

    if not len(today_working_hours):
        return []

    if not merge_tomorrow:
        return whs_to_dt_ranges(today_working_hours)

    tomorrow_working_hours = whs_by_date(tomorrow(d))

    if are_working_hours_contiguous(today_working_hours,
                                    tomorrow_working_hours):
        # last range of today become a merged range between
        # the last of today and the first of tomorrow

        next_day = tomorrow(d)

        # when tomorrow working hour end at 00:00, certainly is (00:00, 00:00)
        # because is a contiguous with today working hours, in this case
        # we add a day to current date because end at 00:00 of day after
        # this cover 24/7 like situation
        if tomorrow_working_hours[0][1] == time(0):
            next_day = tomorrow(next_day)

        last_period = (
            datetime.combine(d, today_working_hours[-1][0]),
            datetime.combine(next_day, tomorrow_working_hours[0][1])
        )

        return whs_to_dt_ranges(today_working_hours[:-1]) + [last_period]

    return whs_to_dt_ranges(today_working_hours)
예제 #2
0
def is_datetime_range_available(dt_range, availability={}):
    """
    Checks if a datetime_range is compatible with availability.
    """
    a = defaulitize_availability(availability)
    start_date, end_date = dt_range[0].date(), dt_range[1].date()

    # check if working_hours of date by current availability
    # contains current datetime_range
    def contains_dt_range_in_wh_of_date(d, merge_tomorrow=True):
        working_dt_ranges = working_datetime_ranges_of_date(
            d, a['special_working_hours'], a['week_working_hours'],
            merge_tomorrow=merge_tomorrow)
        return any_match(partial(flip(contains), dt_range), working_dt_ranges)

    if (is_date_available(start_date, a) and
            contains_dt_range_in_wh_of_date(
                start_date,
                merge_tomorrow=is_date_available(tomorrow(start_date), a))):
        return True

    if is_same_date(dt_range):
        return (is_date_available(yesterday(start_date), a) and
                contains_dt_range_in_wh_of_date(yesterday(start_date),
                                                merge_tomorrow=False))

    return False
예제 #3
0
def by_time_range(time_range, d):
    """
    Create a new datetime_range by a time_range and date object.
    """
    start_time, end_time = time_range

    if end_time <= start_time:
        return datetime.combine(d, start_time), datetime.combine(tomorrow(d),
                                                                 end_time)
    else:
        return datetime.combine(d, start_time), datetime.combine(d, end_time)
예제 #4
0
def nearest_working_datetime_range(dt_range, availability={}):
    """
    Nearest working datetime_range by datetime_range.
    """
    a = defaulitize_availability(availability)
    start_date = dt_range[0].date()

    if not is_date_available(start_date, a):
        return None

    tomorrow_available = is_date_available(tomorrow(start_date), a)
    working_dt_ranges = working_datetime_ranges_of_date(
        start_date,
        a['special_working_hours'], a['week_working_hours'],
        merge_tomorrow=tomorrow_available)

    is_near = partial(flip(end_after_or_eq), dt_range)
    return first_match(is_near, working_dt_ranges)