Fixed #31948 -- Added tzinfo parameter to TruncDate() and TruncTime().

This commit is contained in:
Joe Jackson 2020-08-29 14:40:54 -04:00 committed by Mariusz Felisiak
parent 76e0151ea0
commit 9d5d865fd6
5 changed files with 28 additions and 4 deletions

View File

@ -449,6 +449,7 @@ answer newbie questions, and generally made Django that much better:
Joao Oliveira <joaoxsouls@gmail.com> Joao Oliveira <joaoxsouls@gmail.com>
Joao Pedro Silva <j.pedro004@gmail.com> Joao Pedro Silva <j.pedro004@gmail.com>
Joe Heck <http://www.rhonabwy.com/wp/> Joe Heck <http://www.rhonabwy.com/wp/>
Joe Jackson <joe@joejackson.me>
Joel Bohman <mail@jbohman.com> Joel Bohman <mail@jbohman.com>
Joel Heenan <joelh-django@planetjoel.com> Joel Heenan <joelh-django@planetjoel.com>
Joel Watts <joel@joelwatts.com> Joel Watts <joel@joelwatts.com>

View File

@ -292,7 +292,7 @@ class TruncDate(TruncBase):
def as_sql(self, compiler, connection): def as_sql(self, compiler, connection):
# Cast to date rather than truncate to date. # Cast to date rather than truncate to date.
lhs, lhs_params = compiler.compile(self.lhs) lhs, lhs_params = compiler.compile(self.lhs)
tzname = timezone.get_current_timezone_name() if settings.USE_TZ else None tzname = self.get_tzname()
sql = connection.ops.datetime_cast_date_sql(lhs, tzname) sql = connection.ops.datetime_cast_date_sql(lhs, tzname)
return sql, lhs_params return sql, lhs_params
@ -305,7 +305,7 @@ class TruncTime(TruncBase):
def as_sql(self, compiler, connection): def as_sql(self, compiler, connection):
# Cast to time rather than truncate to time. # Cast to time rather than truncate to time.
lhs, lhs_params = compiler.compile(self.lhs) lhs, lhs_params = compiler.compile(self.lhs)
tzname = timezone.get_current_timezone_name() if settings.USE_TZ else None tzname = self.get_tzname()
sql = connection.ops.datetime_cast_time_sql(lhs, tzname) sql = connection.ops.datetime_cast_time_sql(lhs, tzname)
return sql, lhs_params return sql, lhs_params

View File

@ -623,20 +623,28 @@ that deal with date-parts can be used with ``DateField``::
``DateTimeField`` truncation ``DateTimeField`` truncation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. class:: TruncDate(expression, **extra) .. class:: TruncDate(expression, tzinfo=None, **extra)
.. attribute:: lookup_name = 'date' .. attribute:: lookup_name = 'date'
.. attribute:: output_field = DateField() .. attribute:: output_field = DateField()
.. versionchanged:: 3.2
The ``tzinfo`` parameter was added.
``TruncDate`` casts ``expression`` to a date rather than using the built-in SQL ``TruncDate`` casts ``expression`` to a date rather than using the built-in SQL
truncate function. It's also registered as a transform on ``DateTimeField`` as truncate function. It's also registered as a transform on ``DateTimeField`` as
``__date``. ``__date``.
.. class:: TruncTime(expression, **extra) .. class:: TruncTime(expression, tzinfo=None, **extra)
.. attribute:: lookup_name = 'time' .. attribute:: lookup_name = 'time'
.. attribute:: output_field = TimeField() .. attribute:: output_field = TimeField()
.. versionchanged:: 3.2
The ``tzinfo`` parameter was added.
``TruncTime`` casts ``expression`` to a time rather than using the built-in SQL ``TruncTime`` casts ``expression`` to a time rather than using the built-in SQL
truncate function. It's also registered as a transform on ``DateTimeField`` as truncate function. It's also registered as a transform on ``DateTimeField`` as
``__time``. ``__time``.

View File

@ -290,6 +290,11 @@ Models
distinct fields if there's only one field specified in distinct fields if there's only one field specified in
:meth:`.QuerySet.distinct`. :meth:`.QuerySet.distinct`.
* The new ``tzinfo`` parameter of the
:class:`~django.db.models.functions.TruncDate` and
:class:`~django.db.models.functions.TruncTime` database functions allows
truncating datetimes in a specific timezone.
Pagination Pagination
~~~~~~~~~~ ~~~~~~~~~~

View File

@ -1124,14 +1124,24 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
model = DTModel.objects.annotate( model = DTModel.objects.annotate(
melb_year=TruncYear('start_datetime', tzinfo=melb), melb_year=TruncYear('start_datetime', tzinfo=melb),
pacific_year=TruncYear('start_datetime', tzinfo=pacific), pacific_year=TruncYear('start_datetime', tzinfo=pacific),
melb_date=TruncDate('start_datetime', tzinfo=melb),
pacific_date=TruncDate('start_datetime', tzinfo=pacific),
melb_time=TruncTime('start_datetime', tzinfo=melb),
pacific_time=TruncTime('start_datetime', tzinfo=pacific),
).order_by('start_datetime').get() ).order_by('start_datetime').get()
melb_start_datetime = start_datetime.astimezone(melb)
pacific_start_datetime = start_datetime.astimezone(pacific)
self.assertEqual(model.start_datetime, start_datetime) self.assertEqual(model.start_datetime, start_datetime)
self.assertEqual(model.melb_year, truncate_to(start_datetime, 'year', melb)) self.assertEqual(model.melb_year, truncate_to(start_datetime, 'year', melb))
self.assertEqual(model.pacific_year, truncate_to(start_datetime, 'year', pacific)) self.assertEqual(model.pacific_year, truncate_to(start_datetime, 'year', pacific))
self.assertEqual(model.start_datetime.year, 2016) self.assertEqual(model.start_datetime.year, 2016)
self.assertEqual(model.melb_year.year, 2016) self.assertEqual(model.melb_year.year, 2016)
self.assertEqual(model.pacific_year.year, 2015) self.assertEqual(model.pacific_year.year, 2015)
self.assertEqual(model.melb_date, melb_start_datetime.date())
self.assertEqual(model.pacific_date, pacific_start_datetime.date())
self.assertEqual(model.melb_time, melb_start_datetime.time())
self.assertEqual(model.pacific_time, pacific_start_datetime.time())
def test_trunc_ambiguous_and_invalid_times(self): def test_trunc_ambiguous_and_invalid_times(self):
sao = pytz.timezone('America/Sao_Paulo') sao = pytz.timezone('America/Sao_Paulo')