#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.