diff options
| author | Can Sarigol <ertugrulsarigol@gmail.com> | 2021-11-11 09:57:50 +0100 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-11-12 11:14:08 +0100 |
| commit | d54aa49a7d15e708b7da1620310167f39e859cba (patch) | |
| tree | cf38196b421ddcdddd067b9b7f036dfd682a3e99 /django | |
| parent | 45de30dc693fcd63d33816a85fb02abd5f7a10b4 (diff) | |
[4.0.x] Fixed #33279 -- Fixed handling time zones with "-" sign in names.
Thanks yakimka for the report.
Regression in fde9b7d35e4e185903cc14aa587ca870037941b1.
Backport of 661316b066923493ff91d6d2aa92e463f595a6b1 from main.
Diffstat (limited to 'django')
| -rw-r--r-- | django/db/backends/mysql/operations.py | 8 | ||||
| -rw-r--r-- | django/db/backends/oracle/operations.py | 11 | ||||
| -rw-r--r-- | django/db/backends/postgresql/operations.py | 9 | ||||
| -rw-r--r-- | django/db/backends/sqlite3/base.py | 13 | ||||
| -rw-r--r-- | django/db/backends/utils.py | 13 |
5 files changed, 31 insertions, 23 deletions
diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py index 89730cee29..3e1faad41b 100644 --- a/django/db/backends/mysql/operations.py +++ b/django/db/backends/mysql/operations.py @@ -2,6 +2,7 @@ import uuid from django.conf import settings from django.db.backends.base.operations import BaseDatabaseOperations +from django.db.backends.utils import split_tzname_delta from django.utils import timezone from django.utils.encoding import force_str @@ -76,11 +77,8 @@ class DatabaseOperations(BaseDatabaseOperations): return "DATE(%s)" % (field_name) def _prepare_tzname_delta(self, tzname): - if '+' in tzname: - return tzname[tzname.find('+'):] - elif '-' in tzname: - return tzname[tzname.find('-'):] - return tzname + tzname, sign, offset = split_tzname_delta(tzname) + return f'{sign}{offset}' if offset else tzname def _convert_field_to_tz(self, field_name, tzname): if tzname and settings.USE_TZ and self.connection.timezone_name != tzname: diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py index 4cfc7da070..f497390bea 100644 --- a/django/db/backends/oracle/operations.py +++ b/django/db/backends/oracle/operations.py @@ -5,7 +5,9 @@ from functools import lru_cache from django.conf import settings from django.db import DatabaseError, NotSupportedError from django.db.backends.base.operations import BaseDatabaseOperations -from django.db.backends.utils import strip_quotes, truncate_name +from django.db.backends.utils import ( + split_tzname_delta, strip_quotes, truncate_name, +) from django.db.models import AutoField, Exists, ExpressionWrapper, Lookup from django.db.models.expressions import RawSQL from django.db.models.sql.where import WhereNode @@ -108,11 +110,8 @@ END; _tzname_re = _lazy_re_compile(r'^[\w/:+-]+$') def _prepare_tzname_delta(self, tzname): - if '+' in tzname: - return tzname[tzname.find('+'):] - elif '-' in tzname: - return tzname[tzname.find('-'):] - return tzname + tzname, sign, offset = split_tzname_delta(tzname) + return f'{sign}{offset}' if offset else tzname def _convert_field_to_tz(self, field_name, tzname): if not (settings.USE_TZ and tzname): diff --git a/django/db/backends/postgresql/operations.py b/django/db/backends/postgresql/operations.py index 8d19872bea..399c1b24e7 100644 --- a/django/db/backends/postgresql/operations.py +++ b/django/db/backends/postgresql/operations.py @@ -2,6 +2,7 @@ from psycopg2.extras import Inet from django.conf import settings from django.db.backends.base.operations import BaseDatabaseOperations +from django.db.backends.utils import split_tzname_delta class DatabaseOperations(BaseDatabaseOperations): @@ -44,10 +45,10 @@ class DatabaseOperations(BaseDatabaseOperations): return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name) def _prepare_tzname_delta(self, tzname): - if '+' in tzname: - return tzname.replace('+', '-') - elif '-' in tzname: - return tzname.replace('-', '+') + tzname, sign, offset = split_tzname_delta(tzname) + if offset: + sign = '-' if sign == '+' else '+' + return f'{tzname}{sign}{offset}' return tzname def _convert_field_to_tz(self, field_name, tzname): diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index ddf5f40c8e..76ce12ac6d 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -433,14 +433,11 @@ def _sqlite_datetime_parse(dt, tzname=None, conn_tzname=None): if conn_tzname: dt = dt.replace(tzinfo=timezone_constructor(conn_tzname)) if tzname is not None and tzname != conn_tzname: - sign_index = tzname.find('+') + tzname.find('-') + 1 - if sign_index > -1: - sign = tzname[sign_index] - tzname, offset = tzname.split(sign) - if offset: - hours, minutes = offset.split(':') - offset_delta = datetime.timedelta(hours=int(hours), minutes=int(minutes)) - dt += offset_delta if sign == '+' else -offset_delta + tzname, sign, offset = backend_utils.split_tzname_delta(tzname) + if offset: + hours, minutes = offset.split(':') + offset_delta = datetime.timedelta(hours=int(hours), minutes=int(minutes)) + dt += offset_delta if sign == '+' else -offset_delta dt = timezone.localtime(dt, timezone_constructor(tzname)) return dt diff --git a/django/db/backends/utils.py b/django/db/backends/utils.py index c342cf79b5..ff7523742f 100644 --- a/django/db/backends/utils.py +++ b/django/db/backends/utils.py @@ -7,6 +7,7 @@ import time from contextlib import contextmanager from django.db import NotSupportedError +from django.utils.dateparse import parse_time logger = logging.getLogger('django.db.backends') @@ -130,6 +131,18 @@ class CursorDebugWrapper(CursorWrapper): ) +def split_tzname_delta(tzname): + """ + Split a time zone name into a 3-tuple of (name, sign, offset). + """ + for sign in ['+', '-']: + if sign in tzname: + name, offset = tzname.rsplit(sign, 1) + if offset and parse_time(offset): + return name, sign, offset + return tzname, None, None + + ############################################### # Converters from database (string) to Python # ############################################### |
