From b1a4b1f0bdf05adbd3dc4dde14228e68da54c1a3 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Fri, 7 May 2021 08:46:22 +0200 Subject: [PATCH] Fixed #32722 -- Fixed comparing to TruncTime() on Oracle. --- django/db/backends/oracle/features.py | 4 ---- django/db/backends/oracle/operations.py | 12 ++++++++--- .../datetime/test_extract_trunc.py | 21 +++++++++++++------ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/django/db/backends/oracle/features.py b/django/db/backends/oracle/features.py index 604f2316bc..07f16eee71 100644 --- a/django/db/backends/oracle/features.py +++ b/django/db/backends/oracle/features.py @@ -87,10 +87,6 @@ class DatabaseFeatures(BaseDatabaseFeatures): 'Raises ORA-00600: internal error code.': { 'model_fields.test_jsonfield.TestQuerying.test_usage_in_subquery', }, - "Comparing to TruncTime() doesn't work on Oracle (#32722).": { - 'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_trunc_time_no_microseconds', - 'db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_time_no_microseconds', - }, } django_test_expected_failures = { # A bug in Django/cx_Oracle with respect to string handling (#23843). diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py index d48c8dd868..095a125ced 100644 --- a/django/db/backends/oracle/operations.py +++ b/django/db/backends/oracle/operations.py @@ -135,9 +135,15 @@ END; return 'TRUNC(%s)' % field_name def datetime_cast_time_sql(self, field_name, tzname): - # Since `TimeField` values are stored as TIMESTAMP where only the date - # part is ignored, convert the field to the specified timezone. - return self._convert_field_to_tz(field_name, tzname) + # Since `TimeField` values are stored as TIMESTAMP change to the + # default date and convert the field to the specified timezone. + convert_datetime_sql = ( + "TO_TIMESTAMP(CONCAT('1900-01-01 ', TO_CHAR(%s, 'HH24:MI:SS.FF')), " + "'YYYY-MM-DD HH24:MI:SS.FF')" + ) % self._convert_field_to_tz(field_name, tzname) + return "CASE WHEN %s IS NOT NULL THEN %s ELSE NULL END" % ( + field_name, convert_datetime_sql, + ) def datetime_extract_sql(self, lookup_type, field_name, tzname): field_name = self._convert_field_to_tz(field_name, tzname) diff --git a/tests/db_functions/datetime/test_extract_trunc.py b/tests/db_functions/datetime/test_extract_trunc.py index 75b8a4f0f9..fe80904330 100644 --- a/tests/db_functions/datetime/test_extract_trunc.py +++ b/tests/db_functions/datetime/test_extract_trunc.py @@ -923,19 +923,28 @@ class DateFunctionTests(TestCase): self.create_model(None, None) self.assertIsNone(DTModel.objects.annotate(truncated=TruncTime('start_datetime')).first().truncated) - def test_trunc_time_no_microseconds(self): - start_datetime = datetime(2015, 6, 15, 14, 30, 26) + def test_trunc_time_comparison(self): + start_datetime = datetime(2015, 6, 15, 14, 30, 26) # 0 microseconds. + end_datetime = datetime(2015, 6, 15, 14, 30, 26, 321) if settings.USE_TZ: start_datetime = timezone.make_aware(start_datetime, is_dst=False) - self.create_model(start_datetime, None) + end_datetime = timezone.make_aware(end_datetime, is_dst=False) + self.create_model(start_datetime, end_datetime) self.assertIs( - DTModel.objects.filter(start_datetime__time=start_datetime.time()).exists(), + DTModel.objects.filter( + start_datetime__time=start_datetime.time(), + end_datetime__time=end_datetime.time(), + ).exists(), True, ) self.assertIs( DTModel.objects.annotate( - extracted=TruncTime('start_datetime'), - ).filter(extracted=start_datetime.time()).exists(), + extracted_start=TruncTime('start_datetime'), + extracted_end=TruncTime('end_datetime'), + ).filter( + extracted_start=start_datetime.time(), + extracted_end=end_datetime.time(), + ).exists(), True, )