In the last few days I spent a lot of time trying to find a library or repository of some kind that could help me generate the required DAYLIGHT and STANDARD components of ical VTIMEZONE blocks. Since I couldn't find anything, I cobbled together this snippet to poke around in pytz timezone information and output the bare minimum I needed to make my ICS files compliant and useful (DST transitions for this year and the next). I promise it's (superficially) tested against "real" ICS files, but that's all.
UPDATE: Thanks to @ariannedee for a much improved version (see comment for details)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | import pytz
import icalendar
import datetime
def generate_vtimezone(timezone, for_date=None):
if not timezone or 'utc' in timezone.lower(): # UTC doesn't need a timezone definition
return None
if not for_date:
for_date = now()
try:
z = pytz.timezone(timezone)
except pytz.UnknownTimeZoneError:
z = pytz.timezone('Europe/Berlin')
if not hasattr(z, '_utc_transition_times'):
return None
transitions = zip(z._utc_transition_times, z._transition_info)
try:
dst1, std1, dst2, std2 = filter(lambda x: x[0].year in (for_date.year, for_date.year + 1),
transitions)
if dst1[1][1].seconds == 0:
return _vtimezone_with_dst(std1, dst1, std2, dst2, timezone)
else:
return _vtimezone_with_dst(dst1, std1, dst2, std2, timezone)
except:
std = transitions[-1]
if std[0].year > for_date.year:
return None
return _vtimezone_without_dst(std, timezone)
def _vtimezone_without_dst(std, timezone):
vtimezone = icalendar.Timezone(tzid=timezone)
standard = icalendar.TimezoneStandard()
utc_offset, dst_offset, tz_name = std[1]
standard.add('dtstart', std[0])
standard.add('tzoffsetfrom', utc_offset)
standard.add('tzoffsetto', utc_offset)
standard.add('tzname', tz_name)
vtimezone.add_component(standard)
return vtimezone
def _vtimezone_with_dst(dst1, std1, dst2, std2, timezone):
vtimezone = icalendar.Timezone(tzid=timezone)
daylight = icalendar.TimezoneDaylight()
utc_offset, dst_offset, tz_name = dst1[1]
offsetfrom = std1[1][0]
daylight.add('dtstart', dst1[0] + offsetfrom)
daylight.add('rdate', dst1[0] + offsetfrom)
daylight.add('rdate', dst2[0] + offsetfrom)
daylight.add('tzoffsetfrom', offsetfrom)
daylight.add('tzoffsetto', utc_offset)
daylight.add('tzname', tz_name)
vtimezone.add_component(daylight)
standard = icalendar.TimezoneStandard()
utc_offset, dst_offset, tz_name = std1[1]
offsetfrom = dst1[1][0]
standard.add('dtstart', std1[0] + offsetfrom)
standard.add('rdate', std1[0] + offsetfrom)
standard.add('rdate', std2[0] + offsetfrom)
standard.add('tzoffsetfrom', offsetfrom)
standard.add('tzoffsetto', utc_offset)
standard.add('tzname', tz_name)
vtimezone.add_component(standard)
return vtimezone
|
More like this
- Add custom fields to the built-in Group model by jmoppel 1 month, 2 weeks ago
- Month / Year SelectDateWidget based on django SelectDateWidget by pierreben 5 months ago
- Python Django CRUD Example Tutorial by tuts_station 5 months, 2 weeks ago
- Browser-native date input field by kytta 7 months ago
- Generate and render HTML Table by LLyaudet 7 months, 1 week ago
Comments
Thank you for this! I extended this solution to support southern hemisphere timezones (DST starts at opposite time of year) and timezones with no DST:
#
Please login first before commenting.