[{"data":1,"prerenderedAt":289},["ShallowReactive",2],{"doc-\u002Ftroubleshooting\u002Ftimezone-mismatch":3},{"id":4,"title":5,"body":6,"description":279,"edit":280,"extension":281,"meta":282,"navigation":283,"path":284,"seo":285,"stem":286,"vertical":280,"weight":287,"__hash__":288},"content\u002Ftroubleshooting\u002Ftimezone-mismatch.md","Timezone mismatch",{"type":7,"value":8,"toc":271},"minimark",[9,13,18,21,70,76,80,83,90,94,97,134,137,141,152,167,171,188,191,246,253,257,267],[10,11,12],"p",{},"A surprising number of \"help desk\" tickets come from this. The data is\ncorrect, the rule is correct, the UI is rendering in the wrong zone.\nThis page walks the three places where timezones live.",[14,15,17],"h2",{"id":16},"the-three-timezones","The three timezones",[10,19,20],{},"OpenSense's stack has three timezones in play. They are usually\ndifferent.",[22,23,24,37,55],"ol",{},[25,26,27,31,32,36],"li",{},[28,29,30],"strong",{},"Storage TZ."," Always UTC. Every measurement, every event, every\naudit-log row carries ",[33,34,35],"code",{},"ts_utc",". This is what is in the database.",[25,38,39,42,43,46,47,50,51,54],{},[28,40,41],{},"Site TZ."," Set per site (",[33,44,45],{},"Europe\u002FBratislava",", ",[33,48,49],{},"Asia\u002FTokyo",", …).\nUsed by the ",[28,52,53],{},"PDF report"," renderer for day boundaries and labels.",[25,56,57,60,61,64,65,69],{},[28,58,59],{},"Browser TZ."," Used by the ",[28,62,63],{},"dashboard chart"," when rendered in\nyour browser. The chart x-axis labels reflect ",[66,67,68],"em",{},"your"," local clock.",[10,71,72,73,75],{},"This is intentional: an operator in the EU travelling to Tokyo wants\nto see the dashboard in JST, while the inspector at the Bratislava\ncafé gets a PDF in ",[33,74,45],{}," regardless of who issued it.",[14,77,79],{"id":78},"symptom-chart-and-pdf-disagree","Symptom: chart and PDF disagree",[10,81,82],{},"If the dashboard chart shows a +9 °C spike at 14:30 and the PDF shows\nthe same spike at 12:30, that is the storage-TZ → browser-TZ vs\nstorage-TZ → site-TZ difference. The data is the same; the labelling\ndiffers by your offset minus the site offset.",[10,84,85,86,89],{},"This is correct behaviour for travel scenarios but confuses operators\nwho never leave their site. To make them agree, set the dashboard's\n\"display timezone\" to the site's timezone in ",[33,87,88],{},"Account → Preferences → Display timezone",". The chart then matches the PDF.",[14,91,93],{"id":92},"symptom-a-yesterday-report-is-empty","Symptom: a \"yesterday\" report is empty",[10,95,96],{},"If you click \"Yesterday's report\" at 02:00 local time:",[98,99,100,103,114,127],"ul",{},[25,101,102],{},"It is 01:00 UTC.",[25,104,105,106,109,110,113],{},"The report engine asks: \"what measurements fall in ",[33,107,108],{},"2026-05-16 00:00 site-local"," → ",[33,111,112],{},"2026-05-16 24:00 site-local","?\"",[25,115,116,117,119,120,109,123,126],{},"For a site in ",[33,118,45],{}," (UTC+2 in summer), that is\n",[33,121,122],{},"2026-05-15 22:00 UTC",[33,124,125],{},"2026-05-16 22:00 UTC",".",[25,128,129,130,133],{},"You have until 02:00 site-local on the ",[28,131,132],{},"17th"," for \"yesterday the\n16th\" to be a full day.",[10,135,136],{},"Fix: request \"the previous full local day\", or wait until later in\nthe morning. The PDF service refuses to render an incomplete day with\na friendly modal; the API returns an empty (header-only) PDF.",[14,138,140],{"id":139},"symptom-dst-shift-makes-a-thresholdcross-at-the-wrong-hour","Symptom: DST shift makes a thresholdcross at the wrong hour",[10,142,143,144,147,148,151],{},"If a rule has a time-of-day window (",[33,145,146],{},"FREQ=DAILY;BYHOUR=22","), it fires\nat 22:00 in the site's timezone, ",[28,149,150],{},"respecting DST",". On the morning\nafter a spring-forward, the window happens 23 hours after the\nprevious one; on the morning after a fall-back, 25 hours.",[10,153,154,155,158,159,162,163,166],{},"If your rule is for a process that runs on a fixed real-world clock\n(e.g. a thermal-disinfection cycle scheduled by a PLC at 03:00 local\nwithout DST awareness), the rule's window will drift from the\nprocess's actual time twice a year. Fix: use UTC in the rule's\n",[33,156,157],{},"rrule"," (",[33,160,161],{},"TZID=UTC;FREQ=DAILY;BYHOUR=...","), or set the site's\ntimezone to ",[33,164,165],{},"UTC"," (rare).",[14,168,170],{"id":169},"symptom-ts-is-in-the-future","Symptom: \"ts is in the future\"",[10,172,173,174,177,178,180,181,184,185,126],{},"If your device's clock is wrong (no NTP, or NTP misconfigured), it may\nsend ",[33,175,176],{},"ts"," in the future. OpenSense accepts ",[33,179,176],{}," up to ",[28,182,183],{},"30 seconds","\nin the future (clock skew tolerance) and rejects beyond that with\n",[33,186,187],{},"422 ts_in_future",[10,189,190],{},"Fix the device clock. For ESPHome:",[192,193,198],"pre",{"className":194,"code":195,"language":196,"meta":197,"style":197},"language-yaml shiki shiki-themes github-dark github-dark","time:\n  - platform: sntp\n    servers:\n      - pool.ntp.org\n","yaml","",[33,199,200,213,229,237],{"__ignoreMap":197},[201,202,205,209],"span",{"class":203,"line":204},"line",1,[201,206,208],{"class":207},"sxg3X","time",[201,210,212],{"class":211},"suv1-",":\n",[201,214,216,219,222,225],{"class":203,"line":215},2,[201,217,218],{"class":211},"  - ",[201,220,221],{"class":207},"platform",[201,223,224],{"class":211},": ",[201,226,228],{"class":227},"s4wv1","sntp\n",[201,230,232,235],{"class":203,"line":231},3,[201,233,234],{"class":207},"    servers",[201,236,212],{"class":211},[201,238,240,243],{"class":203,"line":239},4,[201,241,242],{"class":211},"      - ",[201,244,245],{"class":227},"pool.ntp.org\n",[10,247,248,249,252],{},"For Shelly, the device gets time from your WiFi router via DHCP option\n42 or from the Shelly cloud. If your router does not advertise an NTP\nserver, configure one in the Shelly's ",[33,250,251],{},"Time"," settings.",[14,254,256],{"id":255},"symptom-the-pdf-labels-show-utc-instead-of-local","Symptom: the PDF labels show UTC instead of local",[10,258,259,260,262,263,266],{},"Your site's timezone field is empty or ",[33,261,165],{},". Set it:\n",[33,264,265],{},"Site → Settings → Timezone → Europe\u002FBratislava"," (or whatever applies).\nRe-issue the report. The cached PDF for the period is invalidated and\nre-rendered with correct labels.",[268,269,270],"style",{},"html pre.shiki code .sxg3X, html code.shiki .sxg3X{--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .suv1-, html code.shiki .suv1-{--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .s4wv1, html code.shiki .s4wv1{--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":197,"searchDepth":231,"depth":231,"links":272},[273,274,275,276,277,278],{"id":16,"depth":215,"text":17},{"id":78,"depth":215,"text":79},{"id":92,"depth":215,"text":93},{"id":139,"depth":215,"text":140},{"id":169,"depth":215,"text":170},{"id":255,"depth":215,"text":256},"Wrong dates on the report or the chart",null,"md",{},true,"\u002Ftroubleshooting\u002Ftimezone-mismatch",{"title":5,"description":279},"troubleshooting\u002Ftimezone-mismatch",470,"3q0MQRqQREDO5ej0egW_wBbl_Adrcj8y-L961_VH8fY",1779022955508]