From a4093cf3b6563f87e8198c3f0cc439f2b227a7ff Mon Sep 17 00:00:00 2001 From: Paco Cartones <253313177+pacocartones@users.noreply.github.com> Date: Tue, 20 Oct 2026 04:32:08 +0200 Subject: [PATCH] Normalize aware datetimes before formatting headers --- cachecontrol/heuristics.py | 2 +- tests/test_expires_heuristics.py | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/cachecontrol/heuristics.py b/cachecontrol/heuristics.py index d95e78a9..314775c0 100644 --- a/cachecontrol/heuristics.py +++ b/cachecontrol/heuristics.py @@ -21,7 +21,7 @@ def expire_after(delta: timedelta, date: datetime | None = None) -> datetime: def datetime_to_header(dt: datetime) -> str: - return formatdate(calendar.timegm(dt.timetuple())) + return formatdate(calendar.timegm(dt.utctimetuple())) class BaseHeuristic: diff --git a/tests/test_expires_heuristics.py b/tests/test_expires_heuristics.py index 2a5fd23b..afaf3743 100644 --- a/tests/test_expires_heuristics.py +++ b/tests/test_expires_heuristics.py @@ -4,7 +4,7 @@ import calendar import time -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone from email.utils import formatdate, parsedate from pprint import pprint from unittest.mock import Mock @@ -19,10 +19,35 @@ LastModified, OneDayCache, ) +from cachecontrol.heuristics import ( + datetime_to_header as heuristic_datetime_to_header, +) from .utils import DummyResponse +class TestDatetimeToHeader: + def test_positive_timezone_offset(self): + value = datetime( + 2026, 10, 20, 1, tzinfo=timezone(timedelta(hours=5, minutes=30)) + ) + assert heuristic_datetime_to_header(value) == "Mon, 19 Oct 2026 19:30:00 -0000" + + def test_negative_timezone_offset(self): + value = datetime( + 2026, 10, 20, 23, tzinfo=timezone(timedelta(hours=-3, minutes=-30)) + ) + assert heuristic_datetime_to_header(value) == "Wed, 21 Oct 2026 02:30:00 -0000" + + def test_utc(self): + value = datetime(2026, 10, 20, 12, tzinfo=timezone.utc) + assert heuristic_datetime_to_header(value) == "Tue, 20 Oct 2026 12:00:00 -0000" + + def test_naive_remains_utc(self): + value = datetime(2026, 10, 20, 12) + assert heuristic_datetime_to_header(value) == "Tue, 20 Oct 2026 12:00:00 -0000" + + class TestHeuristicWithoutWarning: def setup_method(self): class NoopHeuristic(BaseHeuristic):