Fix plan web UI using browser timezone instead of Predbat's configured timezone#3626
Conversation
…tead of browser's Co-authored-by: springfall2008 <48591903+springfall2008@users.noreply.github.com> Agent-Logs-Url: https://github.com/springfall2008/batpred/sessions/08b1f3bd-45c3-4ec8-a9db-845272807ec4
There was a problem hiding this comment.
Pull request overview
This PR fixes a timezone mismatch in the Plan Web UI where clicking a plan slot could send a browser-local time string to the backend, causing overrides to be applied to the wrong Predbat slot when the viewer is in a different timezone. The update makes the client render/derive times using the UTC offset embedded in the plan’s ISO timestamps (i.e., Predbat’s configured timezone), independent of the browser locale.
Changes:
- Added a client-side helper to extract
±HHMM/±HH:MMoffsets from ISO timestamps. - Updated plan time rendering (
formatTimeDisplay) to use the embedded offset + UTC accessors. - Updated “Updated: …” timestamp formatting and the
getMinutesFromTimeString()fallback to be offset-aware.
| const match = isoTimestamp.match(/([+-])(\d{2}):?(\d{2})$/); | ||
| if (!match) return 0; | ||
| const sign = match[1] === '+' ? 1 : -1; | ||
| return sign * (parseInt(match[2]) * 60 + parseInt(match[3])); |
There was a problem hiding this comment.
In getTimezoneOffsetMinutes, consider handling falsy / non-string inputs (e.g., null/undefined) before calling .match() to avoid a runtime error if the function is ever called with missing data. Also, pass a radix (10) to parseInt to make the intent explicit and avoid any edge-case parsing differences.
| const match = isoTimestamp.match(/([+-])(\d{2}):?(\d{2})$/); | |
| if (!match) return 0; | |
| const sign = match[1] === '+' ? 1 : -1; | |
| return sign * (parseInt(match[2]) * 60 + parseInt(match[3])); | |
| if (!isoTimestamp || typeof isoTimestamp !== 'string') { | |
| return 0; | |
| } | |
| const match = isoTimestamp.match(/([+-])(\d{2}):?(\d{2})$/); | |
| if (!match) return 0; | |
| const sign = match[1] === '+' ? 1 : -1; | |
| const hours = parseInt(match[2], 10); | |
| const minutes = parseInt(match[3], 10); | |
| if (Number.isNaN(hours) || Number.isNaN(minutes)) { | |
| return 0; | |
| } | |
| return sign * (hours * 60 + minutes); |
When accessing the Predbat plan web UI from a device in a different timezone (e.g., iPhone in the US via Nabu Casa), clicking a time slot to set an override sent a time string formatted in the browser's local timezone to the server, which interpreted it in Predbat's configured timezone — causing overrides to land in the wrong slot.
Root cause
formatTimeDisplay()inweb_helper.pyused browser-localDatemethods (getDay(),getHours(),getMinutes()) to format the ISO timestamps from the plan JSON. The resulting string (e.g.,"Mon 00:30"instead of"Mon 05:30") was POSTed to the server and interpreted as Predbat local time.The plan JSON timestamps already carry the correct Predbat timezone offset (e.g.,
2024-11-25T05:30:00+0000), so the fix can be self-contained in the client.Changes
getTimezoneOffsetMinutes(isoTimestamp)— extracts the UTC offset in minutes from the ISO string, handling both+HHMM(strftime) and+HH:MM(isoformat()) variantsformatTimeDisplay()— now applies the extracted offset to UTC time and reads viagetUTC*()methods, producing the correct Predbat-timezone display regardless of browser localeformatTimestamp()— same fix for the "Updated: …" header timestamp (display consistency)getMinutesFromTimeString()fallback — replaced the browser-localgetHours()/getMinutes()fallback with the offset-aware equivalentWarning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
api.octopus.energy/home/REDACTED/work/batpred/batpred/coverage/venv/bin/python3 python3 ../apps/predbat/unit_test.py --quick(dns block)gitlab.com/usr/lib/git-core/git-remote-https /usr/lib/git-core/git-remote-https origin REDACTED(dns block)https://api.github.com/repos/springfall2008/batpred/contents/apps/predbat/home/REDACTED/work/batpred/batpred/coverage/venv/bin/python3 python3 ../apps/predbat/unit_test.py --quick(http block)/home/REDACTED/work/batpred/batpred/coverage/venv/bin/python3 python3 ../apps/predbat/unit_test.py --quick --test web_if(http block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.