TIME_WINDOW rule dates shift one day earlier in time zones ahead of Europe/Paris #311

Closed
opened 2026-10-19 13:33:35 +02:00 by nessar · 0 comments
Owner

Problem

TIME_WINDOW rule dates reach the planner one day earlier than the user picked whenever the time zone of the device is ahead of Europe/Paris (for example Europe/Helsinki, Asia/, Australia/, Pacific/Auckland).

The date picker builds local-midnight Date objects (src/app/shared/day-first-date-adapter.ts, parse). Rules are handed to the planner as those Date objects (planning-calculation.service.ts, request: rules: this.rules.rules), copyDate keeps the instant (leave-planner.service.ts:118), and dateKey() reads the Paris date of that instant (leave-planner.core.ts:599, used for rule windows at :942-943). Local midnight east of Paris is still the previous day in Paris.

The rules panel keeps displaying the picked date (rules-panel.ts:341, toLocaleDateString), so the shift is invisible: the plan silently uses a window starting and ending one day earlier.

Balances are not affected: planning-calculation.service.ts:94-97 formats them with dayjs(...).format("YYYY-MM-DD") from local components before planning.

Evidence

planningDateInParis(new Date(2026, 11, 20)) (the default Christmas window start in rule-service.ts:145) gives:

TZ planner date
Europe/Paris 2026-12-20
UTC 2026-12-20
America/New_York 2026-12-20
Pacific/Auckland 2026-12-19

The conversion was run; the path from the rules panel to dateKey() was traced by reading, not by running a full plan in an east-of-Paris time zone.

Expected

A TIME_WINDOW rule plans on the calendar dates the user picked, whatever the time zone of the device, matching how balance dates are already handled.

Notes

  • Saved rules are stored as UTC ISO strings and restored as the same instant (rule-service.ts:195, 214), i.e. the local midnight of the picked date. Converting from local components on the same device recovers the picked date; only a device time-zone change between saving and planning would misread it.
  • Found while grilling #301 (today marker vs Paris planning date); kept separate because it changes planning results rather than display.
## Problem TIME_WINDOW rule dates reach the planner one day earlier than the user picked whenever the time zone of the device is ahead of Europe/Paris (for example Europe/Helsinki, Asia/*, Australia/*, Pacific/Auckland). The date picker builds local-midnight `Date` objects (`src/app/shared/day-first-date-adapter.ts`, `parse`). Rules are handed to the planner as those `Date` objects (`planning-calculation.service.ts`, `request`: `rules: this.rules.rules`), `copyDate` keeps the instant (`leave-planner.service.ts:118`), and `dateKey()` reads the **Paris** date of that instant (`leave-planner.core.ts:599`, used for rule windows at `:942-943`). Local midnight east of Paris is still the previous day in Paris. The rules panel keeps displaying the picked date (`rules-panel.ts:341`, `toLocaleDateString`), so the shift is invisible: the plan silently uses a window starting and ending one day earlier. Balances are not affected: `planning-calculation.service.ts:94-97` formats them with `dayjs(...).format("YYYY-MM-DD")` from local components before planning. ## Evidence `planningDateInParis(new Date(2026, 11, 20))` (the default Christmas window start in `rule-service.ts:145`) gives: | TZ | planner date | | --- | --- | | Europe/Paris | 2026-12-20 | | UTC | 2026-12-20 | | America/New_York | 2026-12-20 | | Pacific/Auckland | **2026-12-19** | The conversion was run; the path from the rules panel to `dateKey()` was traced by reading, not by running a full plan in an east-of-Paris time zone. ## Expected A TIME_WINDOW rule plans on the calendar dates the user picked, whatever the time zone of the device, matching how balance dates are already handled. ## Notes - Saved rules are stored as UTC ISO strings and restored as the same instant (`rule-service.ts:195, 214`), i.e. the local midnight of the picked date. Converting from local components on the same device recovers the picked date; only a device time-zone change between saving and planning would misread it. - Found while grilling #301 (today marker vs Paris planning date); kept separate because it changes planning results rather than display.
nessar added the needs-triage label 2026-10-19 13:33:35 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: nessar/vac-optimizer#311