def parse_iso8601_interval(interval_str): """ Parse an iso8601 time interval string. @type interval_str: str @param interval_str: iso8601 time interval string to parse @rtype: tuple of (int or None, datetime.datetime or None, datetime.timedelta) @return: a tuple of the length of the interval, the starting time of the interval or None if not present, and number of recurrences of the interval or None if notpresent """ # iso8601 supports a number of different time interval formats, however, # only one is really useful to pulp: # <recurrences>/<start time>/<interval duration> # NOTE that recurrences and start time are both optional # XXX this algorithm will mistakenly parse the format: # <recurrences>/<interval duration>/<end time> interval = None start_time = None recurrences = None for part in _iso8601_delimiter.split(interval_str): if _iso8601_delimiter.match(part): continue match = _iso8601_recurrences.match(part) if match is not None: if recurrences is not None: raise isodate.ISO8601Error('Multiple recurrences specified') recurrences = int(match.group('num')) elif part.startswith('P'): if interval is not None: raise isodate.ISO8601Error( 'Multiple interval durations specified') interval = parse_iso8601_duration(part) else: if start_time is not None: raise isodate.ISO8601Error( 'Interval with start and end times is not supported') start_time = parse_iso8601_datetime(part) # the interval is the only required part if interval is None: raise isodate.ISO8601Error('No interval specification found') # if the interval contains months or years, isodate will use it's own # internal Duration class instead of timedelta # pulp cannot handle Duration instances if a start_time is not provided if isinstance(interval, isodate.Duration) and start_time is None: raise isodate.ISO8601Error( 'Intervals with year and month values are not valid without a start time' ) return (interval, start_time, recurrences)
def parse_iso8601_duration(duration_str): """ Parse an iso8601 duration string. @type duration_str: str @param: duration_str: iso8601 duration string to parse @rtype: isodate.Duration or datetime.timedelta instance """ try: return isodate.parse_duration(duration_str) except (ValueError, isodate.ISO8601Error): msg = _('Malformed ISO8601 duration string: %(d)s') % {'d': duration_str} raise isodate.ISO8601Error(msg), None, sys.exc_info()[2]
def parse_iso8601_datetime(datetime_str): """ Parse an iso8601 datetime string. @type datetime_str: str @param datetime_str: iso8601 datetime string to parse @rtype: datetime.datetime instance """ try: return isodate.parse_datetime(datetime_str) except (ValueError, isodate.ISO8601Error): msg = _('Malformed ISO8601 date-time string: %(d)s') % {'d': datetime_str} raise isodate.ISO8601Error(msg), None, sys.exc_info()[2]
def parse_datetime(datetimestring): ''' Parses ISO 8601 date-times into datetime.datetime objects. This function uses parse_date and parse_time to do the job, so it allows more combinations of date and time representations, than the actual ISO 8601:2004 standard allows. ''' try: datestring, timestring = re.split('T| ', datetimestring) except ValueError: raise isodate.ISO8601Error( "ISO 8601 time designator 'T' or ' ' missing. Unable to parse " "datetime string %r" % datetimestring) tmpdate = isodate.parse_date(datestring) tmptime = isodate.parse_time(timestring) return datetime.datetime.combine(tmpdate, tmptime)