瀏覽代碼

Fixed #32722 -- Fixed comparing to TruncTime() on Oracle.

Mariusz Felisiak 3 年之前
父節點
當前提交
b1a4b1f0bd

+ 0 - 4
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).

+ 9 - 3
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)

+ 15 - 6
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,
         )