Skip to content

Fix date filtering for all-day entries across timezones - #2392

Merged
patrickunterwegs merged 1 commit into
developfrom
claude/time-filter-timezone-bug-i88ucr
Sep 11, 2026
Merged

patrickunterwegs merged 1 commit into
developfrom
claude/time-filter-timezone-bug-i88ucr

Conversation

@patrickunterwegs

Copy link
Copy Markdown
Member

Summary

This PR fixes date filtering logic to correctly handle all-day entries across different timezones. Previously, filtering by date ranges would incorrectly include entries from neighboring days when the system timezone was not UTC, since all-day entries are stored as midnight UTC while timed entries are stored as epoch milliseconds.

Key Changes

  • Added timezone-aware filtering methods in ICal4List:

    • getDayRangeFilter(): Generates SQL CASE statements that apply different boundary calculations for all-day entries (UTC-based) vs timed entries (local timezone-based)
    • getBeforeNowFilter() and getAfterNowFilter(): Handle "past" and "future" filters with timezone awareness
  • Updated all date filtering queries to use the new methods:

    • Replaced hardcoded BETWEEN clauses with timezone-aware filtering for start date, due date, and completed date filters
    • Updated filters for: today, tomorrow, within 7 days, past, future, overdue, and date range filters
    • Fixed day range filters to properly handle relative day offsets
  • Added utility functions in DateTimeUtils:

    • getStartOfDayUTCAsLong(): Returns midnight UTC for a given date (for all-day entries)
    • getStartOfDayLocalAsLong(): Returns midnight in local timezone (for timed entries)
    • getLocalDateFromUTCMidnight(): Converts UTC midnight epoch to LocalDate
  • Added comprehensive test coverage in ICal4ListTest:

    • Tests verify that date filters correctly include/exclude entries based on local timezone
    • Tests confirm all-day entries are compared in UTC while timed entries use local timezone
    • Tests use non-standard timezone (Australia/Adelaide with +09:30 offset) to catch rounding issues

Implementation Details

The core issue is that jtx stores:

  • All-day entries as midnight UTC (e.g., 2024-03-15T00:00:00Z)
  • Timed entries as epoch milliseconds of the actual instant in the user's timezone

When filtering by day boundaries, using UTC-based calculations for both types causes entries to slip into adjacent days on non-UTC timezones. The solution uses SQL CASE statements to apply the correct boundary calculation based on the timezone column value.

https://claude.ai/code/session_01Am92mRS8fz3WKPdBSNdVKS

Time based filters showed entries of the neighbouring day whenever the
device timezone was not UTC: the day boundaries were calculated with
DateTimeUtils.getTodayAsLong(), which returns midnight UTC. That is the
correct representation for all-day entries (they are stored as midnight
UTC), but entries with a time are stored as the epoch millis of the
actual instant, so e.g. "Started today" covered "today 00:00 UTC" until
"tomorrow 00:00 UTC" - in a +11:30 timezone that is local 11:30 today
until 11:30 tomorrow.

The day boundaries are now calculated for both cases separately and the
query picks the matching one via the timezone column of the respective
date, so all-day entries keep being compared in UTC while all other
entries are compared against the beginning of the local day. This
applies to the today/tomorrow/within 7 days filters, the in past/future
filters (all-day entries of today are now neither), the date range and
day range filters (the pickers deliver midnight UTC as well) and to the
lookup of the next recurring instance.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Am92mRS8fz3WKPdBSNdVKS
@patrickunterwegs
patrickunterwegs merged commit 17ea166 into develop Sep 11, 2026
3 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.

2 participants