fix(timeline): normalize naive datetimes from DB to offset-aware - #29
fix(timeline): normalize naive datetimes from DB to offset-aware#29rogerdigital wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request ensures that datetimes processed in the timeline aggregator and store are timezone-aware by normalizing naive datetimes using the .astimezone() method. These changes are applied to _capture_stem_in_window, get_latest_end, and _row_to_block, and are accompanied by new unit tests to verify correct handling of naive versus aware datetimes. Feedback indicates that the timestamp derived from the filename stem in the aggregator should also be normalized to prevent potential TypeError exceptions during comparison if it remains naive while the window bounds are aware.
| if start.tzinfo is None: | ||
| start = start.astimezone() | ||
| if end.tzinfo is None: | ||
| end = end.astimezone() |
There was a problem hiding this comment.
The comparison start <= ts < end on line 51 will still raise a TypeError if ts is naive and start/end are aware (or vice versa). While _stem_to_dt usually returns aware datetimes, it can return a naive one if the filename stem is exactly 20 characters and lacks a valid 'p' or 'm' offset prefix (e.g., 2026-04-21T17-07-32_). To be truly 'belt-and-suspenders' as intended by this PR, ts should also be normalized to an offset-aware datetime before the comparison.
| if start.tzinfo is None: | |
| start = start.astimezone() | |
| if end.tzinfo is None: | |
| end = end.astimezone() | |
| if ts.tzinfo is None: | |
| ts = ts.astimezone() | |
| if start.tzinfo is None: | |
| start = start.astimezone() | |
| if end.tzinfo is None: | |
| end = end.astimezone() |
There was a problem hiding this comment.
Fixed in 4c74c74 — added ts normalization before comparison.
get_latest_end() and _row_to_block() could return naive datetimes when stored ISO strings lacked a TZ offset, causing TypeError on comparison with aware datetimes. Normalize at all comparison boundaries: DB read paths, _row_to_block, and _capture_stem_in_window. Closes Einsia#24
4c74c74 to
67d212b
Compare
|
@Xiao-ao-jiang-hu The |
Summary
get_latest_end()and_row_to_block()could return naive datetimes when stored ISO strings lacked a TZ offset, causingTypeErroron comparison with aware datetimes from_stem_to_dt()and_now()— this silently breaks the entire timeline pipeline after the first block is writtenastimezone()normalization in all DB read paths and in_capture_stem_in_window()as a belt-and-suspenders guardTests
test_get_latest_end_naive_string_returns_aware— naive ISO string → aware datetimetest_get_latest_end_aware_string_stays_aware— aware stays awaretest_get_latest_end_no_rows— empty table → Nonetest_row_to_block_naive_datetime_becomes_aware— query_recent returns aware blockstest_capture_stem_in_window_naive_start_end— naive start/end don't crash, correct window membershipAll 19 tests pass, ruff clean.
Closes #24