diff --git a/django/db/models/functions/datetime.py b/django/db/models/functions/datetime.py index 6828980733..5075bd3d83 100644 --- a/django/db/models/functions/datetime.py +++ b/django/db/models/functions/datetime.py @@ -46,6 +46,8 @@ class Extract(TimezoneMixin, Transform): if isinstance(lhs_output_field, DateTimeField): tzname = self.get_tzname() sql = connection.ops.datetime_extract_sql(self.lookup_name, sql, tzname) + elif self.tzinfo is not None: + raise ValueError('tzinfo can only be used with DateTimeField.') elif isinstance(lhs_output_field, DateField): sql = connection.ops.date_extract_sql(self.lookup_name, sql) elif isinstance(lhs_output_field, TimeField): diff --git a/tests/db_functions/datetime/test_extract_trunc.py b/tests/db_functions/datetime/test_extract_trunc.py index f898ba5253..a842eb9418 100644 --- a/tests/db_functions/datetime/test_extract_trunc.py +++ b/tests/db_functions/datetime/test_extract_trunc.py @@ -1111,6 +1111,18 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests): self.assertEqual(model.day_melb, 16) self.assertEqual(model.day_utc, 15) + def test_extract_invalid_field_with_timezone(self): + melb = pytz.timezone('Australia/Melbourne') + msg = 'tzinfo can only be used with DateTimeField.' + with self.assertRaisesMessage(ValueError, msg): + DTModel.objects.annotate( + day_melb=Extract('start_date', 'day', tzinfo=melb), + ).get() + with self.assertRaisesMessage(ValueError, msg): + DTModel.objects.annotate( + hour_melb=Extract('start_time', 'hour', tzinfo=melb), + ).get() + def test_trunc_timezone_applied_before_truncation(self): start_datetime = datetime(2016, 1, 1, 1, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)