class vDatetime(object): """Render and generates icalendar datetime format. vDatetime is timezone aware and uses the pytz library, an implementation of the Olson database in Python. When a vDatetime object is created from an ical string, you can pass a valid pytz timezone identifier. When a vDatetime object is created from a python datetime object, it uses the tzinfo component, if present. Otherwise an timezone-naive object is created. Be aware that there are certain limitations with timezone naive DATE-TIME components in the icalendar standard. """ def __init__(self, dt): self.dt = dt self.params = Parameters() def to_ical(self): dt = self.dt tzid = tzid_from_dt(dt) s = "%04d%02d%02dT%02d%02d%02d" % (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second) if tzid == 'UTC': s += "Z" elif tzid: self.params.update({'TZID': tzid}) return s.encode('utf-8') @staticmethod def from_ical(ical, timezone=None): tzinfo = None if timezone: try: tzinfo = pytz.timezone(timezone) except pytz.UnknownTimeZoneError: if timezone in WINDOWS_TO_OLSON: tzinfo = pytz.timezone(WINDOWS_TO_OLSON.get(timezone)) else: tzinfo = _timezone_cache.get(timezone, None) try: timetuple = ( int(ical[:4]), # year int(ical[4:6]), # month int(ical[6:8]), # day int(ical[9:11]), # hour int(ical[11:13]), # minute int(ical[13:15]), # second ) if tzinfo: return tzinfo.localize(datetime(*timetuple)) elif not ical[15:]: return datetime(*timetuple) elif ical[15:16] == 'Z': return pytz.utc.localize(datetime(*timetuple)) else: raise ValueError(ical) except: raise ValueError('Wrong datetime format: %s' % ical)
class vDDDTypes(object): """A combined Datetime, Date or Duration parser/generator. Their format cannot be confused, and often values can be of either types. So this is practical. """ def __init__(self, dt): if not isinstance(dt, (datetime, date, timedelta, time)): raise ValueError('You must use datetime, date, timedelta or time') if isinstance(dt, datetime): self.params = Parameters({'value': 'DATE-TIME'}) elif isinstance(dt, date): self.params = Parameters({'value': 'DATE'}) elif isinstance(dt, time): self.params = Parameters({'value': 'TIME'}) if (isinstance(dt, datetime) or isinstance(dt, time))\ and getattr(dt, 'tzinfo', False): tzinfo = dt.tzinfo if tzinfo is not pytz.utc and\ (tzutc is None or not isinstance(tzinfo, tzutc)): # set the timezone as a parameter to the property tzid = tzid_from_dt(dt) if tzid: self.params.update({'TZID': tzid}) self.dt = dt def to_ical(self): dt = self.dt if isinstance(dt, datetime): return vDatetime(dt).to_ical() elif isinstance(dt, date): return vDate(dt).to_ical() elif isinstance(dt, timedelta): return vDuration(dt).to_ical() elif isinstance(dt, time): return vTime(dt).to_ical() else: raise ValueError('Unknown date type') @classmethod def from_ical(cls, ical, timezone=None): if isinstance(ical, cls): return ical.dt u = ical.upper() if u.startswith(('P', '-P', '+P')): return vDuration.from_ical(ical) if len(ical) in (15, 16): return vDatetime.from_ical(ical, timezone=timezone) elif len(ical) == 8: return vDate.from_ical(ical) elif len(ical) in (6, 7): return vTime.from_ical(ical) else: raise ValueError( "Expected datetime, date, or time, got: '%s'" % ical )
class vDDDTypes(object): """A combined Datetime, Date or Duration parser/generator. Their format cannot be confused, and often values can be of either types. So this is practical. """ def __init__(self, dt): if not isinstance(dt, (datetime, date, timedelta, time)): raise ValueError('You must use datetime, date, timedelta or time') if isinstance(dt, datetime): self.params = Parameters({'value': 'DATE-TIME'}) elif isinstance(dt, date): self.params = Parameters({'value': 'DATE'}) elif isinstance(dt, time): self.params = Parameters({'value': 'TIME'}) if (isinstance(dt, datetime) or isinstance(dt, time))\ and getattr(dt, 'tzinfo', False): tzinfo = dt.tzinfo if tzinfo is not pytz.utc and\ (tzutc is None or not isinstance(tzinfo, tzutc)): # set the timezone as a parameter to the property tzid = tzid_from_dt(dt) if tzid: self.params.update({'TZID': tzid}) self.dt = dt def to_ical(self): dt = self.dt if isinstance(dt, datetime): return vDatetime(dt).to_ical() elif isinstance(dt, date): return vDate(dt).to_ical() elif isinstance(dt, timedelta): return vDuration(dt).to_ical() elif isinstance(dt, time): return vTime(dt).to_ical() else: raise ValueError('Unknown date type') @classmethod def from_ical(cls, ical, timezone=None): if isinstance(ical, cls): return ical.dt u = ical.upper() if u.startswith(('P', '-P', '+P')): return vDuration.from_ical(ical) if len(ical) in (15, 16): return vDatetime.from_ical(ical, timezone=timezone) elif len(ical) == 8: return vDate.from_ical(ical) elif len(ical) in (6, 7): return vTime.from_ical(ical) else: raise ValueError("Expected datetime, date, or time, got: '%s'" % ical)
class vDatetime(object): """Render and generates icalendar datetime format. vDatetime is timezone aware and uses the pytz library, an implementation of the Olson database in Python. When a vDatetime object is created from an ical string, you can pass a valid pytz timezone identifier. When a vDatetime object is created from a python datetime object, it uses the tzinfo component, if present. Otherwise an timezone-naive object is created. Be aware that there are certain limitations with timezone naive DATE-TIME components in the icalendar standard. """ def __init__(self, dt): self.dt = dt self.params = Parameters() def to_ical(self): dt = self.dt tzid = tzid_from_dt(dt) s = "%04d%02d%02dT%02d%02d%02d" % ( dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second ) if tzid == 'UTC': s += "Z" elif tzid: self.params.update({'TZID': tzid}) return s.encode('utf-8') @staticmethod def from_ical(ical, timezone=None): tzinfo = None if timezone: try: tzinfo = pytz.timezone(timezone) except pytz.UnknownTimeZoneError: tzinfo = _timezone_cache.get(timezone, None) try: timetuple = ( int(ical[:4]), # year int(ical[4:6]), # month int(ical[6:8]), # day int(ical[9:11]), # hour int(ical[11:13]), # minute int(ical[13:15]), # second ) if tzinfo: return tzinfo.localize(datetime(*timetuple)) elif not ical[15:]: return datetime(*timetuple) elif ical[15:16] == 'Z': return pytz.utc.localize(datetime(*timetuple)) else: raise ValueError(ical) except: raise ValueError('Wrong datetime format: %s' % ical)
class vDatetime: """ Render and generates icalendar datetime format. vDatetime is timezone aware and uses the pytz library, an implementation of the Olson database in Python. When a vDatetime object is created from an ical string, the string must be a valid pytz timezone identifier. When and vDatetime object is created from a python datetime object, it uses the tzinfo component, if present. Otherwise an timezone-naive object is created. Be aware that there are certain limitations with timezone naive DATE-TIME components in the icalendar standard. >>> d = datetime(2001, 1,1, 12, 30, 0) >>> dt = vDatetime(d) >>> dt.to_ical() '20010101T123000' >>> vDatetime.from_ical('20000101T120000') datetime.datetime(2000, 1, 1, 12, 0) >>> dutc = datetime(2001, 1,1, 12, 30, 0, tzinfo=pytz.utc) >>> vDatetime(dutc).to_ical() '20010101T123000Z' >>> vDatetime.from_ical('20010101T000000') datetime.datetime(2001, 1, 1, 0, 0) >>> vDatetime.from_ical('20010101T000000A') Traceback (most recent call last): ... ValueError: Wrong datetime format: 20010101T000000A >>> utc = vDatetime.from_ical('20010101T000000Z') >>> vDatetime(utc).to_ical() '20010101T000000Z' 1 minute before transition to DST >>> dat = vDatetime.from_ical('20120311T015959', 'America/Denver') >>> dat.strftime('%Y%m%d%H%M%S %z') '20120311015959 -0700' After transition to DST >>> dat = vDatetime.from_ical('20120311T030000', 'America/Denver') >>> dat.strftime('%Y%m%d%H%M%S %z') '20120311030000 -0600' >>> dat = vDatetime.from_ical('20101010T000000', 'Europe/Vienna') >>> vDatetime(dat).to_ical() '20101010T000000' """ def __init__(self, dt): self.dt = dt self.params = Parameters() def to_ical(self): dt = self.dt tzid = dt.tzinfo and dt.tzinfo.zone or None if tzid == 'UTC': return dt.strftime("%Y%m%dT%H%M%SZ") elif tzid: self.params.update({'TZID': tzid}) return dt.strftime("%Y%m%dT%H%M%S") def from_ical(ical, timezone=None): """ Parses the data format from ical text format. """ tzinfo = None if timezone: try: tzinfo = pytz.timezone(timezone) except pytz.UnknownTimeZoneError: pass try: timetuple = map(int, (( ical[:4], # year ical[4:6], # month ical[6:8], # day ical[9:11], # hour ical[11:13], # minute ical[13:15], # second ))) if tzinfo: return tzinfo.localize(datetime(*timetuple)) elif not ical[15:]: return datetime(*timetuple) elif ical[15:16] == 'Z': return datetime(tzinfo=pytz.utc, *timetuple) else: raise ValueError, ical except: raise ValueError, 'Wrong datetime format: %s' % ical from_ical = staticmethod(from_ical)
class vDatetime: """ Render and generates icalendar datetime format. vDatetime is timezone aware and uses the pytz library, an implementation of the Olson database in Python. When a vDatetime object is created from an ical string, the string must be a valid pytz timezone identifier. When and vDatetime object is created from a python datetime object, it uses the tzinfo component, if present. Otherwise an timezone-naive object is created. Be aware that there are certain limitations with timezone naive DATE-TIME components in the icalendar standard. >>> from icalendar.tools import utctz >>> d = datetime(2001, 1,1, 12, 30, 0) >>> dt = vDatetime(d) >>> dt.to_ical() '20010101T123000' >>> vDatetime.from_ical('20000101T120000') datetime.datetime(2000, 1, 1, 12, 0) >>> dutc = datetime(2001, 1,1, 12, 30, 0, tzinfo=utctz()) >>> vDatetime(dutc).to_ical() '20010101T123000Z' >>> vDatetime.from_ical('20010101T000000') datetime.datetime(2001, 1, 1, 0, 0) >>> vDatetime.from_ical('20010101T000000A') Traceback (most recent call last): ... ValueError: Wrong datetime format: 20010101T000000A >>> utc = vDatetime.from_ical('20010101T000000Z') >>> vDatetime(utc).to_ical() '20010101T000000Z' >>> dat = vDatetime.from_ical('20101010T000000', 'Europe/Vienna') >>> vDatetime(dat).to_ical() '20101010T000000' """ def __init__(self, dt): self.dt = dt self.params = Parameters() def to_ical(self): dt = self.dt tzid = dt.tzinfo and dt.tzinfo.zone or None if tzid == 'UTC': return dt.strftime("%Y%m%dT%H%M%SZ") elif tzid: self.params.update({'TZID': tzid}) # return "TZID=%s;%s" % (timezone, self.dt.strftime("%Y%m%dT%H%M%S")) The timezone should not be printed with the date, but rather in the containing component. return dt.strftime("%Y%m%dT%H%M%S") def from_ical(ical, timezone=None): """ Parses the data format from ical text format. """ # TODO: ical string should better contain also the TZID property. if timezone: timezone = normalized_timezone(timezone) try: timetuple = map(int, (( ical[:4], # year ical[4:6], # month ical[6:8], # day ical[9:11], # hour ical[11:13], # minute ical[13:15], # second ))) if timezone: return datetime(tzinfo=timezone, *timetuple) elif not ical[15:]: return datetime(*timetuple) elif ical[15:16] == 'Z': return datetime(tzinfo=utctz(), *timetuple) else: raise ValueError, ical except: raise ValueError, 'Wrong datetime format: %s' % ical from_ical = staticmethod(from_ical)
class vDDDTypes: """A combined Datetime, Date or Duration parser/generator. Their format cannot be confused, and often values can be of either types. So this is practical. >>> d = vDDDTypes.from_ical('20010101T123000') >>> type(d) <type 'datetime.datetime'> >>> repr(vDDDTypes.from_ical('20010101T123000Z'))[:65] 'datetime.datetime(2001, 1, 1, 12, 30, tzinfo=<UTC>)' >>> d = vDDDTypes.from_ical('20010101') >>> type(d) <type 'datetime.date'> >>> vDDDTypes.from_ical('P31D') datetime.timedelta(31) >>> vDDDTypes.from_ical('-P31D') datetime.timedelta(-31) Bad input >>> vDDDTypes(42) Traceback (most recent call last): ... ValueError: You must use datetime, date, timedelta or time """ def __init__(self, dt): "Returns vDate from" if type(dt) not in (datetime, date, timedelta, time): raise ValueError ('You must use datetime, date, timedelta or time') if isinstance(dt, datetime): self.params = Parameters(dict(value='DATE-TIME')) elif isinstance(dt, date): self.params = Parameters(dict(value='DATE')) elif isinstance(dt, time): self.params = Parameters(dict(value='TIME')) if (isinstance(dt, datetime) or isinstance(dt, time))\ and getattr(dt, 'tzinfo', False): tzinfo = dt.tzinfo if tzinfo is not pytz.utc and not isinstance(tzinfo, tzutc): # set the timezone as a parameter to the property tzid = tzid_from_dt(dt) if tzid: self.params.update({'TZID': tzid}) self.dt = dt def to_ical(self): dt = self.dt if isinstance(dt, datetime): return vDatetime(dt).to_ical() elif isinstance(dt, date): return vDate(dt).to_ical() elif isinstance(dt, timedelta): return vDuration(dt).to_ical() elif isinstance(dt, time): return vTime(dt).to_ical() else: raise ValueError('Unknown date type') @staticmethod def from_ical(ical, timezone=None): "Parses the data format from ical text format" if isinstance(ical, vDDDTypes): return ical.dt u = ical.upper() if u.startswith('-P') or u.startswith('P'): return vDuration.from_ical(ical) try: return vDatetime.from_ical(ical, timezone=timezone) except ValueError: try: return vDate.from_ical(ical) except ValueError: return vTime.from_ical(ical)
class vDatetime: """Render and generates icalendar datetime format. vDatetime is timezone aware and uses the pytz library, an implementation of the Olson database in Python. When a vDatetime object is created from an ical string, the string must be a valid pytz timezone identifier. When and vDatetime object is created from a python datetime object, it uses the tzinfo component, if present. Otherwise an timezone-naive object is created. Be aware that there are certain limitations with timezone naive DATE-TIME components in the icalendar standard. >>> d = datetime(2001, 1,1, 12, 30, 0) >>> dt = vDatetime(d) >>> dt.to_ical() '20010101T123000' >>> vDatetime.from_ical('20000101T120000') datetime.datetime(2000, 1, 1, 12, 0) >>> dutc = datetime(2001, 1,1, 12, 30, 0, tzinfo=pytz.utc) >>> vDatetime(dutc).to_ical() '20010101T123000Z' >>> vDatetime.from_ical('20010101T000000') datetime.datetime(2001, 1, 1, 0, 0) >>> vDatetime.from_ical('20010101T000000A') Traceback (most recent call last): ... ValueError: Wrong datetime format: 20010101T000000A >>> utc = vDatetime.from_ical('20010101T000000Z') >>> vDatetime(utc).to_ical() '20010101T000000Z' 1 minute before transition to DST >>> dat = vDatetime.from_ical('20120311T015959', 'America/Denver') >>> dat.strftime('%Y%m%d%H%M%S %z') '20120311015959 -0700' After transition to DST >>> dat = vDatetime.from_ical('20120311T030000', 'America/Denver') >>> dat.strftime('%Y%m%d%H%M%S %z') '20120311030000 -0600' >>> dat = vDatetime.from_ical('20101010T000000', 'Europe/Vienna') >>> vDatetime(dat).to_ical() '20101010T000000' """ def __init__(self, dt): self.dt = dt self.params = Parameters() def to_ical(self): dt = self.dt tzid = dt.tzinfo and dt.tzinfo.zone or None if tzid == 'UTC': return dt.strftime("%Y%m%dT%H%M%SZ") elif tzid: self.params.update({'TZID': tzid}) return dt.strftime("%Y%m%dT%H%M%S") def from_ical(ical, timezone=None): """ Parses the data format from ical text format. """ tzinfo = None if timezone: try: tzinfo = pytz.timezone(timezone) except pytz.UnknownTimeZoneError: pass try: timetuple = map( int, (( ical[:4], # year ical[4:6], # month ical[6:8], # day ical[9:11], # hour ical[11:13], # minute ical[13:15], # second ))) if tzinfo: return tzinfo.localize(datetime(*timetuple)) elif not ical[15:]: return datetime(*timetuple) elif ical[15:16] == 'Z': return datetime(tzinfo=pytz.utc, *timetuple) else: raise ValueError, ical except: raise ValueError, 'Wrong datetime format: %s' % ical from_ical = staticmethod(from_ical)
class vDatetime: """ Render and generates iCalendar datetime format. Important: if tzinfo is defined it renders itself as "date with utc time" Meaning that it has a 'Z' appended, and is in absolute time. >>> d = datetime(2001, 1,1, 12, 30, 0) >>> dt = vDatetime(d) >>> dt.to_ical() '20010101T123000' >>> vDatetime.from_ical('20000101T120000') datetime.datetime(2000, 1, 1, 12, 0) >>> dutc = datetime(2001, 1,1, 12, 30, 0, tzinfo=UTC) >>> vDatetime(dutc).to_ical() '20010101T123000Z' >>> vDatetime.from_ical('20010101T000000') datetime.datetime(2001, 1, 1, 0, 0) >>> vDatetime.from_ical('20010101T000000A') Traceback (most recent call last): ... ValueError: Wrong datetime format: 20010101T000000A >>> utc = vDatetime.from_ical('20010101T000000Z') >>> vDatetime(utc).to_ical() '20010101T000000Z' >>> dat = vDatetime.from_ical('20101010T000000', 'Europe/Vienna') >>> vDatetime(dat).to_ical() 'TZID=CET;20101010T000000' """ def __init__(self, dt): self.dt = dt self.params = Parameters() def to_ical(self): timezone = self.dt.tzname() if timezone == 'UTC' or self.dt.tzinfo == UTC: return self.dt.strftime("%Y%m%dT%H%M%SZ") elif timezone: self.params.update({'TZID': timezone}) return "TZID=%s;%s" % (timezone, self.dt.strftime("%Y%m%dT%H%M%S")) return self.dt.strftime("%Y%m%dT%H%M%S") def from_ical(ical, timezone=None): """ Parses the data format from ical text format. """ # TODO: ical string should better contain also the TZID property.deleter( if timezone: timezone = timezone_from_string(timezone) try: timetuple = map(int, (( ical[:4], # year ical[4:6], # month ical[6:8], # day ical[9:11], # hour ical[11:13], # minute ical[13:15], # second ))) if timezone: return datetime(tzinfo=timezone, *timetuple) elif not ical[15:]: return datetime(*timetuple) elif ical[15:16] == 'Z': timetuple += [0, UTC] return datetime(*timetuple) else: raise ValueError, ical except: raise ValueError, 'Wrong datetime format: %s' % ical from_ical = staticmethod(from_ical)