frontend: show Energy/DSMR/meter times in local timezone, 24h
Backend serializes SQLite-read (naive) UTC datetimes without a Z, so the browser was parsing them as local time -> the UI effectively showed UTC values. - New src/utils/datetime.ts: treats a tz-less timestamp as UTC, then formats in the browser's local timezone with hour12:false (no AM/PM). - Applied to Energy tabs (contracts/prices/costs/DSMR), per-device readings & trends, and the meter readings table on the Records page. - CostView Today/This month now use local day boundaries (queries stay UTC ISO). - Untouched: location/poo (raw Zulu strings), the map, and query-window params. - Tests are timezone-independent (verified under TZ=America/Los_Angeles).
This commit is contained in:
@@ -42,6 +42,7 @@ import {
|
||||
ResponsiveContainer,
|
||||
} from 'recharts'
|
||||
import { useEnergyCosts, useEnergyCostSummary, useRecomputeCosts } from './hooks'
|
||||
import { formatLocalTime } from '../utils/datetime'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Cost limit — prevent accidental full-table pulls
|
||||
@@ -54,17 +55,18 @@ const COSTS_MAX_LIMIT = 500
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function getTodayRange(): { start: string; end: string } {
|
||||
const start = new Date()
|
||||
start.setUTCHours(0, 0, 0, 0)
|
||||
const end = new Date(start)
|
||||
end.setUTCDate(end.getUTCDate() + 1)
|
||||
// Use local date boundary so "today" matches what the user sees in the display.
|
||||
const now = new Date()
|
||||
const start = new Date(now.getFullYear(), now.getMonth(), now.getDate())
|
||||
const end = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1)
|
||||
return { start: start.toISOString(), end: end.toISOString() }
|
||||
}
|
||||
|
||||
function getThisMonthRange(): { start: string; end: string } {
|
||||
// Use local date boundary so "this month" matches what the user sees in the display.
|
||||
const now = new Date()
|
||||
const start = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1))
|
||||
const end = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1))
|
||||
const start = new Date(now.getFullYear(), now.getMonth(), 1)
|
||||
const end = new Date(now.getFullYear(), now.getMonth() + 1, 1)
|
||||
return { start: start.toISOString(), end: end.toISOString() }
|
||||
}
|
||||
|
||||
@@ -261,10 +263,7 @@ export function CostView() {
|
||||
<ResponsiveContainer width="100%" height={220}>
|
||||
<AreaChart
|
||||
data={costsQuery.data.items.map((item) => ({
|
||||
time: new Date(item.period_start).toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
}),
|
||||
time: formatLocalTime(item.period_start),
|
||||
import_cost: item.import_cost,
|
||||
export_revenue: item.export_revenue,
|
||||
net_cost: item.net_cost,
|
||||
@@ -343,10 +342,7 @@ export function CostView() {
|
||||
>
|
||||
<Table.Td>
|
||||
<Text size="xs">
|
||||
{new Date(item.period_start).toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})}
|
||||
{formatLocalTime(item.period_start)}
|
||||
</Text>
|
||||
</Table.Td>
|
||||
<Table.Td>{(item.d1_kwh + item.d2_kwh).toFixed(3)}</Table.Td>
|
||||
|
||||
Reference in New Issue
Block a user