theLeanDeveloper
theLeanDeveloper

Reputation: 391

Python: How to find continuous time intervals in list of time objects?

I have a dictionary whose key is date object and value is a list of time objects.

timeSlots = {
    datetime.date(2014, 12, 11): [
        datetime.time(8, 0),
        datetime.time(8, 30),
        datetime.time(9, 0),
        datetime.time(9, 30),
        datetime.time(12, 0),
        datetime.time(12, 30),
        datetime.time(13, 0),
        datetime.time(13, 30),
        datetime.time(14, 0),
        datetime.time(14, 30)
    ],
    datetime.date(2014, 12, 12): [
        datetime.time(8, 0),
        datetime.time(8, 30),
        datetime.time(9, 0),
        datetime.time(9, 30),
        datetime.time(12, 0),
        datetime.time(12, 30),
        datetime.time(13, 0),
        datetime.time(13, 30),
        datetime.time(14, 0),
        datetime.time(14, 30)
    ]
}

Input : 30 minutes Output : {datetime.date(2014, 12, 11): [90, 150], datetime.date(2014, 12, 12): [90, 150]}

How it is calculated :

  1. assume my interval is 30 minutes as provided in input.

  2. Take first list of time slot. Start seeing that difference between 8:00:00 and 8:30:00 is 30 minutes which is same as input received, so again go to next element of list which is 9:00:00(same case 8:30:00 and 9:00:00 has 30 min difference) and so on.

  3. Stop at 12:00:00 as difference is more than 30 min of previous element in list which is 9:30:00.

  4. Calculate difference between 8:00:00 and 9:30:00 and return in minutes which is 90 minutes.

  5. Continue the process and you will get the output.

Hope I am clear.

What is the best way to do this ?

TIA

Upvotes: 2

Views: 2258

Answers (2)

Reut Sharabani
Reut Sharabani

Reputation: 31339

This function returns a generator that splits on your wanted indices (longer than interval) for each key in your dict.

import datetime

timeSlots = {
    datetime.date(2014, 12, 11): [
        datetime.time(8, 0),
        datetime.time(8, 30),
        datetime.time(9, 0),
        datetime.time(9, 30),
        datetime.time(12, 0),
        datetime.time(12, 30),
        datetime.time(13, 0),
        datetime.time(13, 30),
        datetime.time(14, 0),
        datetime.time(14, 30)]
    ,datetime.date(2   interval = 30
    
    
    def get_consec(time_slots):
        for key, value in time_slots.iteritems():
            print "date: %s" % key
            last_index = 0
            diffs = zip(value[:-1], value[1:])
            print "diffs: %s" % diffs
            index = None
            for index in range(len(diffs)):
                start = diffs[index][0]
                end = diffs[index][1]
                if (end.hour * 60 + end.minute) - (start.hour * 60 + start.minute) > interval:
                    print "splitting: %s"  % str((start ,end))
                    yield value[last_index: index+1]
                    last_index = index + 1
            if index and index != last_index:
                yield value[last_index: index + 2]
            else:
                yield value
    
    print list(get_consec(timeSlots))014, 12, 12): [
            datetime.time(8, 0),
            datetime.time(8, 30),
            datetime.time(9, 0),
            datetime.time(9, 30),
            datetime.time(12, 0),
            datetime.time(12, 30),
            datetime.time(13, 0),
            datetime.time(13, 30),
            datetime.time(14, 0),
            datetime.time(14, 30)
        ]
    ,datetime.date(2014, 12, 13): [
        datetime.time(8, 0),
    ]
    ,datetime.date(2014, 12, 14): [
        datetime.time(8, 0),
        datetime.time(8, 30),
    ]

    ,datetime.date(2014, 12, 15): [
        datetime.time(8, 0),
        datetime.time(8, 40),
    ]
}

interval = 30

def get_consec(time_slots):
    for key, value in time_slots.iteritems():
        print "date: %s" % key
        last_index = 0
        diffs = zip(value[:-1], value[1:])
        print "diffs: %s" % diffs
        index = None
        for index in range(len(diffs)):
            start = diffs[index][0]
            end = diffs[index][1]
            if (end.hour * 60 + end.minute) - (start.hour * 60 + start.minute) > interval:
                print "splitting: %s"  % str((start ,end))
                yield (key, value[last_index: index+1], )
                last_index = index + 1
        if index is not None:
            print "finished with last: %d, index: %d" % (last_index, index)
            yield (key, value[last_index: index+2], )
        else:
            print "no iteration for %s" % value
            yield (key, value, )

print '\n'.join(map(str, list(get_consec(timeSlots))))

Code works for some cases, make sure to add more!

Upvotes: 0

Hernán Erasmo
Hernán Erasmo

Reputation: 371

Ok, I'll be the first to admit that perhaps this is not the most pythonic way to do this, but here's my solution:

import datetime

def get_difference(d, times):
    first = datetime.datetime.combine(d, times[0])
    second = datetime.datetime.combine(d, times[1])
    return second - first

def solution(ts, interval):
    results = []
    outputDict = {}
    acc = datetime.timedelta()
    for key in ts:
        for item in range(len(ts[k])-1):
            delta = get_difference(key, ts[key][item:item+2])
            if delta > interval:
                results.append(acc)
                acc = datetime.timedelta()
            else:
                acc += delta
        results.append(acc)
        acc = datetime.timedelta()
        outputDict[key] = [result.total_seconds() / 60 for result in results]
        results = []
    return outputDict

It gives the exact output you described:

>>> solution(timeSlots, datetime.timedelta(0, 1800))   #Interval needs to be in seconds
{datetime.date(2014, 12, 12): [90.0, 150.0], datetime.date(2014, 12, 11): [90.0, 150.0]}

Upvotes: 1

Related Questions