The unified diff between revisions [8d9287a2..] and [66fcf32a..] is displayed below. It can also be downloaded as a raw diff.

#
#
# patch "icalinate.py"
#  from [bafb379a8b7d97e13288021714d468bd65cc4d27]
#    to [92e16a3397513a44ef7bb405f31c52bbbd04baa5]
#
============================================================
--- icalinate.py	bafb379a8b7d97e13288021714d468bd65cc4d27
+++ icalinate.py	92e16a3397513a44ef7bb405f31c52bbbd04baa5
@@ -7,9 +7,10 @@
 # Copyright (C) 2007 Grahame Bowland
 #

-import datetime
+import datetime, time
 import vobject
 import heapq
+import json

 class EventWrapper(object):
 	def __init__ (self, vevent, offset):
@@ -27,6 +28,51 @@ class EventWrapper(object):
 	def __cmp__ (self, other_event):
 		return cmp (self.next_occurrence, other_event.next_occurrence)

+class EventOccurrence(object):
+	def __init__ (self, occurrence, event):
+		self.occurrence = occurrence
+		self.event = event
+		self.__calced = False
+
+	def __calc (self):
+		if self.__calced:
+			return
+		self.__dtstart = self.event.getChildValue ('dtstart')
+		self.__dtend = self.event.getChildValue ('dtend')
+		self.__duration = self.event.getChildValue ('duration')
+		if not self.__duration:
+			if self.__dtstart and self.__dtend:
+				self.__duration = self.__dtend - self.__dtstart
+			else:
+				self.__duration = None
+		self.__calced = True
+
+	def start (self):
+		self.__calc ()
+		return self.occurrence
+
+	def end (self):
+		self.__calc ()
+		return self.occurrence + self.__duration
+
+	def duration (self):
+		self.__calc ()
+		return self.__duration
+
+	def on_or_later (self, now=None):
+		self.__calc ()
+		if now == None:
+			now = datetime.datetime.now ()
+		if self.occurrence >= now:
+			return True
+		if self.__duration and self.occurrence + self.__duration >= now:
+			return True
+		return False
+
+	def get (self, *args, **kwargs):
+		return self.event.getChildValue (*args, **kwargs)
+
+
 class Upcoming(object):
 	def __init__ (self, ical_file, offset=None):
 		self.ical = vobject.readOne (open (ical_file))
@@ -38,7 +84,7 @@ class Upcoming(object):
 	def __iter__ (self):
 		while len (self.heap) > 0:
 			wrapped = heapq.heappop (self.heap)
-			yield wrapped.next_occurrence, wrapped.vevent
+			yield EventOccurrence (wrapped.next_occurrence, wrapped.vevent)
 			if wrapped.recur ():
 				heapq.heappush (self.heap, wrapped)

@@ -46,44 +92,57 @@ class iCalinate(object):
 	def __init__ (self, *args, **kwargs):
 		self.upcoming = Upcoming (*args, **kwargs)
 		self.__iter_cache = []
+		self.back_to_utc = -1 * int (time.time () - time.mktime (time.gmtime ()))

+	def __unix_from_datetime (self, dt):
+		# dt will be in local time
+		return time.mktime (dt.timetuple ()) + 1e-6 * dt.microsecond + self.back_to_utc
+
 	def summary (self, nevents=10):
 		rv = []
-		for idx, (occurrence, event) in enumerate (self):
+		for idx, event in enumerate (self):
 			if idx >= nevents:
 				break
 			entry = {}
-			dtstart = event.getChildValue ('dtstart')
-			dtend = event.getChildValue ('dtend')
-			duration = event.getChildValue ('duration')
-			if not duration and dtstart and dtend:
-				duration = dtend - dtstart
-			entry['occurrence'] = occurrence
-			entry['duration'] = duration
+			entry['start'] = event.start ()
+			entry['duration'] = event.duration ()
+			entry['end'] = event.end ()
 			for attr in ('summary', 'description'):
-				entry[attr] = event.getChildValue (attr)
+				entry[attr] = event.get (attr)
 			rv.append (entry)
 		return rv
+
+	def json_summary (self, *args, **kwargs):
+		rv = self.summary (*args, **kwargs)
+		writer = json.JsonWriter ()
+		for entry in rv:
+			for k in entry.keys ():
+				v = entry[k]
+				if isinstance (v, datetime.datetime):
+					entry[k] = self.__unix_from_datetime (v)
+				else:
+					entry[k] = str(v)
+		print writer.write (rv)

 	def __iter__ (self):
 		now = datetime.datetime.now ()
 		old_count = 0
-		for occurrence, event in self.__iter_cache:
-			if occurrence >= now:
+		for event in self.__iter_cache:
+			if event.on_or_later (now=now):
 				break
 			else:
 				old_count += 1
 		self.__iter_cache = self.__iter_cache[old_count:]
-		for occurrence, event in self.__iter_cache:
-			yield occurrence, event
-		for occurrence, event in self.upcoming:
-			if occurrence < now:
+		for event in self.__iter_cache:
+			yield event
+		for event in self.upcoming:
+			if not event.on_or_later (now):
 				continue
-			self.__iter_cache.append ((occurrence, event))
-			yield occurrence, event
+			self.__iter_cache.append (event)
+			yield event

 if __name__ == '__main__':
 	nated = iCalinate ('ical', offset=datetime.timedelta(hours=-8))
 	import pprint
-	pprint.pprint (nated.summary())
+	nated.json_summary ()