0

I am trying to parse the ISO 8601 duration P1Y or P1M, representing one year or one month respectively, using the parse_duration() function of the django.utils.dateparse module. The returned value though is None. The documentation of the function says that it supports ISO 8601 durations. But it seems that it supports the standard without the years or months, because I can successfully parse the duration P2DT12H60M33S, resulting in a timedelta object of 2 days and 46833 seconds. Is this a bug, a feature or am I doing something wrong?

pgmank
  • 5,303
  • 5
  • 36
  • 52

1 Answers1

0

From the source code of dateparse.py module:

# Support the sections of ISO 8601 date representation that are accepted by
# timedelta
iso8601_duration_re = re.compile(
    r'^(?P<sign>[-+]?)'
    r'P'
    r'(?:(?P<days>\d+(.\d+)?)D)?'
    r'(?:T'
    r'(?:(?P<hours>\d+(.\d+)?)H)?'
    r'(?:(?P<minutes>\d+(.\d+)?)M)?'
    r'(?:(?P<seconds>\d+(.\d+)?)S)?'
    r')?'
    r'$'
)

# Support PostgreSQL's day-time interval format, e.g. "3 days 04:05:06". The
# year-month and mixed intervals cannot be converted to a timedelta and thus
# aren't accepted.
postgres_interval_re = re.compile(
    r'^'
    r'(?:(?P<days>-?\d+) (days? ?))?'
    r'(?:(?P<sign>[-+])?'
    r'(?P<hours>\d+):'
    r'(?P<minutes>\d\d):'
    r'(?P<seconds>\d\d)'
    r'(?:\.(?P<microseconds>\d{1,6}))?'
    r')?$'
)

The first regular expression is for parsing the ISO 8601 durations. As the comment above iso8601_duration_re states, only the sections of ISO 8601 duration that are accepted by the timedelta are supported. Where timedelta supports only weeks, days, hours, minutes, seconds, milliseconds and microseconds. This is clearly stated also in the comment above the postgres_interval_re:

The year-month and mixed intervals cannot be converted to a timedelta and thus aren't accepted.

The fact that years or months are not supported, can be also proved by examining the source code. For example the code for the iso8601_duration_re regular expression has parsing instructions only for days, hours, minutes and seconds. There are no instructions for years or months.

I think that there is a reason for not supporting months and years, since their duration is ambiguous. A month can be either 28,29,30 or 31 days and a year can be either 365 or 366 days. This ambiguity is allowed in the ISO 8601, but not allowed in the timedelta object (see this answer). This is because internally it stores the duration in days, seconds and microseconds (see here) and therefore a timedelta of 1 year, for example, could be either 365 days, 0 seconds and 0 microseconds or 366 days, 0 seconds and 0 microseconds.

pgmank
  • 5,303
  • 5
  • 36
  • 52
  • A day can also be 23 or 25 hours, and a minute can be 60 or 61 seconds in case of leap seconds. This is just lazy design. – l0b0 Mar 20 '19 at 02:47