ADR 0014: Time zones and regional display
- Status: Accepted
- Date: 2026-10-30
Decision
Section titled “Decision”Workspace Language & region stores a named IANA time zone in sys_workspaces.time_zone. Administrators and Designers configure it together with the language policy in the existing versioned configure_workspace_languages transaction. Omitted timeZone leaves that setting unchanged during an intentional partial update. Personal Language & region stores an optional global sys_users.time_zone; null inherits the current workspace. configure_user_localization atomically saves the owner’s language and time zone with expected previous values. Both paths journal each changed property under one change ID, reject stale writes and produce no journal/version changes for no-ops. Better Auth exposes the saved preference but does not accept direct profile writes to it.
get_time_zone_catalog supplies named zones supported by the server’s Intl/IANA data, including UTC. Numeric offsets and unknown zones are rejected by shared contracts. New-workspace UI proposes the browser zone and allows changing it before creation; API/MCP defaults to UTC. Workspace defaults are UTC and personal overrides are null in the current installation. Display changes never rewrite stored instants or infer a workspace zone from the server location.
The effective personal/workspace zone governs timestamp input, record-list dates, custom timestamp values, record/definition journals and account-session times. PostgreSQL timestamptz values remain instants; API/MCP require explicit offsets and return UTC. Date-only fields remain calendar dates and are never shifted by time zones. The Temporal polyfill converts web wall-clock input using the selected named zone, independent of the browser zone. Spring-forward gaps are invalid; autumn overlaps require selecting one of the two UTC instants. Unchanged existing instants retain their occurrence and millisecond precision.
Other regional preferences
Section titled “Other regional preferences”Workspace regional JSONB stores locale, date-format override, 12/24-hour override, number-format override and first weekday. The installed regional-format catalog covers German (Germany/Austria/Switzerland) and English (US/UK/Canada/Australia), independently of interface language. Each override initially derives from the selected locale. New workspaces default to de-DE for German or en-US for English; subsequent language changes do not silently replace configured regional settings. The current installation has no earlier-regional-schema adoption path under ADR 0028.
Personal regional_preferences JSONB contains nullable overrides for each property. Null inherits that workspace property; a selected personal locale affects any inherited automatic format. All-null personal settings normalize to null. Workspace updates share language_version; personal changes compare expected prior regional settings. Each changed property gets its own journal event under the common change ID, with rollback/no-op rules shared with language/time-zone configuration. Direct auth profile input cannot write these preferences.
The shared display formatters apply to custom date/time, exact numeric/money values, list metadata, journals and security-session dates. Decimal strings pass to Intl without conversion to floating-point numbers. Date-only values are formatted without zone shifting. The settings form previews dates, time, numbers and first weekday. Week start is stored and previewed for future calendar consumers; no calendar view is introduced. Date and time editing uses regional text controls with the standard shadcn Calendar/Popover composition rather than browser-controlled date/time formats. Date order, 12/24-hour cycle, calendar locale and first weekday follow the effective regional settings; calendar Today follows the effective named time zone. ISO calendar-date paste remains accepted. Time entry retains optional seconds/milliseconds and requires AM/PM in 12-hour mode. Integer/decimal/money drafts use regional separators and exact strings, load formatted and format valid values on blur; invalid/incomplete input stays editable. Grouped paste accepts ordinary/nonbreaking/narrow spaces only for space-grouping locales and equivalent apostrophes for apostrophe-grouping locales. Currency display keeps the ISO code, follows regional placement and independently overridden number separators, and never converts the stored amount/currency. Currency belongs to money field defaults and each saved value; preferences never convert or rewrite stored currencies/values.
Open record forms capture the format that gives their drafts meaning. Preference changes reformat valid numeric values and their baseline together through exact canonical strings, preserving semantic dirty state. Incomplete/invalid numeric or temporal drafts retain their prior locale/zone, show a pending-format notice and block Save until corrected or reset. Valid timestamps remain instants across zone changes; ambiguous local times require an explicit occurrence before any format transition. Incomplete date/time drafts cannot be mistaken for valid instants.
Validation
Section titled “Validation”Application tests cover catalog validation, own-user scoping, role checks, optimistic conflicts, no-ops, API/MCP access, retained preferences across repeated initialization and rollback on journal failure. Web tests cover workspace/personal fallback, summer/winter offsets, fractional-hour zones, millisecond round trips, gaps and explicit overlapping instants. Chrome acceptance on an isolated disposable fixture verified personal Tokyo override saving, inherited Berlin fallback, workspace UTC/Berlin changes, and matching table/form display. A 10:30 UTC instant displayed as 19:30 in Tokyo; a 20:00 Tokyo edit displayed as 13:00 in Berlin. The Berlin spring gap blocked Save, and both autumn occurrences could be selected, saved and reopened with the correct offset. Settings-section changes preserved separate drafts; the occurrence selector retained focus after selection. Acceptance data remained isolated. Current unreleased instances are rebuilt from ADR 0028 rather than migrated from earlier development schemas.
Regional input regression coverage includes all seven locales and format overrides, exact large amounts, semantic no-op formatting, spacing variants, safe/blocked draft transitions, calendar-date validation, 12/24-hour boundaries, milliseconds and DST gaps/overlaps. Isolated browser acceptance additionally verifies actual record-form serialization through an in-memory adapter, format changes with pending invalid input, explicit autumn occurrences, and keyboard calendar selection without writing development business records.