Changes between Initial Version and Version 1 of Ticket #36747


Ignore:
Timestamp:
Nov 20, 2025, 4:47:43 AM (4 hours ago)
Author:
florianvazelle
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #36747 – Description

    initial v1  
    5353
    5454Django should capture each calendar unit, or clearly state limitations.
    55 
    56 == **Proposed Fix**
    57 
    58 1. Replace the current `iso8601_duration_re` with one that uses distinct group names for each ISO-8601 calendar unit:
    59 
    60 
    61 
    62 {{{
    63 iso8601_duration_re = _lazy_re_compile(
    64     r"^(?P<sign>[-+]?)"
    65     r"P"
    66     r"(?:(?P<years>\d+([.,]\d+)?)Y)?"
    67     r"(?:(?P<months>\d+([.,]\d+)?)M)?"
    68     r"(?:(?P<weeks>\d+([.,]\d+)?)W)?"
    69     r"(?:(?P<days>\d+([.,]\d+)?)D)?"
    70     r"(?:T"
    71     r"(?:(?P<hours>\d+([.,]\d+)?)H)?"
    72     r"(?:(?P<minutes>\d+([.,]\d+)?)M)?"
    73     r"(?:(?P<seconds>\d+([.,]\d+)?)S)?"
    74     r")?"
    75     r"$"
    76 )
    77 }}}
    78 
    79 
    80 
    81 2. Extend `parse_duration()` to convert these new fields to timedelta.
    82 
    83 
    84 {{{
    85 def parse_duration(value):
    86     match = (
    87         standard_duration_re.match(value)
    88         or iso8601_duration_re.match(value)
    89         or postgres_interval_re.match(value)
    90     )
    91     if match:
    92         kw = match.groupdict()
    93         sign = -1 if kw.pop("sign", "+") == "-" else 1
    94         if kw.get("microseconds"):
    95             kw["microseconds"] = kw["microseconds"].ljust(6, "0")
    96         kw = {k: float(v.replace(",", ".")) for k, v in kw.items() if v is not None}
    97         days = datetime.timedelta(kw.pop("days", 0.0) or 0.0)
    98 
    99         if match.re == iso8601_duration_re:
    100 +           years = kw.pop("years", 0.0)
    101 +           months = kw.pop("months", 0.0)
    102 +           weeks = kw.pop("weeks", 0.0)
    103 +           
    104 +           days = datetime.timedelta(years=years, months=months, days=kw.pop("days", 0.0) + (weeks * 7))
    105             days *= sign
    106 
    107         return days + sign * datetime.timedelta(**kw)
    108 }}}
    109 
    110 
    111 I can provide a full patch (tests + implementation) if desired.
Back to Top