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 )
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:
PnWPnYnMnD- ...
Django should capture each calendar unit, or clearly state limitations.
Change History (5)
comment:1 by , 3 weeks ago
| Description: | modified (diff) |
|---|
comment:2 by , 3 weeks ago
comment:3 by , 3 weeks ago
| Component: | Uncategorized → Utilities |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
| Type: | Bug → Cleanup/optimization |
| Version: | 5.2 → dev |
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 , 3 weeks ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:5 by , 3 weeks ago
| Has patch: | set |
|---|
This is a limit of supporting Python's
timedeltawhich 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
relativedeltawhich implements a more complete timedelta class.