diff options
| author | Nick Pope <nick@nickpope.me.uk> | 2021-05-10 14:39:50 +0100 |
|---|---|---|
| committer | Carlton Gibson <carlton.gibson@noumenal.es> | 2021-05-12 14:42:17 +0200 |
| commit | 46346f8ea08020d503b25472a26b949a5ce980a6 (patch) | |
| tree | 2ea5991cc8dc896fd2858ad1df51ae34655053ff /django | |
| parent | 44accb066a51d15f27e38f203c73830eddea16df (diff) | |
Refs #32738 -- Added sanitize_strftime_format() to replace datetime_safe.
Diffstat (limited to 'django')
| -rw-r--r-- | django/forms/widgets.py | 4 | ||||
| -rw-r--r-- | django/utils/formats.py | 41 |
2 files changed, 40 insertions, 5 deletions
diff --git a/django/forms/widgets.py b/django/forms/widgets.py index 1e67857c31..0a24e924a5 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -10,7 +10,7 @@ from itertools import chain from django.forms.utils import to_current_timezone from django.templatetags.static import static -from django.utils import datetime_safe, formats +from django.utils import formats from django.utils.datastructures import OrderedSet from django.utils.dates import MONTHS from django.utils.formats import get_format @@ -1070,13 +1070,13 @@ class SelectDateWidget(Widget): return None if y is not None and m is not None and d is not None: input_format = get_format('DATE_INPUT_FORMATS')[0] + input_format = formats.sanitize_strftime_format(input_format) try: date_value = datetime.date(int(y), int(m), int(d)) except ValueError: # Return pseudo-ISO dates with zeros for any unselected values, # e.g. '2017-0-23'. return '%s-%s-%s' % (y or 0, m or 0, d or 0) - date_value = datetime_safe.new_date(date_value) return date_value.strftime(input_format) return data.get(name) diff --git a/django/utils/formats.py b/django/utils/formats.py index 028e11415a..3bad64150a 100644 --- a/django/utils/formats.py +++ b/django/utils/formats.py @@ -1,10 +1,12 @@ import datetime import decimal +import functools +import re import unicodedata from importlib import import_module from django.conf import settings -from django.utils import dateformat, datetime_safe, numberformat +from django.utils import dateformat, numberformat from django.utils.functional import lazy from django.utils.translation import ( check_for_language, get_language, to_locale, @@ -221,12 +223,12 @@ def localize_input(value, default=None): elif isinstance(value, (decimal.Decimal, float, int)): return number_format(value) elif isinstance(value, datetime.datetime): - value = datetime_safe.new_datetime(value) format = default or get_format('DATETIME_INPUT_FORMATS')[0] + format = sanitize_strftime_format(format) return value.strftime(format) elif isinstance(value, datetime.date): - value = datetime_safe.new_date(value) format = default or get_format('DATE_INPUT_FORMATS')[0] + format = sanitize_strftime_format(format) return value.strftime(format) elif isinstance(value, datetime.time): format = default or get_format('TIME_INPUT_FORMATS')[0] @@ -234,6 +236,39 @@ def localize_input(value, default=None): return value +@functools.lru_cache() +def sanitize_strftime_format(fmt): + """ + Ensure that certain specifiers are correctly padded with leading zeros. + + For years < 1000 specifiers %C, %F, %G, and %Y don't work as expected for + strftime provided by glibc on Linux as they don't pad the year or century + with leading zeros. Support for specifying the padding explicitly is + available, however, which can be used to fix this issue. + + FreeBSD, macOS, and Windows do not support explicitly specifying the + padding, but return four digit years (with leading zeros) as expected. + + This function checks whether the %Y produces a correctly padded string and, + if not, makes the following substitutions: + + - %C → %02C + - %F → %010F + - %G → %04G + - %Y → %04Y + + See https://bugs.python.org/issue13305 for more details. + """ + if datetime.date(1, 1, 1).strftime('%Y') == '0001': + return fmt + mapping = {'C': 2, 'F': 10, 'G': 4, 'Y': 4} + return re.sub( + r'((?:^|[^%])(?:%%)*)%([CFGY])', + lambda m: r'%s%%0%s%s' % (m[1], mapping[m[2]], m[2]), + fmt, + ) + + def sanitize_separators(value): """ Sanitize a value according to the current decimal and |
