#29754: Trunc() doesn't handle NonExistentTimeError/AmbiguousTimeError -------------------------------------+------------------------------------- Reporter: Alexander Holmbäck | Owner: nobody Type: Bug | Status: new Component: Database layer | Version: master (models, ORM) | Severity: Normal | Resolution: Keywords: pytz, Trunc() | Triage Stage: | Unreviewed Has patch: 0 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+------------------------------------- Description changed by Alexander Holmbäck:
Old description: > When `Trunc()` truncates to a nonexisting or ambiguous datetime, the > exception raised by pytz remains unhandled. The expected behavior would, > IMO, be to use naive datetimes for truncated dates, or adjust to closest > existing non-ambiguous datetime. > > This test for example: > {{{#!python > import datetime > import pytz > > from django.db.models.functions import Trunc > from django.test import TestCase > from django.utils import timezone > > from .models import Log > > class TestTruncateToNonExistingTime(TestCase): > > def test_truncate_to_dst_ends_stockholm(self): > tzinfo = pytz.timezone('Europe/Stockholm') > timestamp = datetime.datetime(2018, 10, 28, 2, tzinfo=tzinfo) > Log.objects.create(timestamp=timestamp) > logs = Log.objects.annotate(day=Trunc('timestamp', 'hour')).all() > > timezone.activate(tzinfo) > self.assertEqual(logs[0].day.day, 28) > }}} > > Results in the following error: > {{{ > ====================================================================== > ERROR: test_truncate_to_dst_ends_stockholm > (trunc.tests.TestTruncateToNonExistingTime) > ---------------------------------------------------------------------- > Traceback (most recent call last): > File "/home/alex/tickets/trunc/tests.py", line 47, in > test_truncate_to_dst_ends_stockholm > self.assertEqual(logs[0].day.day, 28) > File "/home/alex/django/django/db/models/query.py", line 303, in > __getitem__ > qs._fetch_all() > File "/home/alex/django/django/db/models/query.py", line 1190, in > _fetch_all > self._result_cache = list(self._iterable_class(self)) > File "/home/alex/django/django/db/models/query.py", line 64, in > __iter__ > for row in compiler.results_iter(results): > File "/home/alex/django/django/db/models/sql/compiler.py", line 1013, > in apply_converters > value = converter(value, expression, connection) > File "/home/alex/django/django/db/models/functions/datetime.py", line > 225, in convert_value > value = timezone.make_aware(value, self.tzinfo) > File "/home/alex/django/django/utils/timezone.py", line 270, in > make_aware > return timezone.localize(value, is_dst=is_dst) > File "/home/alex/.virtualenvs/djangodev/lib/python3.6/site- > packages/pytz/tzinfo.py", line 363, in localize > raise AmbiguousTimeError(dt) > pytz.exceptions.AmbiguousTimeError: 2018-10-28 02:00:00 > }}} New description: When `Trunc()` truncates to a nonexisting or ambiguous datetime, the exception raised by pytz remains unhandled. The expected behavior would, IMO, be to not check the validity of truncated dates. This test for example: {{{#!python import datetime import pytz from django.db.models.functions import Trunc from django.test import TestCase from django.utils import timezone from .models import Log class TestTruncateToInvalidTime(TestCase): def test_truncate_to_dst_ends_stockholm(self): tzinfo = pytz.timezone('Europe/Stockholm') timestamp = datetime.datetime(2018, 10, 28, 2, tzinfo=tzinfo) Log.objects.create(timestamp=timestamp) logs = Log.objects.annotate(day=Trunc('timestamp', 'hour')).all() timezone.activate(tzinfo) self.assertEqual(logs[0].day.day, 28) }}} Results in the following error: {{{ ====================================================================== ERROR: test_truncate_to_dst_ends_stockholm (trunc.tests.TestTruncateInvalidTime) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/alex/tickets/trunc/tests.py", line 47, in test_truncate_to_dst_ends_stockholm self.assertEqual(logs[0].day.day, 28) File "/home/alex/django/django/db/models/query.py", line 303, in __getitem__ qs._fetch_all() File "/home/alex/django/django/db/models/query.py", line 1190, in _fetch_all self._result_cache = list(self._iterable_class(self)) File "/home/alex/django/django/db/models/query.py", line 64, in __iter__ for row in compiler.results_iter(results): File "/home/alex/django/django/db/models/sql/compiler.py", line 1013, in apply_converters value = converter(value, expression, connection) File "/home/alex/django/django/db/models/functions/datetime.py", line 225, in convert_value value = timezone.make_aware(value, self.tzinfo) File "/home/alex/django/django/utils/timezone.py", line 270, in make_aware return timezone.localize(value, is_dst=is_dst) File "/home/alex/.virtualenvs/djangodev/lib/python3.6/site- packages/pytz/tzinfo.py", line 363, in localize raise AmbiguousTimeError(dt) pytz.exceptions.AmbiguousTimeError: 2018-10-28 02:00:00 }}} -- -- Ticket URL: <https://code.djangoproject.com/ticket/29754#comment:1> 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 django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/066.8c7b0299799a0351cc37cfa6dc94d434%40djangoproject.com. For more options, visit https://groups.google.com/d/optout.