import icalendar
import utils
import time
import datetime
import dateutil.rrule
import operator

CACHE_EXPIRY = 15*60
URL = "http://www.google.com/calendar/ical/loadingreadyrun.com_72jmf1fn564cbbr84l048pv1go%40group.calendar.google.com/public/basic.ics"

@utils.throttle(CACHE_EXPIRY)
def get_calendar_data():
	ical = utils.http_request(URL)
	return icalendar.Calendar.from_ical(ical)

def get_next_event(after=None, all=False):
	cal_data = get_calendar_data()
	events = []
	if after is None:
		after = datetime.datetime.now(datetime.timezone.utc)
	for ev in cal_data.subcomponents:
		if isinstance(ev, icalendar.Event):
			event_name = str(ev['summary'])
			event_time = ev['dtstart'].dt
			if not isinstance(event_time, datetime.datetime):
				# ignore full-day events
				continue
			# Report episodes that are either in the first half, or started less than an hour ago
			# Whichever is shorter
			cutoff_delay = (ev['dtend'].dt - ev['dtstart'].dt) / 2
			if cutoff_delay > datetime.timedelta(hours=1):
				cutoff_delay = datetime.timedelta(hours=1)
			event_time_cutoff = event_time + cutoff_delay
			if 'rrule' in ev:
				rrule = dateutil.rrule.rrulestr(ev['rrule'].to_ical().decode('utf-8'), dtstart=event_time_cutoff)
				event_time_cutoff = rrule.after(after)
				if event_time_cutoff is None:
					continue
				event_time = event_time_cutoff - cutoff_delay
			if event_time_cutoff > after:
				events.append((event_name, event_time))
	if all:
		events.sort(key=operator.itemgetter(1))
		return events
	if events:
		event_name, event_time = min(events, key=operator.itemgetter(1))
		event_wait = (event_time - after).total_seconds()
		return event_name, event_time, event_wait
	else:
		return None, None, None

@@ -1219,16 +1219,105 @@
 cutoff)%0A
+%09%09%09%09### MASSIVE HACK ALERT%0A%09%09%09%09_apply_monkey_patch(rrule)%0A%09%09%09%09### END MASSIVE HACK ALERT%0A
 %09%09%09%09even
@@ -1801,8 +1801,1420 @@
 e, None%0A
+%0Adef _apply_monkey_patch(rrule):%0A%09%22%22%22%0A%09The processing in dateutil.rrule is not properly timezone-aware, mostly because%0A%09Python's timezone handling is far from ideal. In particular, it will claim that,%0A%09for instance, %222014-03-06 19:00:00 PST%22 is %222014-03-13 19:00:00 PST%22, when in fact%0A%09the correct answer is %222014-03-13 19:00:00 PDT%22, as daylight savings has started.%0A%0A%09Notably, the time from the original time to the time 1 week later is not 7*24 hours.%0A%0A%09We monkey-patch the rrule class so that all the datetimes that come out of it are%0A%09re-localised, so that the naive hour/minute values are preserved, but the DST flag%0A%09is changed. This means that the corrected dates are what is seen by rrule.after(),%0A%09when it does comparisons using the dates, so the correct results should come out.%0A%0A%09This is a hack that messes with the internals of the library, and as such is far%0A%09from a good idea. It was written against dateutil 2.2, and no guarantees that it%0A%09will work with any other version of that library. A better solution would be%0A%09appreciated, even if it means ditching dateutil for a better library that does%0A%09what we want it to here.%0A%09%22%22%22%0A%09if rrule._freq %3E dateutil.rrule.DAILY:%0A%09%09return%0A%0A%09import functools%0A%09old_iter = rrule._iter%0A%09@functools.wraps(old_iter)%0A%09def new_iter(*args, **kwargs):%0A%09%09for dt in old_iter(*args, **kwargs):%0A%09%09%09yield dt.tzinfo.localize(dt.replace(tzinfo=None))%0A%09rrule._iter = new_iter%0A

Fix daylight saving transition with massive hack