def _parse_duration_prescribed(durationstr, builder): # durationstr can be of the form PnYnMnDTnHnMnS or PnW # Don't allow negative elements # https://bitbucket.org/nielsenb/aniso8601/issues/20/negative-duration if durationstr.find("-") != -1: raise NegativeDurationError("ISO 8601 durations must be positive.") # Make sure the end character is valid # https://bitbucket.org/nielsenb/aniso8601/issues/9/durations-with-trailing-garbage-are-parsed if durationstr[-1] not in ["Y", "M", "D", "H", "S", "W"]: raise ISOFormatError("ISO 8601 duration must end with a valid " "character.") # Make sure only the lowest order element has decimal precision separator_index = find_separator(durationstr) if separator_index != -1: remaining = durationstr[separator_index + 1 :] if find_separator(remaining) != -1: raise ISOFormatError( "ISO 8601 allows only lowest order element to " "have a decimal fraction." ) # There should only ever be 1 letter after a decimal if there is more # then one, the string is invalid lettercount = 0 for character in remaining: if character.isalpha() is True: lettercount += 1 if lettercount > 1: raise ISOFormatError( "ISO 8601 duration must end with " "a single valid character." ) # Do not allow W in combination with other designators # https://bitbucket.org/nielsenb/aniso8601/issues/2/week-designators-should-not-be-combinable if ( durationstr.find("W") != -1 and _has_any_component(durationstr, ["Y", "M", "D", "H", "S"]) is True ): raise ISOFormatError( "ISO 8601 week designators may not be combined " "with other time designators." ) # Parse the elements of the duration if durationstr.find("T") == -1: return _parse_duration_prescribed_notime(durationstr, builder) return _parse_duration_prescribed_time(durationstr, builder)
def _parse_duration_prescribed_notime(durationstr, builder): # durationstr can be of the form PnYnMnD or PnW # Don't allow negative elements # https://bitbucket.org/nielsenb/aniso8601/issues/20/negative-duration if durationstr.find('-') != -1: raise NegativeDurationError('ISO 8601 durations must be positive.') # Make sure no time portion is included # https://bitbucket.org/nielsenb/aniso8601/issues/7/durations-with-time-components-before-t if _has_any_component(durationstr, ['H', 'S']): raise ISOFormatError( 'ISO 8601 time components not allowed in duration ' 'without prescribed time.') if _component_order_correct(durationstr, ['P', 'Y', 'M', 'D', 'W']) is False: raise ISOFormatError('ISO 8601 duration components must be in the ' 'correct order.') if durationstr.find('Y') != -1: yearstr = _parse_duration_element(durationstr, 'Y') else: yearstr = None if durationstr.find('M') != -1: monthstr = _parse_duration_element(durationstr, 'M') else: monthstr = None if durationstr.find('W') != -1: weekstr = _parse_duration_element(durationstr, 'W') else: weekstr = None if durationstr.find('D') != -1: daystr = _parse_duration_element(durationstr, 'D') else: daystr = None return builder.build_duration(PnY=yearstr, PnM=monthstr, PnW=weekstr, PnD=daystr)
def _parse_duration_prescribed_notime(durationstr, builder): # durationstr can be of the form PnYnMnD or PnW # Don't allow negative elements # https://bitbucket.org/nielsenb/aniso8601/issues/20/negative-duration if durationstr.find("-") != -1: raise NegativeDurationError("ISO 8601 durations must be positive.") # Make sure no time portion is included # https://bitbucket.org/nielsenb/aniso8601/issues/7/durations-with-time-components-before-t if _has_any_component(durationstr, ["H", "S"]): raise ISOFormatError( "ISO 8601 time components not allowed in duration " "without prescribed time.") if _component_order_correct(durationstr, ["P", "Y", "M", "D", "W"]) is False: raise ISOFormatError("ISO 8601 duration components must be in the " "correct order.") if durationstr.find("Y") != -1: yearstr = _parse_duration_element(durationstr, "Y") else: yearstr = None if durationstr.find("M") != -1: monthstr = _parse_duration_element(durationstr, "M") else: monthstr = None if durationstr.find("W") != -1: weekstr = _parse_duration_element(durationstr, "W") else: weekstr = None if durationstr.find("D") != -1: daystr = _parse_duration_element(durationstr, "D") else: daystr = None return builder.build_duration(PnY=yearstr, PnM=monthstr, PnW=weekstr, PnD=daystr)
def _parse_duration_prescribed(durationstr, builder): #durationstr can be of the form PnYnMnDTnHnMnS or PnW #Don't allow negative elements #https://bitbucket.org/nielsenb/aniso8601/issues/20/negative-duration if durationstr.find('-') != -1: raise NegativeDurationError('ISO 8601 durations must be positive.') #Make sure the end character is valid #https://bitbucket.org/nielsenb/aniso8601/issues/9/durations-with-trailing-garbage-are-parsed if durationstr[-1] not in ['Y', 'M', 'D', 'H', 'S', 'W']: raise ISOFormatError('ISO 8601 duration must end with a valid ' 'character.') #Make sure only the lowest order element has decimal precision if durationstr.count('.') > 1: raise ISOFormatError('ISO 8601 allows only lowest order element to ' 'have a decimal fraction.') elif durationstr.count('.') == 1: #There should only ever be 1 letter after a decimal if there is more #then one, the string is invalid lettercount = 0 for character in durationstr.split('.')[1]: if character.isalpha() is True: lettercount += 1 if lettercount > 1: raise ISOFormatError('ISO 8601 duration must end with ' 'a single valid character.') #Do not allow W in combination with other designators #https://bitbucket.org/nielsenb/aniso8601/issues/2/week-designators-should-not-be-combinable if (durationstr.find('W') != -1 and _has_any_component( durationstr, ['Y', 'M', 'D', 'H', 'S']) is True): raise ISOFormatError('ISO 8601 week designators may not be combined ' 'with other time designators.') #Parse the elements of the duration if durationstr.find('T') == -1: return _parse_duration_prescribed_notime(durationstr, builder) return _parse_duration_prescribed_time(durationstr, builder)
def _parse_duration_prescribed_time(durationstr, builder): # durationstr can be of the form PnYnMnDTnHnMnS # Don't allow negative elements # https://bitbucket.org/nielsenb/aniso8601/issues/20/negative-duration if durationstr.find('-') != -1: raise NegativeDurationError('ISO 8601 durations must be positive.') firsthalf = durationstr[:durationstr.find('T')] secondhalf = durationstr[durationstr.find('T'):] # Make sure no time portion is included in the date half # https://bitbucket.org/nielsenb/aniso8601/issues/7/durations-with-time-components-before-t if _has_any_component(firsthalf, ['H', 'S']): raise ISOFormatError('ISO 8601 time components not allowed in date ' 'portion of duration.') if _component_order_correct(firsthalf, ['P', 'Y', 'M', 'D', 'W']) is False: raise ISOFormatError('ISO 8601 duration components must be in the ' 'correct order.') # Make sure no date component is included in the time half if _has_any_component(secondhalf, ['Y', 'D']): raise ISOFormatError('ISO 8601 time components not allowed in date ' 'portion of duration.') if _component_order_correct(secondhalf, ['T', 'H', 'M', 'S']) is False: raise ISOFormatError('ISO 8601 time components in duration must be in ' 'the correct order.') if firsthalf.find('Y') != -1: yearstr = _parse_duration_element(firsthalf, 'Y') else: yearstr = None if firsthalf.find('M') != -1: monthstr = _parse_duration_element(firsthalf, 'M') else: monthstr = None if firsthalf.find('D') != -1: daystr = _parse_duration_element(firsthalf, 'D') else: daystr = None if secondhalf.find('H') != -1: hourstr = _parse_duration_element(secondhalf, 'H') else: hourstr = None if secondhalf.find('M') != -1: minutestr = _parse_duration_element(secondhalf, 'M') else: minutestr = None if secondhalf.find('S') != -1: secondstr = _parse_duration_element(secondhalf, 'S') else: secondstr = None return builder.build_duration(PnY=yearstr, PnM=monthstr, PnD=daystr, TnH=hourstr, TnM=minutestr, TnS=secondstr)
def _parse_duration_prescribed_time(durationstr, builder): # durationstr can be of the form PnYnMnDTnHnMnS # Don't allow negative elements # https://bitbucket.org/nielsenb/aniso8601/issues/20/negative-duration if durationstr.find("-") != -1: raise NegativeDurationError("ISO 8601 durations must be positive.") firsthalf = durationstr[: durationstr.find("T")] secondhalf = durationstr[durationstr.find("T") :] # Make sure no time portion is included in the date half # https://bitbucket.org/nielsenb/aniso8601/issues/7/durations-with-time-components-before-t if _has_any_component(firsthalf, ["H", "S"]): raise ISOFormatError( "ISO 8601 time components not allowed in date " "portion of duration." ) if _component_order_correct(firsthalf, ["P", "Y", "M", "D", "W"]) is False: raise ISOFormatError( "ISO 8601 duration components must be in the " "correct order." ) # Make sure no date component is included in the time half if _has_any_component(secondhalf, ["Y", "D"]): raise ISOFormatError( "ISO 8601 time components not allowed in date " "portion of duration." ) if _component_order_correct(secondhalf, ["T", "H", "M", "S"]) is False: raise ISOFormatError( "ISO 8601 time components in duration must be in " "the correct order." ) if firsthalf.find("Y") != -1: yearstr = _parse_duration_element(firsthalf, "Y") else: yearstr = None if firsthalf.find("M") != -1: monthstr = _parse_duration_element(firsthalf, "M") else: monthstr = None if firsthalf.find("D") != -1: daystr = _parse_duration_element(firsthalf, "D") else: daystr = None if secondhalf.find("H") != -1: hourstr = _parse_duration_element(secondhalf, "H") else: hourstr = None if secondhalf.find("M") != -1: minutestr = _parse_duration_element(secondhalf, "M") else: minutestr = None if secondhalf.find("S") != -1: secondstr = _parse_duration_element(secondhalf, "S") else: secondstr = None return builder.build_duration( PnY=yearstr, PnM=monthstr, PnD=daystr, TnH=hourstr, TnM=minutestr, TnS=secondstr )