Skip to content

Commit

Permalink
Fix timezone passing to datetime, since Django 4.2 uses zoneinfo
Browse files Browse the repository at this point in the history
This ruff fix previously didn't work on Django 3.2 as that uses pytz.
Passing such timezone to datetime causes +00:18 min shifts instead of
the expected +01:00 change.

This is caused by the way pytz handles the zoneinfo from history and
needs pytz.timezone.localize() to create the proper timezone information.
See: https://groups.google.com/g/django-users/c/rXalwEztfr0/m/QAd5bIJubwAJ
  • Loading branch information
vdboor committed Jul 18, 2024
1 parent 5cfb5e3 commit d883b2a
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 16 deletions.
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ select = [
"C90", # mccabe
"BLE", # flake8-blind-except
"C4", # flake8-comprehensions
# "DTZ", # flake8-datetimez
"DTZ", # flake8-datetimez
"T10", # flake8-debugger
"DJ", # flake8-django
"ISC", # flake8-implicit-str-concat
Expand Down Expand Up @@ -85,6 +85,9 @@ allow-dict-calls-with-keyword-arguments = true
[tool.ruff.lint.flake8-gettext]
extend-function-names = ["gettext_lazy", "ngettext_lazy", "pgettext", "pgettext_lazy", "npgettext", "npgettext_lazy"]

[tool.ruff.lint.flake8-tidy-imports.banned-api]
"django.utils.timezone.make_aware".msg = "There is no need for make_aware(), pass tzinfo directly."

[tool.ruff.lint.isort]
known-first-party = ["dso_api", "rest_framework_dso"]
known-third-party = ["gisserver", "schematools"]
Expand Down
6 changes: 4 additions & 2 deletions src/dso_api/dynamic_api/temporal.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from django.db import models
from django.db.models import Q
from django.utils.timezone import make_aware, now
from django.utils.timezone import get_current_timezone, now
from more_itertools import first
from rest_framework.exceptions import ValidationError
from rest_framework.request import Request
Expand Down Expand Up @@ -119,7 +119,9 @@ def _parse_date(dimension: str, value: str) -> Literal["*"] | date | datetime:

try:
if "T" in value or " " in value:
return make_aware(datetime.fromisoformat(value))
# Add timezone if needed.
val = datetime.fromisoformat(value)
return val.replace(tzinfo=get_current_timezone()) if val.tzinfo is None else val
else:
return date.fromisoformat(value)
except ValueError:
Expand Down
3 changes: 2 additions & 1 deletion src/rest_framework_dso/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import orjson
from django.conf import settings
from django.urls import reverse
from django.utils.timezone import get_current_timezone
from rest_framework import renderers
from rest_framework.relations import HyperlinkedRelatedField
from rest_framework.serializers import ListSerializer, Serializer, SerializerMethodField
Expand Down Expand Up @@ -91,7 +92,7 @@ def finalize_response(self, response, renderer_context: dict):
def get_http_headers(self, renderer_context: dict):
"""Return the http headers for the response."""
if self.content_disposition:
now = datetime.now().isoformat()
now = datetime.now(tz=get_current_timezone()).isoformat()
dataset_id = renderer_context.get("dataset_id", "dataset")
table_id = renderer_context.get("table_id", "table")
return {
Expand Down
18 changes: 12 additions & 6 deletions src/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from django.core.handlers.wsgi import WSGIRequest
from django.db import connection
from django.utils.functional import SimpleLazyObject
from django.utils.timezone import make_aware
from django.utils.timezone import get_current_timezone
from jwcrypto.jwt import JWT
from psycopg2.sql import SQL, Identifier
from rest_framework.request import Request
Expand All @@ -26,8 +26,8 @@
from tests.utils import api_request_with_scopes, to_drf_request

HERE = Path(__file__).parent
DATE_2021_FEB = make_aware(datetime(2021, 2, 28, 10, 0))
DATE_2021_JUNE = make_aware(datetime(2021, 6, 11, 10, 0))
DATE_2021_FEB = datetime(2021, 2, 28, 10, 0, tzinfo=get_current_timezone())
DATE_2021_JUNE = datetime(2021, 6, 11, 10, 0, tzinfo=get_current_timezone())


@pytest.fixture()
Expand Down Expand Up @@ -367,7 +367,7 @@ def afval_container(afval_container_model, afval_cluster):
eigenaar_naam="Dataservices",
# set to fixed dates to the CSV export can also check for desired formatting
datum_creatie=date(2021, 1, 3),
datum_leegmaken=make_aware(datetime(2021, 1, 3, 12, 13, 14)),
datum_leegmaken=datetime(2021, 1, 3, 12, 13, 14, tzinfo=get_current_timezone()),
cluster=afval_cluster,
geometry=Point(10, 10), # no SRID on purpose, should use django model field.
)
Expand Down Expand Up @@ -571,10 +571,16 @@ def movies_model(movies_dataset, dynamic_models):
def movies_data(movies_model, movies_category):
return [
movies_model.objects.create(
id=3, name="foo123", category=movies_category, date_added=datetime(2020, 1, 1, 0, 45)
id=3,
name="foo123",
category=movies_category,
date_added=datetime(2020, 1, 1, 0, 45, tzinfo=get_current_timezone()),
),
movies_model.objects.create(
id=4, name="test", category=movies_category, date_added=datetime(2020, 2, 2, 13, 15)
id=4,
name="test",
category=movies_category,
date_added=datetime(2020, 2, 2, 13, 15, tzinfo=get_current_timezone()),
),
]

Expand Down
8 changes: 4 additions & 4 deletions src/tests/test_dynamic_api/test_temporal_actions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import date, datetime
from datetime import date, datetime, timezone
from urllib.parse import parse_qs, urlparse

import pytest
Expand All @@ -18,7 +18,7 @@ def stadsdelen(gebieden_models):
id="03630000000016.1",
identificatie="03630000000016",
volgnummer=1,
registratiedatum=datetime(2006, 6, 12, 5, 40, 12),
registratiedatum=datetime(2006, 6, 12, 5, 40, 12, tzinfo=timezone.utc),
begin_geldigheid=date(2006, 6, 1),
eind_geldigheid=date(2015, 1, 1),
naam="Zuidoost",
Expand All @@ -28,7 +28,7 @@ def stadsdelen(gebieden_models):
id="03630000000016.2",
identificatie="03630000000016",
volgnummer=2,
registratiedatum=datetime(2015, 1, 1, 5, 40, 12),
registratiedatum=datetime(2015, 1, 1, 5, 40, 12, tzinfo=timezone.utc),
begin_geldigheid=date(2015, 1, 1),
eind_geldigheid=None,
naam="Zuidoost",
Expand All @@ -46,7 +46,7 @@ def gebied(gebieden_models, stadsdelen, buurt):
id="03630950000019.1",
identificatie="03630950000019",
volgnummer=1,
registratiedatum=datetime(2015, 1, 1, 5, 40, 12),
registratiedatum=datetime(2015, 1, 1, 5, 40, 12, tzinfo=timezone.utc),
begin_geldigheid=date(2014, 2, 20),
naam="Bijlmer-Centrum",
)
Expand Down
4 changes: 2 additions & 2 deletions src/tests/test_dynamic_api/test_views_mvt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import mapbox_vector_tile
import pytest
from django.contrib.gis.geos import Point
from django.utils.timezone import make_aware
from django.utils.timezone import get_current_timezone

CONTENT_TYPE = "application/vnd.mapbox-vector-tile"

Expand Down Expand Up @@ -119,7 +119,7 @@ def test_mvt_content(api_client, afval_container_model, afval_cluster, filled_ro
eigenaar_naam="Dataservices",
# set to fixed dates to the CSV export can also check for desired formatting
datum_creatie=date(2021, 1, 3),
datum_leegmaken=make_aware(datetime(2021, 1, 3, 12, 13, 14)),
datum_leegmaken=datetime(2021, 1, 3, 12, 13, 14, tzinfo=get_current_timezone()),
cluster=afval_cluster,
geometry=Point(123207.6558130105, 486624.6399002579),
)
Expand Down

0 comments on commit d883b2a

Please sign in to comment.