Следующее должно достичь того, что вы ищете:
def make_date_mask(day_start, time_start, day_end, time_end, series):
flipped = False
if day_start > day_end:
# Need to flip the ordering, then negate at the end
day_start, time_start, day_end, time_end = (
day_end, time_end, day_start, time_start
)
flipped = True
time_start = datetime.strptime(time_start, "%H:%M:%S").time()
time_end = datetime.strptime(time_end, "%H:%M:%S").time()
# Get everything for the specified days, inclusive
mask = series.dt.dayofweek.between(day_start, day_end)
# Filter things that happen before the begining of the start time
# of the start day
mask = mask & ~(
(series.dt.dayofweek == day_start)
& (series.dt.time < time_start)
)
# Filter things that happen after the ending time of the end day
mask = mask & ~(
(series.dt.dayofweek == day_end)
& (series.dt.time > time_end)
)
if flipped:
# Negate the mask to get the actual result and add in the
# times that were exactly on the boundaries, just in case
mask = ~mask | (
(series.dt.dayofweek == day_start)
& (series.dt.time == time_start)
) | (
(series.dt.dayofweek == day_end)
& (series.dt.time == time_end)
)
return mask
Используя это с вашим примером:
import pandas as pd
df = pd.DataFrame({
"dates": pd.date_range('2019-01-01', '2019-01-31', freq='H')
})
filtered_df = df[make_date_mask(6, "23:00:00", 0, "00:30:00", df["dates"])]
filtered
выглядит так:
dates
143 2019-01-06 23:00:00
144 2019-01-07 00:00:00
311 2019-01-13 23:00:00
312 2019-01-14 00:00:00
479 2019-01-20 23:00:00
480 2019-01-21 00:00:00
647 2019-01-27 23:00:00
648 2019-01-28 00:00:00