Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Counting day-of-week-hour pairs between two dates

Consider the following list of day-of-week-hour pairs in 24H format:

{
 'Mon': [9,23],
 'Thu': [12, 13, 14],
 'Tue': [11, 12, 14],
 'Wed': [11, 12, 13, 14]
 'Fri': [13],
 'Sat': [],
 'Sun': [],
}

and two time points, e.g.:

  • Start:

    datetime.datetime(2015, 7, 22, 17, 58, 54, 746784)
    
  • End:

    datetime.datetime(2015, 8, 30, 10, 22, 36, 363912)
    

Say we need to know how many hours there are between these two datetimes (either rounding up or down) for each of the day-of-week-hour pairs specified above.

How can I approach this problem in Python? I explored timedelta and relativedelta in a general level of detail but I didn't find anything that provides something close to this.

For simplicity, we can assume that everything refers to the same timezone.


Perhaps a simpler problem is to focus on a single day-hour pair, e.g. How many Wednesdays: 14 are there between two arbitrary datetimes?

like image 925
Amelio Vazquez-Reina Avatar asked Jul 22 '15 22:07

Amelio Vazquez-Reina


2 Answers

Perhaps something like this:

from calendar import day_abbr
from datetime import datetime, timedelta


def solve(start, end, data):
    days = list(day_abbr)
    output = dict.fromkeys(days, 0)

    while start <= end:
        day = days[start.weekday()]
        if start.hour in data[day]:
            output[day] += 1
        start = start + timedelta(minutes=60)

    return output


data = {
 'Mon': [9, 23],
 'Thu': [12, 13, 14],
 'Tue': [11, 12, 14],
 'Wed': [11, 12, 13, 14],
 'Fri': [13],
 'Sat': [],
 'Sun': [],
}

start = datetime(2015, 7, 22, 17, 58, 54, 746784)
end = datetime(2015, 8, 30, 10, 22, 36, 363912)

print solve(start, end, data)
# {'Wed': 20, 'Sun': 0, 'Fri': 6, 'Tue': 15, 'Mon': 10, 'Thu': 18, 'Sat': 0} 

Getting count for each day by hour:

from calendar import day_abbr
from collections import defaultdict
from datetime import datetime, timedelta
from pprint import pprint


def solve(start, end, data):
    days = list(day_abbr)
    output = defaultdict(lambda: defaultdict(int))

    while start <= end:
        day = days[start.weekday()]
        if start.hour in data[day]:
            output[day][start.hour] += 1
        start = start + timedelta(minutes=60)
    return {k: dict(v) for k, v in output.items()}


data = {
 'Mon': [9, 23],
 'Thu': [12, 13, 14],
 'Tue': [11, 12, 14],
 'Wed': [11, 12, 13, 14],
 'Fri': [13],
 'Sat': [],
 'Sun': [],
}

start = datetime(2015, 7, 22, 17, 58, 54, 746784)
end = datetime(2015, 8, 30, 10, 22, 36, 363912)

pprint(solve(start, end, data))
# output 
{'Fri': {13: 6},
 'Mon': {9: 5, 23: 5},
 'Thu': {12: 6, 13: 6, 14: 6},
 'Tue': {11: 5, 12: 5, 14: 5},
 'Wed': {11: 5, 12: 5, 13: 5, 14: 5}}
like image 157
Ashwini Chaudhary Avatar answered Sep 22 '22 06:09

Ashwini Chaudhary


Maybe I am not grasping your issue fully but you could get all the hours between the two dates and sum how many times each hour and day appears between the two dates:

from datetime import datetime
from dateutil import  rrule,parser


d={
 'Mon': [9, 23],
 'Thu': [12, 13, 14],
 'Tue': [11, 12, 14],
 'Wed': [11, 12, 13, 14],
 'Fri': [13],
 'Sat': [],
 'Sun': [],
}

st = datetime(2015, 7, 22, 17, 58, 54, 746784)

ed = datetime(2015, 8, 30, 10, 22, 36, 363912)
dates = list(rrule.rrule(rrule.HOURLY,
                         dtstart=parser.parse(st.strftime("%Y-%m-%d %H:%M:%S")),
                         until=parser.parse(ed.strftime("%Y-%m-%d %H:%M:%S"))))


days = {"Mon":0,"Tue": 1,"Wed":2,"Thu": 3,"Fri":4,"Sat":5,"Sun":6}

for k, val in d.items():
    for v in val:
        print("day: {} hour: {}".format(k,v))
        day = days[k]
        print(sum((v == dt.hour and dt.weekday() == day) for dt in dates))

Output:

day: Wed hour: 11
5
day: Wed hour: 12
5
day: Wed hour: 13
5
day: Wed hour: 14
5
day: Fri hour: 13
6
day: Tue hour: 11
5
day: Tue hour: 12
5
day: Tue hour: 14
5
day: Mon hour: 9
6
day: Mon hour: 23
5
day: Thu hour: 12
5
day: Thu hour: 13
5
day: Thu hour: 14
5

Not sure if you want the sum for all hours in each list or the total for each individual hour but either way you can store the output in a dict.

counts = {'Thu':{}, 'Sun':{}, 'Fri':{}, 'Mon':{}, 'Tue':{}, 'Sat':{}, 'Wed':{}}
for k, val in d.items():
    for v in val:
        day = days[k]
        sm = sum((v == dt.hour and dt.weekday() == day) for dt in dates)
        counts[k][v] = sm

from pprint import pprint as pp
pp(counts)

Output:

{'Fri': {13: 6},
 'Mon': {9: 5, 23: 5},
 'Sat': {},
 'Sun': {},
 'Thu': {12: 6, 13: 6, 14: 6},
 'Tue': {11: 5, 12: 5, 14: 5},
 'Wed': {11: 5, 12: 5, 13: 5, 14: 5}}
like image 40
Padraic Cunningham Avatar answered Sep 22 '22 06:09

Padraic Cunningham