Closes the last open item on #152: clients filter by calendar day without doing any time-zone math.
Problem
The server side of #152 (true-instant filtering, PR #162) is done. Clients still built calendar-day ranges as device-local midnights, though: FileViewer's startOfDay/endOfDay, its presets and the custom picker. Whenever the phone's zone differs from the owner's display_tz (travel), a range shifts by the offset, so a photo can show inside a day in the grid but fall out of that day's filter.
Fix
/photos, /photos/exif and /photos/search/unified accept date_from_day / date_to_day (YYYY-MM-DD). date_view::apply_day_bounds turns them into the first day's start and the last day's end in the owner's display zone, the same days /memories groups by, using day_start_instant, so DST days are handled. Each day param replaces its instant counterpart, and an unparseable day is ignored. Requests without day params never read prefs.
date_from / date_to (instants) are unchanged and still right for windows around a moment (FileViewer's messages photo sheet; Apollo's track matching).
Also fixes the stale list_exif_summary doc comment (it still said date_taken), and documents the params in CLAUDE.md.
The client half is in FileViewer-React's fix/calendar-day-date-filters PR. Deploy this first: an older server ignores the day params and drops the date filter.
Tests
day_bounds_are_the_display_zone_day: July 5 for a NY owner vs a Tokyo owner, plus a 23-hour DST day.
day_bounds_replace_their_side_only_and_skip_bad_input: also checks prefs aren't read when no day param is given.
e2e:check_wall_clock.py now also asserts, for every fixture, that its display-zone day includes it and the days either side exclude it. I ran it against a fresh instance of this branch on another port: 97/97.
Closes the last open item on #152: clients filter by calendar day without doing any time-zone math.
## Problem
The server side of #152 (true-instant filtering, PR #162) is done. Clients still built calendar-day ranges as **device-local** midnights, though: FileViewer's `startOfDay`/`endOfDay`, its presets and the custom picker. Whenever the phone's zone differs from the owner's `display_tz` (travel), a range shifts by the offset, so a photo can show inside a day in the grid but fall out of that day's filter.
## Fix
`/photos`, `/photos/exif` and `/photos/search/unified` accept **`date_from_day` / `date_to_day`** (`YYYY-MM-DD`). `date_view::apply_day_bounds` turns them into the first day's start and the last day's end in the owner's display zone, the same days `/memories` groups by, using `day_start_instant`, so DST days are handled. Each day param replaces its instant counterpart, and an unparseable day is ignored. Requests without day params never read prefs.
`date_from` / `date_to` (instants) are unchanged and still right for windows around a moment (FileViewer's messages photo sheet; Apollo's track matching).
Also fixes the stale `list_exif_summary` doc comment (it still said `date_taken`), and documents the params in CLAUDE.md.
The client half is in FileViewer-React's `fix/calendar-day-date-filters` PR. **Deploy this first**: an older server ignores the day params and drops the date filter.
## Tests
- `day_bounds_are_the_display_zone_day`: July 5 for a NY owner vs a Tokyo owner, plus a 23-hour DST day.
- `day_bounds_replace_their_side_only_and_skip_bad_input`: also checks prefs aren't read when no day param is given.
- **e2e:** `check_wall_clock.py` now also asserts, for every fixture, that its display-zone day includes it and the days either side exclude it. I ran it against a fresh instance of this branch on another port: **97/97**.
- Full suite passes and clippy is clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
/photos, /photos/exif and unified search take date_from_day /
date_to_day (YYYY-MM-DD): the server turns them into the first day's
start and the last day's end in the owner's display zone, the same days
/memories groups by. Each replaces its instant counterpart. Clients stop
computing midnights in the device's zone, which drifted by the travel
offset whenever the phone's zone differed from display_tz.
e2e check: every fixture is included by its display-zone day and
excluded by the days either side.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes the last open item on #152: clients filter by calendar day without doing any time-zone math.
Problem
The server side of #152 (true-instant filtering, PR #162) is done. Clients still built calendar-day ranges as device-local midnights, though: FileViewer's
startOfDay/endOfDay, its presets and the custom picker. Whenever the phone's zone differs from the owner'sdisplay_tz(travel), a range shifts by the offset, so a photo can show inside a day in the grid but fall out of that day's filter.Fix
/photos,/photos/exifand/photos/search/unifiedacceptdate_from_day/date_to_day(YYYY-MM-DD).date_view::apply_day_boundsturns them into the first day's start and the last day's end in the owner's display zone, the same days/memoriesgroups by, usingday_start_instant, so DST days are handled. Each day param replaces its instant counterpart, and an unparseable day is ignored. Requests without day params never read prefs.date_from/date_to(instants) are unchanged and still right for windows around a moment (FileViewer's messages photo sheet; Apollo's track matching).Also fixes the stale
list_exif_summarydoc comment (it still saiddate_taken), and documents the params in CLAUDE.md.The client half is in FileViewer-React's
fix/calendar-day-date-filtersPR. Deploy this first: an older server ignores the day params and drops the date filter.Tests
day_bounds_are_the_display_zone_day: July 5 for a NY owner vs a Tokyo owner, plus a 23-hour DST day.day_bounds_replace_their_side_only_and_skip_bad_input: also checks prefs aren't read when no day param is given.check_wall_clock.pynow also asserts, for every fixture, that its display-zone day includes it and the days either side exclude it. I ran it against a fresh instance of this branch on another port: 97/97.🤖 Generated with Claude Code
ebafa0decato139de444af