Great question, obviously the "right" solution depends on your expectations for the input (a more reliable data source doesn't need as much input validation).
My approach to parse an ISO8601 duration timestamp only checks that the "PT" prefix is present and will not assume integer values for any of the units:
from datetime import timedeltadef parse_isoduration(isostring, as_dict=False):""" Parse the ISO8601 duration string as hours, minutes, seconds""" separators = {"PT": None,"W": "weeks","D": "days","H": "hours","M": "minutes","S": "seconds", } duration_vals = {} for sep, unit in separators.items(): partitioned = isostring.partition(sep) if partitioned[1] == sep: # Matched this unit isostring = partitioned[2] if sep == "PT": continue # Successful prefix match dur_str = partitioned[0] dur_val = float(dur_str) if "." in dur_str else int(dur_str) duration_vals.update({unit: dur_val}) else: if sep == "PT": raise ValueError("Missing PT prefix") else: # No match for this unit: it's absent duration_vals.update({unit: 0}) if as_dict: return duration_vals else: return tuple(duration_vals.values())dur_isostr = "PT3H2M59.989333S"dur_tuple = parse_isoduration(dur_isostr)dur_dict = parse_isoduration(dur_isostr, as_dict=True)td = timedelta(**dur_dict)s = td.total_seconds()
⇣
>>> dur_tuple(0, 0, 3, 2, 59.989333)>>> dur_dict{'weeks': 0, 'days': 0, 'hours': 3, 'minutes': 2, 'seconds': 59.989333}>>> tddatetime.timedelta(seconds=10979, microseconds=989333)>>> s10979.989333