From 2bfc91ec7567c0c7fbc7c8dd94725422b6f7ea32 Mon Sep 17 00:00:00 2001 From: nightcityblade Date: Fri, 3 Jul 2026 11:26:42 +0800 Subject: [PATCH] Fix datetime last_modified rounding --- CHANGES/5303.bugfix.rst | 3 +++ aiohttp/web_response.py | 2 +- tests/test_web_response.py | 11 +++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 CHANGES/5303.bugfix.rst diff --git a/CHANGES/5303.bugfix.rst b/CHANGES/5303.bugfix.rst new file mode 100644 index 00000000000..dd60f3a4dea --- /dev/null +++ b/CHANGES/5303.bugfix.rst @@ -0,0 +1,3 @@ +Aligned ``StreamResponse.last_modified`` datetime handling with the timestamp +path so sub-second values round up consistently. +-- by :user:`nightcityblade`. diff --git a/aiohttp/web_response.py b/aiohttp/web_response.py index cea31be1733..51a79d7b78c 100644 --- a/aiohttp/web_response.py +++ b/aiohttp/web_response.py @@ -372,7 +372,7 @@ def last_modified( ) elif isinstance(value, datetime.datetime): self._headers[hdrs.LAST_MODIFIED] = time.strftime( - "%a, %d %b %Y %H:%M:%S GMT", value.utctimetuple() + "%a, %d %b %Y %H:%M:%S GMT", time.gmtime(math.ceil(value.timestamp())) ) elif isinstance(value, str): self._headers[hdrs.LAST_MODIFIED] = value diff --git a/tests/test_web_response.py b/tests/test_web_response.py index c5ca849b6b9..cb02535ead3 100644 --- a/tests/test_web_response.py +++ b/tests/test_web_response.py @@ -339,6 +339,17 @@ def test_last_modified_datetime() -> None: assert resp.last_modified == dt +def test_last_modified_datetime_rounds_like_timestamp() -> None: + resp = StreamResponse() + + dt = datetime.datetime(2001, 2, 3, 4, 5, 6, 1000, datetime.timezone.utc) + resp.last_modified = dt + + assert resp.last_modified == datetime.datetime( + 2001, 2, 3, 4, 5, 7, tzinfo=datetime.timezone.utc + ) + + def test_last_modified_reset() -> None: resp = StreamResponse()