def deserialize_dt(text): try: year, month, day = int(text[:4]), int(text[4:6]), int(text[6:8]) except ValueError: raise exceptions.DeserializationError('malformed date-time: %r' % text) if u'T' in text: # time is also specified try: hour, minute, second = ( int(text[9:11]), int(text[11:13]), int(text[13:15])) except ValueError: raise exceptions.DeserializationError('malformed date-time: %r' % text) else: # only date is specified, use midnight hour, minute, second = (0, 0, 0) if u'Z' in text: # time is in utc tzinfo = pytz.utc else: # right now there is no support for VTIMEZONE/TZID since # this is a partial implementation of rfc2445 so we'll # just use the time zone specified in the Django settings. tzinfo = localtz dt = datetime.datetime( year, month, day, hour, minute, second, tzinfo=tzinfo) dt = dt.astimezone(localtz) # set tz to settings.TIME_ZONE and return offset-naive datetime return datetime.datetime( dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
def deserialize_dt(text): """ Deserialize a rfc2445 text to a datetime. The setting RECURRENCE_USE_TZ determines if a naive or timezone aware datetime is returned. If this setting is not present the setting USE_TZ is used as a default. This setting is accessed via the `.settings.deserialize_tz` function. """ try: year, month, day = int(text[:4]), int(text[4:6]), int(text[6:8]) except ValueError: raise exceptions.DeserializationError('malformed date-time: %r' % text) if u'T' in text: # time is also specified try: hour, minute, second = (int(text[9:11]), int(text[11:13]), int(text[13:15])) except ValueError: raise exceptions.DeserializationError( 'malformed date-time: %r' % text) else: # only date is specified, use midnight hour, minute, second = (0, 0, 0) if u'Z' in text: # time is in utc tzinfo = pytz.utc else: # right now there is no support for VTIMEZONE/TZID since # this is a partial implementation of rfc2445 so we'll # just use the time zone specified in the Django settings. tzinfo = localtz() dt = datetime.datetime(year, month, day, hour, minute, second, tzinfo=tzinfo) if settings.deserialize_tz(): return dt dt = dt.astimezone(localtz()) # set tz to settings.TIME_ZONE and return offset-naive datetime return datetime.datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
def deserialize(text): """ Deserialize a rfc2445 formatted string. This is a basic parser that is a partial implementation of rfc2445 which pertains to specifying recurring date/times. Limitations include: - Only collects `DTSTART`, `DTEND`, `RRULE`, `EXRULE`, `RDATE`, and `EXDATE` properties. - Does not capture parameter options (i.e. RDATE;VALUE=PERIOD). `dateutil.rrule` does not support anything other than `DATE-TIME` parameter types. - `VTIMEZONE` and `TZID` can't be specified, so dates without the 'Z' marker will be localized to `settings.TIME_ZONE`. `datetime.datetime` objects in `Recurrence`/`Rrule` objects will be serialized as UTC. - The `DTSTART`, `DTEND`, `RDATE` and `EXDATE` properties also only support the `DATE-TIME` type. :Returns: A `Recurrence` instance. """ def deserialize_dt(text): try: year, month, day = int(text[:4]), int(text[4:6]), int(text[6:8]) except ValueError: raise exceptions.DeserializationError('malformed date-time: %r' % text) if u'T' in text: # time is also specified try: hour, minute, second = (int(text[9:11]), int(text[11:13]), int(text[13:15])) except ValueError: raise exceptions.DeserializationError( 'malformed date-time: %r' % text) else: # only date is specified, use midnight hour, minute, second = (0, 0, 0) if u'Z' in text: # time is in utc tzinfo = pytz.utc else: # right now there is no support for VTIMEZONE/TZID since # this is a partial implementation of rfc2445 so we'll # just use the time zone specified in the Django settings. tzinfo = localtz dt = datetime.datetime(year, month, day, hour, minute, second, tzinfo=tzinfo) dt = dt.astimezone(localtz) # set tz to settings.TIME_ZONE and return offset-naive datetime return datetime.datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second) dtstart, dtend, rrules, exrules, rdates, exdates = None, None, [], [], [], [] tokens = re.compile(u'(DTSTART|DTEND|RRULE|EXRULE|RDATE|EXDATE)[^:]*:(.*)', re.MULTILINE).findall(text) if not tokens and text: raise exceptions.DeserializationError('malformed data') for label, param_text in tokens: if not param_text: raise exceptions.DeserializationError('empty property: %r' % label) if u'=' not in param_text: params = param_text else: params = {} param_tokens = filter(lambda p: p, param_text.split(u';')) for item in param_tokens: try: param_name, param_value = map(lambda i: i.strip(), item.split(u'=', 1)) except ValueError: raise exceptions.DeserializationError( 'missing parameter value: %r' % item) params[param_name] = map(lambda i: i.strip(), param_value.split(u',')) if label in (u'RRULE', u'EXRULE'): kwargs = {} for key, value in params.items(): if key == u'FREQ': try: kwargs[str(key.lower())] = list( Rule.frequencies).index(value[0]) except ValueError: raise exceptions.DeserializationError( 'bad frequency value: %r' % value[0]) elif key == u'INTERVAL': try: kwargs[str(key.lower())] = int(value[0]) except ValueError: raise exceptions.DeserializationError( 'bad interval value: %r' % value[0]) elif key == u'WKST': try: kwargs[str(key.lower())] = to_weekday(value[0]) except ValueError: raise exceptions.DeserializationError( 'bad weekday value: %r' % value[0]) elif key == u'COUNT': try: kwargs[str(key.lower())] = int(value[0]) except ValueError: raise exceptions.DeserializationError( 'bad count value: %r' % value[0]) elif key == u'UNTIL': kwargs[str(key.lower())] = deserialize_dt(value[0]) elif key == u'BYDAY': bydays = [] for v in value: try: bydays.append(to_weekday(v)) except ValueError: raise exceptions.DeserializationError( 'bad weekday value: %r' % v) kwargs[str(key.lower())] = bydays elif key.lower() in Rule.byparams: numbers = [] for v in value: try: numbers.append(int(v)) except ValueError: raise exceptions.DeserializationError( 'bad value: %r' % value) kwargs[str(key.lower())] = numbers else: raise exceptions.DeserializationError('bad parameter: %r' % key) if 'freq' not in kwargs: raise exceptions.DeserializationError( 'frequency parameter missing from rule') if label == u'RRULE': rrules.append(Rule(**kwargs)) else: exrules.append(Rule(**kwargs)) elif label == u'DTSTART': dtstart = deserialize_dt(params) elif label == u'DTEND': dtend = deserialize_dt(params) elif label == u'RDATE': rdates.append(deserialize_dt(params)) elif label == u'EXDATE': exdates.append(deserialize_dt(params)) return Recurrence(dtstart, dtend, rrules, exrules, rdates, exdates)