Fix access log timestamps ignoring daylight savings time#12085
Fix access log timestamps ignoring daylight savings time#12085Dreamsorcerer merged 13 commits intoaio-libs:masterfrom
Conversation
nightcityblade
left a comment
There was a problem hiding this comment.
Thanks for the review!
On the UTC concern: datetime.now(utc).astimezone() does NOT produce UTC timestamps. The .astimezone() call (with no argument) converts to the system's local timezone, correctly reflecting DST. So the flow is: get current time in UTC → convert to local timezone (with DST awareness). The old code used time.timezone which is a module-level constant that never changes, even during DST transitions.
On the test: Added test_access_logger_dst_timezone in 88f273b that simulates an EST→EDT transition and verifies both the UTC offset and hour change correctly. Also added the changelog entry (CHANGES/11283.bugfix.rst).
Got it. But, it is creating 2 datetime objects in the process. Do you think my original suggestion could be a better option (assuming it works correctly)? A quick test suggests this version is ~25% slower (and given the frequency of logging, performance is probably fairly important here): There may be a mistake in my testing, so let me know if you think I'm wrong there. |
|
With my suggestion, the timezone could also be cached, resulting in something that is 4.5x faster: Obviously, if we cache it, we'd need to have some way to update/invalidate that cache at an appropriate time for when the server is running across a DST change. But, even if we invalidated it every minute, that'd be a substantial performance improvement for a server under load. |
|
Great benchmarking — you're right that the cached timezone approach is significantly faster. Let me implement that. I'll update the PR to use a cached Will push the update shortly. |
Use time.localtime().tm_gmtoff with a 60-second cache to correctly resolve the local timezone including DST transitions. The previous implementation used time.timezone which is a constant and does not reflect DST changes. Fixes aio-libs#11283
ef23383 to
e2438dd
Compare
|
Updated! The implementation now uses a cached Let me know if you'd like any adjustments. |
- Use time.time() instead of monotonic clock for cache expiry - Implement 30-minute thresholds for DST-aware cache invalidation - Calculate next 30-min boundary aligned to 0/30 minutes past hour - Reuse datetime.now() calculation between _get_local_timezone and _format_t - Return tuple from _get_local_timezone to avoid redundant datetime.now() calls Addresses all 5 inline comments from Dreamsorcerer on PR aio-libs#12085.
052e3ff to
c3224ed
Compare
|
Thank you for the detailed review @Dreamsorcerer! I've addressed all 5 of your inline comments: ✅ 1. Use time.time() instead of monotonic clock - Changed from ✅ 2. & 3. 30-minute threshold alignment - Implemented your suggested approach for calculating the next 30-minute boundary aligned to DST changes ✅ 4. Reuse datetime.now() calculation - Modified ✅ 5. Specific code implementation - Used your exact code suggestion for the 30-minute threshold calculation The implementation now properly aligns cache expiry to 30-minute boundaries (0 and 30 minutes past the hour) to handle DST transitions correctly, and eliminates the redundant All existing tests pass with these changes. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #12085 +/- ##
==========================================
+ Coverage 98.71% 98.78% +0.06%
==========================================
Files 128 128
Lines 44907 45109 +202
Branches 2383 2397 +14
==========================================
+ Hits 44332 44560 +228
+ Misses 408 390 -18
+ Partials 167 159 -8
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Backport to 3.13: 💔 cherry-picking failed — conflicts found❌ Failed to cleanly apply 004127a on top of patchback/backports/3.13/004127a837d91169f03a40b0904e544c711b481d/pr-12085 Backporting merged PR #12085 into master
🤖 @patchback |
Backport to 3.14: 💔 cherry-picking failed — conflicts found❌ Failed to cleanly apply 004127a on top of patchback/backports/3.14/004127a837d91169f03a40b0904e544c711b481d/pr-12085 Backporting merged PR #12085 into master
🤖 @patchback |
|
@nightcityblade If you could follow the instructions to create backports, that'd be really helpful. |
) --------- Co-authored-by: nightcityblade <[email protected]> Co-authored-by: Sam Bull <[email protected]>
) --------- Co-authored-by: nightcityblade <[email protected]> Co-authored-by: Sam Bull <[email protected]>
) --------- Co-authored-by: nightcityblade <[email protected]> Co-authored-by: Sam Bull <[email protected]>
…time (#12085) (#12127) Co-authored-by: nightcityblade <[email protected]> Co-authored-by: Sam Bull <[email protected]>
) Backport of aio-libs#12085 to 3.13 branch. Uses Optional[] syntax for Python 3.9 compatibility.
…time (#12085) (#12126) Co-authored-by: nightcityblade <[email protected]>
…time (aio-libs#12085) (aio-libs#12126) Co-authored-by: nightcityblade <[email protected]>
Description
Fixes #11283.
The
_format_tmethod inweb_log.pyusedtime.timezoneto construct the timezone offset, buttime.timezoneis a constant representing the standard time UTC offset and does not account for daylight savings time. This causes access log timestamps to show the wrong time and offset during DST periods.Changes
Replaced the manual timezone construction with
datetime.now(tz=datetime.timezone.utc).astimezone(), which correctly resolves to the system's local timezone including DST. Also removed the now-unusedimport time as time_mod.Before / After
Before (during MDT, UTC-6):
After: