Taking the stored offset at face value is what puts an all-day reminder on the
wrong hour, and owning the alarm is what finally allows fixing it.
An all-day occurrence begins at UTC midnight, and the offset in `Reminders` is
not a plain lead time: `AllDayReminderEncoding` folds the wanted wall-clock hour
into it, sampled against one date's UTC offset. Fire at `begin - minutes` and
every occurrence in a different DST phase than the sampled one drifts by the
offset delta — an hour early one way, an hour late the other, which for a yearly
birthday is every second occurrence. Its KDoc documents that drift as inherent to
the provider model. It was, while the provider held the alarm.
Rows written by other calendar apps have the opposite problem: a conventional
1440 carries no hour at all, so it fires at UTC midnight — 02:00 local in summer
Berlin, and a day early west of UTC, where UTC midnight still falls on the
previous local date.
So the offset is now read only for which day it means, and the hour comes from
the one global all-day reminder setting, recomposed against each occurrence's own
date. Plain multiples of 1440 are read at face value, which covers foreign rows
and stays right for our own rows that land on a multiple; anything else keeps the
local-date recovery `fromProviderAllDayMinutes` already uses for display, so the
notification arrives on the day the event screen promises.
Timed reminders are untouched: `begin` is an absolute instant, so `begin -
minutes` is exact in any zone across any boundary. A test pins that too.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>