Splitting up a list with datetimes I have this ordered list of datetimes that comprises of 30 minute slots:

availability = [
    datetime.datetime(2010, 1, 1, 9, 0), 
    datetime.datetime(2010, 1, 1, 9, 30),
    datetime.datetime(2010, 1, 1, 10, 0), 
    datetime.datetime(2010, 1, 1, 10, 30), 
    datetime.datetime(2010, 1, 1, 13, 0), # gap
    datetime.datetime(2010, 1, 1, 13, 30), 
    datetime.datetime(2010, 1, 1, 15, 30), # gap
    datetime.datetime(2010, 1, 1, 16, 0), 
    datetime.datetime(2010, 1, 1, 16, 30)
]


And I would to split the ones with time gaps in between into a dictionary with start and end values, like so:

[
    {'start': datetime.datetime(2010, 1, 1, 9, 0), 'end': datetime.datetime(2010, 1, 1, 10, 30)},
    {'start': datetime.datetime(2010, 1, 1, 13, 0), 'end': datetime.datetime(2010, 1, 1, 13, 30)},         
    {'start': datetime.datetime(2010, 1, 1, 15, 30), 'end': datetime.datetime(2010, 1, 1, 16, 30)}
]


So I threw this snippet of code together that does exactly that.

result = []
row = {}
for index, date in enumerate(available):
    exists = False
    if not row:
        row['start'] = date
    try:
        if date + timedelta(minutes = 30) != available[index + 1]:
            exists = True
    except IndexError:
        exists = True
    if exists:
        row['end'] = date
        result.append(row)
        row = {}


But needless to say this is super ugly and there just has to be a better, shorter and more elegant way to do this.
It is possible to utilize itertools.groupby() using indexes to calculate if there is a gap:

import datetime
from datetime import timedelta
from functools import partial
from itertools import groupby
from operator import itemgetter


def is_consecutive(start_date, item):
    """A grouping key function that highlights the gaps in a list of datetimes with a 30 minute interval."""
    index, value = item
    return (start_date + index * timedelta(minutes=30)) - value


available = [
    datetime.datetime(2010, 1, 1, 9, 0),
    datetime.datetime(2010, 1, 1, 9, 30),
    datetime.datetime(2010, 1, 1, 10, 0),
    datetime.datetime(2010, 1, 1, 10, 30),
    datetime.datetime(2010, 1, 1, 13, 0),  # gap
    datetime.datetime(2010, 1, 1, 13, 30),
    datetime.datetime(2010, 1, 1, 15, 30),  # gap
    datetime.datetime(2010, 1, 1, 16, 0),
    datetime.datetime(2010, 1, 1, 16, 30)
]

start_date = available[0]

result = []
for _, group in groupby(enumerate(available), key=partial(is_consecutive, start_date)):
    current_range = list(map(itemgetter(1), group))

    result.append({
        'start': current_range[0],
        'end': current_range[-1]
    })
print(result)


Prints:

[
    {'start': datetime.datetime(2010, 1, 1, 9, 0), 'end': datetime.datetime(2010, 1, 1, 10, 30)}, 
    {'start': datetime.datetime(2010, 1, 1, 13, 0), 'end': datetime.datetime(2010, 1, 1, 13, 30)}, 
    {'start': datetime.datetime(2010, 1, 1, 15, 30), 'end': datetime.datetime(2010, 1, 1, 16, 30)}
]