#34699: Filtering on annotated TruncSecond expression gives unexpected result.
-------------------------------------+-------------------------------------
     Reporter:  Stefan               |                    Owner:  Wes P.
         Type:                       |                   Status:  assigned
  Cleanup/optimization               |
    Component:  Database layer       |                  Version:  dev
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:  Accepted
    Has patch:  1                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Comment (by Jacob Walls):

 After "discovering" these issues for myself in a
 [https://github.com/django/django/pull/20502 related PR], I agree that we
 primarily have a documentation issue (or issues) to address.

 > But then, at least to me, is quite surprising that TruncSecond, which is
 an operation fully occurring in the DB, would not "respect" that "UTC
 invariant" and have the TIME_ZONE setting affecting the results. Does my
 point make sense? Do you have historic information about why TruncSecond
 (and related functions) would not operate with/keep the tz defined in the
 datetime being processed?

 My guess is simply that it would be a useful convenience for `USE_TZ =
 False` projects, which was the ancient default. There's no reason to
 expect database data to be in UTC if `TIME_ZONE = 'America/Chicago'`
 (default) and `USE_TZ = False`,  so you would probably want this feature:

 > If you switch from `USE_TZ = False` to `USE_TZ = True`, you must convert
 your data from local time to UTC -- which isn't deterministic if your
 local time has DST.

 (It may have also been needed before 1.9 when there were
 [https://docs.djangoproject.com/en/6.0/releases/1.9/#removal-of-time-zone-
 aware-global-adapters-and-converters-for-datetimes global time zone
 adapters]?)
 ----
 > My PR basically adds a warning in the documentation when using Trunc
 functions as a filter because it can have unexpected behavior.

 That sounds good. It's really easy to compare local times against UTC
 times by doing `my_trunc=datetime.now()` (while `USE_TZ = True`) like in
 the original report.

 Notice that for `USE_TZ=False`, `Trunc`
 
[https://github.com/django/django/blob/2b192bff26cf956c168790fce6a637cbd814250b/tests/db_functions/datetime/test_extract_trunc.py#L105
 tests] routinely call `make_aware()` on the right-hand sides to correct
 for this, comparing local to local:

 {{{#!py
 @override_settings(USE_TZ=False)
 class DateFunctionTests(TestCase):
 ...
     def test_extract_year_lessthan_lookup(self):
         start_datetime = datetime.datetime(2015, 6, 15, 14, 10)
         end_datetime = datetime.datetime(2016, 6, 15, 14, 10)
         if settings.USE_TZ:
             start_datetime = timezone.make_aware(start_datetime)
             end_datetime = timezone.make_aware(end_datetime)

 }}}

 The
 
[https://github.com/django/django/blob/2b192bff26cf956c168790fce6a637cbd814250b/tests/db_functions/datetime/test_extract_trunc.py#L1685
 subsequent tests] test `UZE_TZ=True` with `TIME_ZONE="UTC"`, which is not
 the default (default is `America/Chicago`):
 {{{#!py
 @override_settings(USE_TZ=True, TIME_ZONE="UTC")
 class DateFunctionWithTimeZoneTests(DateFunctionTests):
     def test_extract_func_with_timezone(self):
         start_datetime = datetime.datetime(2015, 6, 15, 23, 30, 1, 321)
         end_datetime = datetime.datetime(2015, 6, 16, 13, 11, 27, 123)
         start_datetime = timezone.make_aware(start_datetime)
         end_datetime = timezone.make_aware(end_datetime)
 ...
         melb = zoneinfo.ZoneInfo("Australia/Melbourne")

         qs = DTModel.objects.annotate(
             day=Extract("start_datetime", "day"),
             day_melb=Extract("start_datetime", "day", tzinfo=melb),
 ...
 }}}
 ----
 My recommendation is that we close this ticket by:
 1. Updating the docs for `Extract()` and `Trunc()` with some nuance
 2. Fixing the Melbourne details from comment:19
 3. Add at least one test for `Extract` or `Trunc` with `USE_TZ = True` and
 `TIME_ZONE` != `UTC` (e.g. the default `America/Chicago`)

 I'll review the PR with that in mind (it looks already well-scoped to
 those points).
-- 
Ticket URL: <https://code.djangoproject.com/ticket/34699#comment:23>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/0107019bb41db37a-9905e6bd-f50e-4412-8758-1dcb57acb179-000000%40eu-central-1.amazonses.com.

Reply via email to