Skip to content

fix(core): align SQL end_date filter with whole-day semantics - #1165

Merged
Kohei-Wada merged 1 commit into
Kohei-Wada:mainfrom
Sanjays2402:fix/date-filter-end-date-boundary
Jul 26, 2026
Merged

fix(core): align SQL end_date filter with whole-day semantics#1165
Kohei-Wada merged 1 commit into
Kohei-Wada:mainfrom
Sanjays2402:fix/date-filter-end-date-boundary

Conversation

@Sanjays2402

Copy link
Copy Markdown
Contributor

Description

TaskQueryBuilder._build_date_filter_conditions compared the datetime columns against the bare end_date, which SQLite coerces to midnight, so a same-day value carrying a time was excluded. The default TaskRepository.get_filtered() truncates to a date and includes it, so both repository implementations returned different results for the same query. end_date is now turned into an exclusive next-day bound, making both paths whole-day inclusive.

Related Issue

Closes #1164

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Changes Made

  • _build_date_filter_conditions: end_date becomes an exclusive end_date + 1 day bound (field >= start / field < end + 1d) instead of between/<= end_date.
  • TaskRepository._matches_date_filter: docstring now names the SQL helper it mirrors and states the whole-day-inclusive end_date semantics.
  • New regression test with a time-bearing boundary value asserting both implementations agree; updated the query-builder SQL-shape assertion that checked for between.

Testing

Test Environment

  • OS: macOS
  • Python version: 3.14
  • UV version: N/A (plain venv + pytest)

Tests Performed

  • Unit tests pass (packages/taskdog-core/tests, 1175 passed)
  • Added new tests for new features
  • Manual testing completed

test_date_filter_end_date_includes_same_day_time fails on main (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

  • Linter passes (Ruff check on changed files)
  • Type checker passes (make typecheck)
  • Code is formatted (make format)
  • No new warnings introduced
  • Code follows project conventions

Documentation

  • Added/updated docstrings

Package Affected

  • taskdog-core

Breaking Changes

Behavioural change to the SQL filter only, bringing it in line with the documented inclusive end_date and with the default repository implementation.

Checklist

  • My code follows the coding standards of this project
  • I have performed a self-review of my own code
  • I have commented my code in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective
  • New and existing unit tests pass locally with my changes

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 Kohei-Wada left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. end_bound is recomputed on every iteration of the for field in date_fields loop. It doesn't depend on field, so please hoist it above the loop.

  2. (field >= start_date) & (field < end_bound) — the surrounding code uses the SQLAlchemy function style (or_(...)), so and_(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.

@Kohei-Wada

Copy link
Copy Markdown
Owner

Thanks! Nice catch on the two repository implementations disagreeing — the regression test asserting both paths agree is exactly the right shape. Merging.

@Kohei-Wada
Kohei-Wada merged commit 740d50d into Kohei-Wada:main Jul 26, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(core): default get_filtered and SQL date filters disagree on the end_date boundary

2 participants