Opened 3 weeks ago

Last modified 7 days ago

#36747 assigned Cleanup/optimization

parse_duration() fails to parse valid ISO-8601 durations including years, months, and weeks due to incorrect regex

Reported by: florianvazelle Owned by: Varun Kasyap Pentamaraju
Component: Utilities Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by florianvazelle)

Description

django.utils.dateparse.parse_duration() claims to support ISO-8601 duration strings, but the current implementation only handles the PnDTnHnMnS subset. Valid ISO-8601 components such as years (Y), months (M), and weeks (W) are not supported.

The internal regex used for ISO-8601 durations:

iso8601_duration_re = _lazy_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"$"
)

This means Django currently rejects valid duration strings such as:

P1Y2M
P3W
P1Y
P2M10DT2H

Despite the documentation suggesting ISO-8601 support, these forms cannot be parsed.

Steps to Reproduce

from django.utils.dateparse import parse_duration

parse_duration("P1Y")      # returns None
parse_duration("P2M")      # returns None
parse_duration("P3W")      # returns None
parse_duration("P1Y2M3DT4H")  # returns None

Expected Behavior

parse_duration() should parse all valid ISO-8601 durations that can be represented as timedelta, including:

  • PnW
  • PnYnMnD
  • ...

Django should capture each calendar unit, or clearly state limitations.

Change History (5)

comment:1 by florianvazelle, 3 weeks ago

Description: modified (diff)

comment:2 by David, 3 weeks ago

This is a limit of supporting Python's timedelta which does not support years and months: https://docs.python.org/3/library/datetime.html#timedelta-objects.
Yet it supports weeks, thus the parsing in django could be improved to also support ISO8601 duration with weeks.

If you need to support every IS08601 duration you can use https://github.com/CodeYellowBV/django-relativedelta which offers support for relativedelta which implements a more complete timedelta class.

comment:3 by Jacob Walls, 3 weeks ago

Component: UncategorizedUtilities
Triage Stage: UnreviewedAccepted
Type: BugCleanup/optimization
Version: 5.2dev

Very helpful triage, David. I'd accept a PR that added support for weeks and documented that years and months are not supported.

comment:4 by Varun Kasyap Pentamaraju, 3 weeks ago

Owner: set to Varun Kasyap Pentamaraju
Status: newassigned

comment:5 by Varun Kasyap Pentamaraju, 3 weeks ago

Has patch: set
Version 0, edited 3 weeks ago by Varun Kasyap Pentamaraju (next)
Note: See TracTickets for help on using tickets.
Back to Top