Timezone mismatch
Wrong dates on the report or the chart
A surprising number of "help desk" tickets come from this. The data is correct, the rule is correct, the UI is rendering in the wrong zone. This page walks the three places where timezones live.
The three timezones
OpenSense's stack has three timezones in play. They are usually different.
- Storage TZ. Always UTC. Every measurement, every event, every
audit-log row carries
ts_utc. This is what is in the database. - Site TZ. Set per site (
Europe/Bratislava,Asia/Tokyo, …). Used by the PDF report renderer for day boundaries and labels. - Browser TZ. Used by the dashboard chart when rendered in your browser. The chart x-axis labels reflect your local clock.
This is intentional: an operator in the EU travelling to Tokyo wants
to see the dashboard in JST, while the inspector at the Bratislava
café gets a PDF in Europe/Bratislava regardless of who issued it.
Symptom: chart and PDF disagree
If the dashboard chart shows a +9 °C spike at 14:30 and the PDF shows the same spike at 12:30, that is the storage-TZ → browser-TZ vs storage-TZ → site-TZ difference. The data is the same; the labelling differs by your offset minus the site offset.
This is correct behaviour for travel scenarios but confuses operators
who never leave their site. To make them agree, set the dashboard's
"display timezone" to the site's timezone in Account → Preferences → Display timezone. The chart then matches the PDF.
Symptom: a "yesterday" report is empty
If you click "Yesterday's report" at 02:00 local time:
- It is 01:00 UTC.
- The report engine asks: "what measurements fall in
2026-05-16 00:00 site-local→2026-05-16 24:00 site-local?" - For a site in
Europe/Bratislava(UTC+2 in summer), that is2026-05-15 22:00 UTC→2026-05-16 22:00 UTC. - You have until 02:00 site-local on the 17th for "yesterday the 16th" to be a full day.
Fix: request "the previous full local day", or wait until later in the morning. The PDF service refuses to render an incomplete day with a friendly modal; the API returns an empty (header-only) PDF.
Symptom: DST shift makes a thresholdcross at the wrong hour
If a rule has a time-of-day window (FREQ=DAILY;BYHOUR=22), it fires
at 22:00 in the site's timezone, respecting DST. On the morning
after a spring-forward, the window happens 23 hours after the
previous one; on the morning after a fall-back, 25 hours.
If your rule is for a process that runs on a fixed real-world clock
(e.g. a thermal-disinfection cycle scheduled by a PLC at 03:00 local
without DST awareness), the rule's window will drift from the
process's actual time twice a year. Fix: use UTC in the rule's
rrule (TZID=UTC;FREQ=DAILY;BYHOUR=...), or set the site's
timezone to UTC (rare).
Symptom: "ts is in the future"
If your device's clock is wrong (no NTP, or NTP misconfigured), it may
send ts in the future. OpenSense accepts ts up to 30 seconds
in the future (clock skew tolerance) and rejects beyond that with
422 ts_in_future.
Fix the device clock. For ESPHome:
time:
- platform: sntp
servers:
- pool.ntp.org
For Shelly, the device gets time from your WiFi router via DHCP option
42 or from the Shelly cloud. If your router does not advertise an NTP
server, configure one in the Shelly's Time settings.
Symptom: the PDF labels show UTC instead of local
Your site's timezone field is empty or UTC. Set it:
Site → Settings → Timezone → Europe/Bratislava (or whatever applies).
Re-issue the report. The cached PDF for the period is invalidated and
re-rendered with correct labels.