Repository navigation
feat(settings): display timezone (account default + per-device override) - #25
Merged
Merged
Conversation
Mirrors web's two-tier timezone preference: - Account default (System.timezone): an IANA zone or null = "automatic" (each device's own clock), synced across devices via PATCH /v1/systems/me. "Automatic" is an explicit null the server must receive, so it goes through a dedicated serialize-nulls body (the shared codegen adapter drops null fields; the backend uses exclude_unset). - Device override (local pref): shadows the account on this device only. Absent = follow the account, "auto" = pin to this device's clock, or a pinned zone. Resolution (device override > account > device-local) is exposed app-wide through a LocalDisplayTimeZone composition local, sourced from a cached account timezone (refreshed on login) combined with the local override. UI lives under Settings > Appearance: an account picker and an "On this device" override, each using a searchable picker that leads with a "Common" group of friendly, DST-compensated names (Eastern Time, UK / Ireland, ...) then the full zone list, matching web's timezone-select. Front history, journal, and member-revision timestamps now render in the resolved zone. This also fixes those journal/member times previously rendering in the server's offset rather than any chosen zone. Remaining timestamp surfaces (analytics, polls, files, imports, retention, the widget, and wear) still use the device clock and are tracked as follow-up. Adds unit tests for the resolver and the common-zone mapping.
SiteRelEnby
enabled auto-merge
July 12, 2026 21:52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the display-timezone preference to Android, mirroring web's two tiers.
Tiers
System.timezone): an IANA zone or null = "Automatic" (each device's own clock). Synced across devices and exported. Set viaPATCH /v1/systems/me.nullthe server must receive. Since Moshi codegen drops null fields and the backend usesmodel_dump(exclude_unset=True)(omit = unchanged, null = auto), the account tier sends a dedicated single-field body serialized with.serializeNulls().PreferencesRepository): shadows the account on this device only. Absent = follow the account,"auto"= pin to this device's clock, or a pinned IANA zone.Resolution (device override > account > device-local) is exposed app-wide via a
LocalDisplayTimeZonecomposition local, sourced from a cached account timezone (refreshed on login, persisted likefile_cdn_base) combined with the local override.UI
Settings → Appearance gains an Account timezone picker and an On this device override. Both use a searchable picker that leads with a "Common" group of friendly, DST-compensated names (Eastern Time (US & Canada), UK / Ireland (London), ...) then the full "All time zones" list, matching web's
timezone-select. Selected common zones display their friendly label.Applied
Front history, journal entry, and member-revision timestamps render in the resolved zone. This also fixes a latent bug where those journal/member times rendered in the server's offset (
OffsetDateTime.toLocalDateTime()) rather than any chosen zone.Scope / follow-up
Deliberately partial sweep. Remaining timestamp surfaces still render in the device clock and are tracked as follow-up: analytics grouping, poll close-dates, files, imports, retention, custom-field date editor, the history chart buckets + date-range pickers, the RecentFronts widget, and the Wear module. (Widget/wear are separate processes; the ViewModel surfaces need the effective zone via prefs rather than the composition local.)
Testing
:app:assemblePlayReleasegreen (through R8); unit suite green.Backend dependency
The account tier reads/writes
System.timezoneon/v1/systems/me, so it needs the timezone-enabled backend deployed to the target instance.