Times come off the API as UTC and get formatted into the signed-in user's timezone at render, through the same vue-i18n named formats that already handle dates and numbers. Only the timezone is injected per call, the locale is resolved by vue-i18n, so a single useDateTime wrapper covers every date on the site without each caller having to think about zones.
There's no guest-side persistence here the way locale has it. Locale gets resolved from the browser and kept in local storage so it survives a refresh before anyone signs in. A timezone only matters once there's an account to format times for, so nothing is stored locally. It's read straight from the browser with Intl.DateTimeFormat().resolvedOptions().timeZone at the one moment it's needed, registration, and sent up on the same payload that carries the auto detected locale.
The account carries its own timezone, applied on login, so it follows the user across devices instead of tracking whatever machine they happen to be on. That's the point for time display, someone who set their zone to America/New_York should keep seeing New York times from a laptop that's physically in Berlin. useDateTime reads the timezone straight off the signed-in user, so it assumes a user is present, and dates only render on authenticated pages.
The timezone list feeds off the API rather than a hardcoded front-end constant, with defaultTimezone in config as the fallback selection. Labels are localized server side, which is the one wrinkle worth knowing about. When the user changes locale in settings the timezone query is invalidated so the labels come back in the new language. Otherwise the list is cached indefinitely, it doesn't change between loads.
Localization covers the locale half of the same settings form, along with the auto detect and cross-device pattern this one mirrors.