fix(core): align SQL end_date filter with whole-day semantics - #1165
Conversation
The SQL date filter compared datetime columns against the bare end_date, which SQLite coerces to midnight, so a same-day value carrying a time (deadline 2026-04-01 10:00 with end_date 2026-04-01) was excluded. The default TaskRepository.get_filtered() truncates to a date and includes it, so the two repository implementations returned different results for the same query. end_date is now turned into an exclusive next-day bound in _build_date_filter_conditions, making both paths whole-day inclusive, and the _matches_date_filter docstring now points at the SQL helper it mirrors. Adds a regression test with a time-bearing value on the boundary that asserts both implementations agree. Closes Kohei-Wada#1164
Kohei-Wada
left a comment
There was a problem hiding this comment.
Thanks for the fix — the diagnosis is right and the direction is correct. end_date is documented as inclusive, so making the SQL path whole-day inclusive (rather than making the default repository exclusive) is the right way to reconcile the two implementations.
I verified locally: the new test_date_filter_end_date_includes_same_day_time fails on main with assert 0 == 1 when only the source change is reverted, and the full taskdog-core suite passes with the fix (1175 passed).
Two minor nits in _build_date_filter_conditions:
-
end_boundis recomputed on every iteration of thefor field in date_fieldsloop. It doesn't depend onfield, so please hoist it above the loop. -
(field >= start_date) & (field < end_bound)— the surrounding code uses the SQLAlchemy function style (or_(...)), soand_(field >= start_date, field < end_bound)would be more consistent, and it may also let you drop the# type: ignore[operator].
Neither affects behaviour. Happy to merge once these are addressed.
|
Thanks! Nice catch on the two repository implementations disagreeing — the regression test asserting both paths agree is exactly the right shape. Merging. |
Description
TaskQueryBuilder._build_date_filter_conditionscompared the datetime columns against the bareend_date, which SQLite coerces to midnight, so a same-day value carrying a time was excluded. The defaultTaskRepository.get_filtered()truncates to a date and includes it, so both repository implementations returned different results for the same query.end_dateis now turned into an exclusive next-day bound, making both paths whole-day inclusive.Related Issue
Closes #1164
Type of Change
Changes Made
_build_date_filter_conditions:end_datebecomes an exclusiveend_date + 1 daybound (field >= start/field < end + 1d) instead ofbetween/<= end_date.TaskRepository._matches_date_filter: docstring now names the SQL helper it mirrors and states the whole-day-inclusiveend_datesemantics.between.Testing
Test Environment
Tests Performed
packages/taskdog-core/tests, 1175 passed)test_date_filter_end_date_includes_same_day_timefails onmain(assert 0 == 1— the task is dropped by the SQL path) and passes with the fix; verified by stashing only the source change.Code Quality Checklist
make typecheck)make format)Documentation
Package Affected
Breaking Changes
Behavioural change to the SQL filter only, bringing it in line with the documented inclusive
end_dateand with the default repository implementation.Checklist