Fixed #32892 -- Optimized django.utils.dateparse functions by using fromisoformat().

This commit is contained in:
Keryn Knight 2021-07-01 12:05:41 +01:00 committed by Mariusz Felisiak
parent 857320e9e0
commit f35ab74752
1 changed files with 35 additions and 26 deletions

View File

@ -72,10 +72,12 @@ def parse_date(value):
Raise ValueError if the input is well formatted but not a valid date. Raise ValueError if the input is well formatted but not a valid date.
Return None if the input isn't well formatted. Return None if the input isn't well formatted.
""" """
match = date_re.match(value) try:
if match: return datetime.date.fromisoformat(value)
kw = {k: int(v) for k, v in match.groupdict().items()} except ValueError:
return datetime.date(**kw) if match := date_re.match(value):
kw = {k: int(v) for k, v in match.groupdict().items()}
return datetime.date(**kw)
def parse_time(value): def parse_time(value):
@ -87,12 +89,18 @@ def parse_time(value):
Return None if the input isn't well formatted, in particular if it Return None if the input isn't well formatted, in particular if it
contains an offset. contains an offset.
""" """
match = time_re.match(value) try:
if match: # The fromisoformat() method takes time zone info into account and
kw = match.groupdict() # returns a time with a tzinfo component, if possible. However, there
kw['microsecond'] = kw['microsecond'] and kw['microsecond'].ljust(6, '0') # are no circumstances where aware datetime.time objects make sense, so
kw = {k: int(v) for k, v in kw.items() if v is not None} # remove the time zone offset.
return datetime.time(**kw) return datetime.time.fromisoformat(value).replace(tzinfo=None)
except ValueError:
if match := time_re.match(value):
kw = match.groupdict()
kw['microsecond'] = kw['microsecond'] and kw['microsecond'].ljust(6, '0')
kw = {k: int(v) for k, v in kw.items() if v is not None}
return datetime.time(**kw)
def parse_datetime(value): def parse_datetime(value):
@ -104,22 +112,23 @@ def parse_datetime(value):
Raise ValueError if the input is well formatted but not a valid datetime. Raise ValueError if the input is well formatted but not a valid datetime.
Return None if the input isn't well formatted. Return None if the input isn't well formatted.
""" """
match = datetime_re.match(value) try:
if match: return datetime.datetime.fromisoformat(value)
kw = match.groupdict() except ValueError:
kw['microsecond'] = kw['microsecond'] and kw['microsecond'].ljust(6, '0') if match := datetime_re.match(value):
tzinfo = kw.pop('tzinfo') kw = match.groupdict()
if tzinfo == 'Z': kw['microsecond'] = kw['microsecond'] and kw['microsecond'].ljust(6, '0')
tzinfo = utc tzinfo = kw.pop('tzinfo')
elif tzinfo is not None: if tzinfo == 'Z':
offset_mins = int(tzinfo[-2:]) if len(tzinfo) > 3 else 0 tzinfo = utc
offset = 60 * int(tzinfo[1:3]) + offset_mins elif tzinfo is not None:
if tzinfo[0] == '-': offset_mins = int(tzinfo[-2:]) if len(tzinfo) > 3 else 0
offset = -offset offset = 60 * int(tzinfo[1:3]) + offset_mins
tzinfo = get_fixed_timezone(offset) if tzinfo[0] == '-':
kw = {k: int(v) for k, v in kw.items() if v is not None} offset = -offset
kw['tzinfo'] = tzinfo tzinfo = get_fixed_timezone(offset)
return datetime.datetime(**kw) kw = {k: int(v) for k, v in kw.items() if v is not None}
return datetime.datetime(**kw, tzinfo=tzinfo)
def parse_duration(value): def parse_duration(value):