Commit d9521f66 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Removed global timezone-aware datetime adapters.

Refs #23820.

Fixed #19738.

Refs #17755. In order not to introduce a regression for raw queries,
parameters are passed through the connection.ops.value_to_db_* methods,
depending on their type.
parent fe6b5e62
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -433,6 +433,25 @@ class BaseDatabaseOperations(object):
        """
        return value

    def value_to_db_unknown(self, value):
        """
        Transforms a value to something compatible with the backend driver.

        This method only depends on the type of the value. It's designed for
        cases where the target type isn't known, such as .raw() SQL queries.
        As a consequence it may not work perfectly in all circumstances.
        """
        if isinstance(value, datetime.datetime):   # must be before date
            return self.value_to_db_datetime(value)
        elif isinstance(value, datetime.date):
            return self.value_to_db_date(value)
        elif isinstance(value, datetime.time):
            return self.value_to_db_time(value)
        elif isinstance(value, decimal.Decimal):
            return self.value_to_db_decimal(value)
        else:
            return value

    def value_to_db_date(self, value):
        """
        Transforms a date value to an object compatible with what is expected
@@ -486,6 +505,8 @@ class BaseDatabaseOperations(object):
        """
        first = datetime.date(value, 1, 1)
        second = datetime.date(value, 12, 31)
        first = self.value_to_db_date(first)
        second = self.value_to_db_date(second)
        return [first, second]

    def year_lookup_bounds_for_datetime_field(self, value):
@@ -502,6 +523,8 @@ class BaseDatabaseOperations(object):
            tz = timezone.get_current_timezone()
            first = timezone.make_aware(first, tz)
            second = timezone.make_aware(second, tz)
        first = self.value_to_db_datetime(first)
        second = self.value_to_db_datetime(second)
        return [first, second]

    def get_db_converters(self, expression):
+10 −10
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ from django.db import utils
from django.db.backends import utils as backend_utils
from django.db.backends.base.base import BaseDatabaseWrapper
from django.utils import six, timezone
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.encoding import force_str
from django.utils.functional import cached_property
from django.utils.safestring import SafeBytes, SafeText
@@ -52,15 +53,14 @@ DatabaseError = Database.DatabaseError
IntegrityError = Database.IntegrityError


def adapt_datetime_with_timezone_support(value, conv):
    # Equivalent to DateTimeField.get_db_prep_value. Used only by raw SQL.
    if settings.USE_TZ:
        if timezone.is_naive(value):
            warnings.warn("MySQL received a naive datetime (%s)"
                          " while time zone support is active." % value,
                          RuntimeWarning)
            default_timezone = timezone.get_default_timezone()
            value = timezone.make_aware(value, default_timezone)
def adapt_datetime_warn_on_aware_datetime(value, conv):
    # Remove this function and rely on the default adapter in Django 2.1.
    if settings.USE_TZ and timezone.is_aware(value):
        warnings.warn(
            "The MySQL database adapter received an aware datetime (%s), "
            "probably from cursor.execute(). Update your code to pass a "
            "naive datetime in the database connection's time zone (UTC by "
            "default).", RemovedInDjango21Warning)
        value = value.astimezone(timezone.utc).replace(tzinfo=None)
    return Thing2Literal(value.strftime("%Y-%m-%d %H:%M:%S.%f"), conv)

@@ -74,7 +74,7 @@ django_conversions.update({
    FIELD_TYPE.TIME: backend_utils.typecast_time,
    FIELD_TYPE.DECIMAL: backend_utils.typecast_decimal,
    FIELD_TYPE.NEWDECIMAL: backend_utils.typecast_decimal,
    datetime.datetime: adapt_datetime_with_timezone_support,
    datetime.datetime: adapt_datetime_warn_on_aware_datetime,
})

# This should match the numerical portion of the version numbers (we can treat
+9 −7
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ from django.db import utils
from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.backends.base.validation import BaseDatabaseValidation
from django.utils import six, timezone
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.duration import duration_string
from django.utils.encoding import force_bytes, force_text
from django.utils.functional import cached_property
@@ -336,13 +337,14 @@ class OracleParam(object):
        # without being converted by DateTimeField.get_db_prep_value.
        if settings.USE_TZ and (isinstance(param, datetime.datetime) and
                                not isinstance(param, Oracle_datetime)):
            if timezone.is_naive(param):
                warnings.warn("Oracle received a naive datetime (%s)"
                              " while time zone support is active." % param,
                              RuntimeWarning)
                default_timezone = timezone.get_default_timezone()
                param = timezone.make_aware(param, default_timezone)
            param = Oracle_datetime.from_datetime(param.astimezone(timezone.utc))
            if timezone.is_aware(param):
                warnings.warn(
                    "The Oracle database adapter received an aware datetime (%s), "
                    "probably from cursor.execute(). Update your code to pass a "
                    "naive datetime in the database connection's time zone (UTC by "
                    "default).", RemovedInDjango21Warning)
                param = param.astimezone(timezone.utc).replace(tzinfo=None)
            param = Oracle_datetime.from_datetime(param)

        if isinstance(param, datetime.timedelta):
            param = duration_string(param)
+0 −13
Original line number Diff line number Diff line
@@ -419,19 +419,6 @@ WHEN (new.%(col_name)s IS NULL)
        return Oracle_datetime(1900, 1, 1, value.hour, value.minute,
                               value.second, value.microsecond)

    def year_lookup_bounds_for_date_field(self, value):
        # Create bounds as real date values
        first = datetime.date(value, 1, 1)
        last = datetime.date(value, 12, 31)
        return [first, last]

    def year_lookup_bounds_for_datetime_field(self, value):
        # cx_Oracle doesn't support tz-aware datetimes
        bounds = super(DatabaseOperations, self).year_lookup_bounds_for_datetime_field(value)
        if settings.USE_TZ:
            bounds = [b.astimezone(timezone.utc) for b in bounds]
        return [Oracle_datetime.from_datetime(b) for b in bounds]

    def combine_expression(self, connector, sub_expressions):
        "Oracle requires special cases for %% and & operators in query expressions"
        if connector == '%%':
+10 −10
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ from django.utils import six, timezone
from django.utils.dateparse import (
    parse_date, parse_datetime, parse_duration, parse_time,
)
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.encoding import force_text
from django.utils.safestring import SafeBytes

@@ -49,15 +50,14 @@ DatabaseError = Database.DatabaseError
IntegrityError = Database.IntegrityError


def adapt_datetime_with_timezone_support(value):
    # Equivalent to DateTimeField.get_db_prep_value. Used only by raw SQL.
    if settings.USE_TZ:
        if timezone.is_naive(value):
            warnings.warn("SQLite received a naive datetime (%s)"
                          " while time zone support is active." % value,
                          RuntimeWarning)
            default_timezone = timezone.get_default_timezone()
            value = timezone.make_aware(value, default_timezone)
def adapt_datetime_warn_on_aware_datetime(value):
    # Remove this function and rely on the default adapter in Django 2.1.
    if settings.USE_TZ and timezone.is_aware(value):
        warnings.warn(
            "The SQLite database adapter received an aware datetime (%s), "
            "probably from cursor.execute(). Update your code to pass a "
            "naive datetime in the database connection's time zone (UTC by "
            "default).", RemovedInDjango21Warning)
        value = value.astimezone(timezone.utc).replace(tzinfo=None)
    return value.isoformat(str(" "))

@@ -77,7 +77,7 @@ Database.register_converter(str("timestamp"), decoder(parse_datetime))
Database.register_converter(str("TIMESTAMP"), decoder(parse_datetime))
Database.register_converter(str("decimal"), decoder(backend_utils.typecast_decimal))

Database.register_adapter(datetime.datetime, adapt_datetime_with_timezone_support)
Database.register_adapter(datetime.datetime, adapt_datetime_warn_on_aware_datetime)
Database.register_adapter(decimal.Decimal, backend_utils.rev_typecast_decimal)
if six.PY2:
    Database.register_adapter(str, lambda s: s.decode('utf-8'))
Loading