Skip to content

Add a separate end time zone for events (#311)#1231

Open
josephkimani wants to merge 7 commits into
FossifyOrg:mainfrom
josephkimani:feat/start-end-timezones
Open

Add a separate end time zone for events (#311)#1231
josephkimani wants to merge 7 commits into
FossifyOrg:mainfrom
josephkimani:feat/start-end-timezones

Conversation

@josephkimani

Copy link
Copy Markdown

What

Adds an optional separate end time zone for events, so an event can start in one zone and end in another — e.g. a flight that departs New York and lands in London shows the correct local time at each end. Implements the long-standing request in #311 (and #1113).

When no distinct end zone is set, behaviour is unchanged: an empty end zone means "same as the start zone", so existing events and the common single-zone case are completely unaffected.

How

  • Model (Event): new end_time_zone column (Room v11 → v12, additive migration with DEFAULT ''). getEndTimeZoneString() falls back to the start zone when the end zone is unset or unknown.
  • Time math (computeStartEndSeconds): interprets the start and end wall-clock times each in its own zone, tolerating DST spring-forward gaps.
  • Editor (EventActivity): reveals a second time-zone row plus a device-local-time readout, all gated behind the existing "Allow changing event time zones" setting. All-day and recurring events keep a single zone.
  • CalDAV: reads/writes the native EVENT_END_TIMEZONE column — no extra storage.
  • ICS import: parses a per-property TZID for both DTSTART and DTEND.

New unit tests cover the time math (incl. a DST-gap case), the end-zone fallback/alias handling, and TZID parsing.

Scope / follow-up

In-app, on-device, and CalDAV (intra-device) all carry the end zone today. ICS export (TZID + VTIMEZONE) and full cross-client/server propagation are intentionally deferred to a follow-up PR — correct VTIMEZONE generation is a sizeable change that deserves its own review.

Testing

  • Unit tests pass; detekt and all debug flavors build clean.
  • Emulator-verified: distinct start/end zones persist and round-trip through edit/view and CalDAV; all-day and recurring events stay single-zone; the local-time readout reflects the device zone.

🤖 Generated with Claude Code

josephkimani and others added 6 commits June 22, 2026 01:31
Empty end_time_zone means 'same as start zone', so existing events are
unchanged. getEndTimeZoneString() falls back to the start zone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the single time-zone row with a zone label under each of the
start and end time (tappable -> SelectTimeZoneActivity), and a local-time
readout shown when a zone differs from the device zone. Gated behind
allowChangingTimeZones; all-day events unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The CalDAV import loop reads Events.EVENT_END_TIMEZONE, but the column was
missing from the cursor projection. Fossify Commons' getStringValue uses
getColumnIndexOrThrow, so the read threw on the first event row;
queryCursorInlined silently swallowed it, leaving fetchedEventIds empty.
The subsequent cleanup pass then deleted every locally-cached CalDAV event
because none were in the (empty) fetched set, making CalDAV events vanish
from the app. Deletion ran with deleteFromCalDAV=false, so server data was
unaffected and a fixed re-sync restores the events.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant