timezones
Owlette tracks three independent timezone actors: each user picks which one renders absolute timestamps, and each site picks whether process launch windows follow the site's clock or each machine's own.
three actors
| actor | source | written by | decides when schedules fire |
|---|---|---|---|
| machine | The agent's own Windows local timezone | Agent writes machine_timezone_iana into the machine's Firestore doc on every heartbeat | Always for scheduled reboots. For process launch windows too, unless the site has opted into site time |
| user | The dashboard viewer's preferred IANA timezone | User sets timezone in Preferences (default: browser-detected) | Never — display only |
| site | The site's configured timezone | Set when the site is created (detected from the creator's browser, editable there) and changeable afterwards in Manage Sites | Process launch windows, but only once the site turns on schedulesFollowSiteTime (see process schedules) |
All three are stored as IANA identifiers (e.g. America/New_York, Europe/Berlin). There is no "offset" or "abbreviation" field — offsets are resolved from the IANA name so that DST transitions work correctly.
The last column is the part that catches people out: a display mode never moves a schedule. Only the site's opt-in does, and only for process launch windows.
display modes
Each user picks one timeDisplayMode in preferences. That choice determines which actor's timezone is used to render absolute timestamps (heartbeats, activity logs, crash events, etc.) across the whole dashboard.
| mode | behavior | best for |
|---|---|---|
user | All times render in the user's timezone | Single-operator setups where you always want your own local time |
machine (default) | Each machine's times render in that machine's own local tz | Distributed kiosks across multiple timezones — "when did the Tokyo kiosk crash?" stays in JST |
site | All times render in the site's configured tz | Single-site teams where the site's local time is the shared reference |
In machine mode, two cards on the same dashboard page may render times in two different timezones. A <TimezoneChip> next to each list of times tells you which actor delivered the timezone so the ambiguity is never silent.
fallback chain
When the primary source for the chosen mode is missing, Owlette falls back in a fixed order (see getDisplayTimezone() in web/lib/timeUtils.ts):
| mode | fallback order |
|---|---|
user | user's tz → browser → UTC |
machine | machine tz → site tz → browser → UTC |
site | site tz → browser → UTC |
machine falls back to site (not user) because if the agent hasn't reported its tz yet, the site's tz is the closest "this installation lives in X" approximation. Browser detection is always the last resort before UTC.
schedule editor
Schedule editors are unaffected by the user's display mode, but they do not all use the same timezone reference. Each scheduler uses the timezone that its feature expects:
| feature | timezone used | notes |
|---|---|---|
| process launch windows | The site's timezone if the site has opted into site time; each machine's local timezone otherwise (the default) | Opt-in is per site — see process schedules below. The editor labels which clock a window will be read against. Its outside-window hint is computed in the site's timezone either way: on site time that is exactly what the agents do, on machine time it is a prediction of their clocks and the machine's clock is what decides. |
| scheduled restarts | Machine local timezone, always | The reboot dialog shows a machine timezone chip and the agent resolves each reboot entry against the machine's own Windows local timezone. A "03:00" reboot means 03:00 on that machine, even at a site that runs its process windows on site time. This is deliberate: keeping a box's maintenance window on the box's own clock is a different question from keeping a venue's opening hours on the venue's clock. |
| talon schedule triggers | The site's timezone, always | Automations have always been site-scoped, so a schedule trigger fires on the site's clock (UTC when the site has no timezone set) regardless of schedulesFollowSiteTime. |
All three are wall-clock schedules, not absolute UTC instants. Changing your dashboard display mode affects timestamp rendering only; it does not reinterpret saved schedule entries.
process schedules
A process window of "09:00-17:00 Mon-Fri" means 09:00 on whichever clock its site follows. Sites created since site time shipped follow the site's own timezone — the create-site dialog detects it from your browser and you can change it there before the site exists. Sites created before it evaluate windows on each machine's own clock, so a fleet spread across five cities opens at five different absolute instants, until a site admin answers the dashboard's one-time prompt.
The switch is a single field on the site, schedulesFollowSiteTime, and it has three states rather than two:
| state | what the machines do | how a site gets here |
|---|---|---|
| absent | Machine-local windows — the original behavior, unchanged | Every site that predates site time (plus the rare new site whose browser reported no timezone at all). Site admins see a one-time banner on the dashboard asking which clock the site should use; it appears only when the site actually has a scheduled process |
false | Machine-local windows | The site was asked and kept machine clocks. Touring rigs and multi-city fleets usually want this |
true | Every machine evaluates its process windows in the site's timezone | The site was created after site time shipped — the create-site dialog writes this flag and the timezone together — or it was asked and chose site time, or an admin turned it on afterwards |
Absent and false behave identically on the machines. They are stored differently so the dashboard can tell whether the site has answered yet — that is the only thing the banner's presence depends on.
a site cannot follow site time without a timezone
Turning the flag on is rejected unless the site ends the write with a non-empty timezone. Set the timezone and the flag together in one edit — the dashboard banner does exactly that, and so should an API caller. Turning it back off never needs a timezone.
how the change reaches the machines
Agents ask the API which clock to use (GET /api/agent/site) on every connect and every 15 minutes after that, so a flip takes up to about a quarter hour to reach the fleet. Nothing is pushed, and no agent or service restart is involved.
The API returns a timezone only when the flag is exactly true and the site has one set; in every other case it returns null and the agent clears whatever it had cached. That is how switching site time back off drops the fleet to machine clocks on its own.
Agents older than 3.2.3 ignore the site's timezone and keep evaluating windows on their own clock. The dashboard flags those machines with an advisory note — it never blocks the setting, since one offline machine would otherwise hold an entire site back. Update them and they pick the site's clock up at their next refresh.
what a flip does not do
It does not rewrite saved schedule entries. The same stored "09:00" is simply read against a different clock, so a fleet that spans timezones will genuinely shift when the flag goes on — check the windows still mean what you want first. Scheduled reboots are not affected at all.
related files
web/lib/timeUtils.ts—getDisplayTimezone(),getBrowserTimezone(),COMMON_TIMEZONES, searchable picker helpersweb/contexts/AuthContext.tsx—UserPreferences.timezone/timeDisplayMode/timeFormatweb/app/api/agent/site/route.ts— the projection agents read; gatestimezoneonschedulesFollowSiteTime === trueweb/lib/actions/updateSite.server.ts— refusestruefor a site that would end the write without a timezoneweb/components/CreateSiteDialog.tsx— surfaces the detected browser timezone and creates the site with it andschedulesFollowSiteTime: truein one write- Agent-side:
machine_timezone_ianais written alongside other heartbeat metrics; the cached schedule timezone is published inservice_status.jsonasfirebase.schedule_timezone
activity logs
The activity logs page shows a site-scoped timeline for agent, process, command, deployment, and scheduled reboot events. Open it from the dashboard menu by selecting logs, or go directly to /logs.
account settings
Your own preferences, not the site's: how timestamps render, which alert emails you get, which machines you have muted, your hoot key, password and second factors, and your API keys.