{"id":150,"date":"2010-07-15T14:58:07","date_gmt":"2010-07-15T18:58:07","guid":{"rendered":"http:\/\/dashdrum.com\/blog\/?p=150"},"modified":"2010-07-15T14:58:07","modified_gmt":"2010-07-15T18:58:07","slug":"using-the-python-icalendar-library","status":"publish","type":"post","link":"https:\/\/dashdrum.com\/blog\/2010\/07\/using-the-python-icalendar-library\/","title":{"rendered":"Using the Python iCalendar Library"},"content":{"rendered":"<p>An application I&#8217;m working on uses the icalendar library (<a href=\"http:\/\/codespeak.net\/icalendar\/\">http:\/\/codespeak.net\/icalendar\/<\/a>) to generate an ICS file of upcoming events that can be linked to another calendar program (I&#8217;ve tried Outlook and Google Calendar).  One problem I was having was that I was unable to generate time zone aware times.  Mine were all naive &#8211; also called &#8216;floating&#8217; times &#8211; that would appear the same regardless of the calendar program&#8217;s timezone.<\/p>\n<p>What I was trying to do was to create a new time zone in the ICS file, and then append the TZID parameter to each date\/time value.  It was not happening.<\/p>\n<p>So, I dug into the source code for icalendar.  This library is well documented with tests, and I soon found a solution &#8211; include a tzinfo value when supplying the date\/time and icalendar will convert it to UTC and append a &#8216;Z&#8217; to the end of the time to indicate this.  icalendar supplies a class called LocalTimezone that can be used for this purpose.  I tried it, and it worked!  Here&#8217;s a simplified version of my code:<\/p>\n<pre>\r\n    from icalendar import Calendar, Event\r\n    from datetime import datetime \r\n    from icalendar import LocalTimezone   \r\n    \r\n    cal = Calendar()\r\n    \r\n    cal.add('version', '2.0')\r\n    cal.add('prodid', '-\/\/test file\/\/example.com\/\/')\r\n    cal.add('X-WR-CALNAME','Test Calendar ' )\r\n    \r\n    lt = LocalTimezone() # we append the local timezone to each time so that icalendar will convert\r\n                         # to UTC in the output\r\n    \r\n    for ent in queryset:        \r\n        event = Event()\r\n        event.add('summary', ent.event_name)\r\n        event.add('dtstart', datetime.combine(ent.event_date,ent.start_time).replace(tzinfo=lt))\r\n        event.add('dtend', datetime.combine(ent.stop_date,ent.stop_time).replace(tzinfo=lt))\r\n        event.add('dtstamp', ent.updated_on.replace(tzinfo=lt))\r\n        event['uid'] = ent.pk  # should probably use a better guid than just the PK\r\n        event.add('priority', 5)\r\n        \r\n        cal.add_component(event)\r\n    \r\n    return cal<\/pre>\n<p>And this is a sample event from the output:<\/p>\n<pre>BEGIN:VEVENT\r\nDTEND: 20100714T184500Z\r\nDTSTAMP:20100714T185936Z\r\nDTSTART:20100719T174500Z\r\nPRIORITY:5\r\nSUMMARY:Gateway Production\r\nUID:66\r\nEND:VEVENT<\/pre>\n<p>Note that my 1:45pm event in the US Eastern time zone (EDT) shows as 1745 in UTC.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>An application I&#8217;m working on uses the icalendar library (http:\/\/codespeak.net\/icalendar\/) to generate an ICS file of upcoming events that can be linked to another calendar program (I&#8217;ve tried Outlook and Google Calendar). One problem I was having was that I was unable to generate time zone aware times. Mine were all naive &#8211; also called &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/dashdrum.com\/blog\/2010\/07\/using-the-python-icalendar-library\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Using the Python iCalendar Library&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-150","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts\/150","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/comments?post=150"}],"version-history":[{"count":3,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts\/150\/revisions"}],"predecessor-version":[{"id":153,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts\/150\/revisions\/153"}],"wp:attachment":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/media?parent=150"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/categories?post=150"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/tags?post=150"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}