#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:  1
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Comment (by Wes P.):

 My PR basically adds a warning in the documentation when using `Trunc`
 functions as a filter because it can have unexpected behavior. I also
 added some tests that verify that basic issue exists (the unexpected
 behavior) and my suggested work-around are valid. It would be nice to have
 someone look over my test but more importantly that the warning makes
 sense (I'll attach a screenshot from my dev environment):
 > Warning
 > Trunc functions, at the database level, return a timezone naive value
 which is converted to a timezone aware value by the ORM. When you use a
 Trunc function in a filter you will need to remember that it is a timezone
 naive value. This can lead to unexpected results if you are using
 timezones other than UTC. Django will store date/time values in the
 database in the UTC timezone. The following example demonstrates what
 happens when using the timezone “Europe/Berlin” and how to adjust for
 this:
 {{{#!python
 >>> from django.utils import timezone
 >>> from datetime import datetime
 >>> from django.db.models.functions import TruncSecond
 >>> import zoneinfo
 >>> start = datetime(2015, 6, 15, 14, 30, 50, 321)
 >>> start = timezone.make_aware(start)
 >>> exp = Experiment.objects.create(start_datetime=start)
 >>> find_this_exp = Experiment.objects.annotate(
 ...     trunc_start=TruncSecond("start_datetime")
 ... ).filter(trunc_start__lte=start)
 >>> find_this_exp.count()
 0  # We expect to find one result but 0 are found
 >>> start_adjusted = timezone.localtime(start).replace(
 ...     tzinfo=zoneinfo.ZoneInfo(key="UTC")
 ... )
 >>> find_this_exp_adjusted = Experiment.objects.annotate(
 ...     trunc_start=TruncSecond("start_datetime")
 ... ).filter(trunc_start__lte=start_adjusted)
 >>> find_this_exp.count()
 1
 }}}
-- 
Ticket URL: <https://code.djangoproject.com/ticket/34699#comment:21>
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/010701961cd6f78d-f310d4f6-9b44-4cdd-839d-619aae2cec95-000000%40eu-central-1.amazonses.com.

Reply via email to