187 files

This commit is contained in:
Home Assistant Version Control
2026-10-09 11:57:31 +00:00
parent 28fa34d78a
commit 1e1b12d52b
187 changed files with 40899 additions and 32654 deletions
+22 -40
View File
@@ -38,6 +38,21 @@ import homeassistant.util.dt as dt_util
_LOGGER = logging.getLogger(__name__)
def utc_now() -> datetime:
"""Return the current time as an aware UTC datetime, for interval arithmetic.
Two aware datetimes that share one tzinfo instance are subtracted on their
wall-clock fields, and every ``dt_util.now()`` stamp shares HA's ZoneInfo, so
``now() - earlier_now()`` is an hour wrong across a DST change (audit
DETECT-01). Use this for anything that is subtracted, compared or stored to
be subtracted later; keep ``dt_util.now()`` only where the LOCAL clock is the
point (quiet hours, "finished at 14:05"). It reads ``dt_util.now()`` rather
than ``dt_util.utcnow()`` so tests that freeze ``dt_util.now`` keep
controlling the clock.
"""
return dt_util.as_utc(dt_util.now())
# Type aliases
PowerPoint = list[Any] | tuple[Any, ...]
PowerData = list[PowerPoint]
@@ -103,7 +118,7 @@ def power_data_to_offsets(
parsed_start = dt_util.parse_datetime(start_time_iso)
if parsed_start is not None:
base_ts = parsed_start.timestamp()
except (ValueError, OSError) as e:
except (ValueError, OSError, OverflowError) as e:
_LOGGER.debug("Failed to parse start_time_iso %s: %s", start_time_iso, e)
result: list[list[float]] = []
for item in power_data:
@@ -114,7 +129,7 @@ def power_data_to_offsets(
base_ts = ts_abs # use first reading as anchor
offset = round(ts_abs - base_ts, 1)
result.append([max(0.0, offset), p])
except (TypeError, ValueError, IndexError):
except (TypeError, ValueError, IndexError, OverflowError):
continue
return result
@@ -124,7 +139,7 @@ def power_data_to_offsets(
for item in power_data:
try:
result.append([float(item[0]), float(item[1])])
except (TypeError, ValueError, IndexError):
except (TypeError, ValueError, IndexError, OverflowError):
continue
return result
@@ -135,7 +150,7 @@ def power_data_to_offsets(
parsed_start = dt_util.parse_datetime(start_time_iso)
if parsed_start is not None:
start_ts = parsed_start.timestamp()
except (ValueError, OSError) as e:
except (ValueError, OSError, OverflowError) as e:
_LOGGER.debug("Failed to parse datetime %s: %s", start_time_iso, e)
result: list[list[float]] = []
for item in power_data:
@@ -148,7 +163,7 @@ def power_data_to_offsets(
if start_ts is None:
start_ts = ts.timestamp()
result.append([round(ts.timestamp() - start_ts, 1), p])
except (TypeError, ValueError, AttributeError, IndexError):
except (TypeError, ValueError, AttributeError, IndexError, OverflowError):
continue
return result
@@ -161,7 +176,7 @@ def power_data_to_offsets(
if parsed is None:
return []
base_ts = parsed.timestamp()
except (ValueError, OSError) as e:
except (ValueError, OSError, OverflowError) as e:
_LOGGER.debug("Failed to parse datetime %s: %s", start_time_iso, e)
return []
@@ -198,7 +213,7 @@ def power_data_to_offsets(
offset, p, len(result),
)
result.append([max(0.0, offset), p])
except (TypeError, ValueError, AttributeError, IndexError):
except (TypeError, ValueError, AttributeError, IndexError, OverflowError):
continue
return result
@@ -206,39 +221,6 @@ def power_data_to_offsets(
return []
def power_data_offsets_to_datetimes(
power_data: PowerData,
start_time_iso: str,
) -> list[tuple[datetime, float]]:
"""Convert stored ``[[offset_sec, power], ...]`` to ``[(datetime, power), ...]``.
Args:
power_data: Offset-format power data.
start_time_iso: ISO-8601 cycle start time.
Returns:
List of ``(datetime, power)`` tuples. Empty list on failure.
"""
try:
start_dt = dt_util.parse_datetime(start_time_iso)
if start_dt is None:
return []
start_ts = start_dt.timestamp()
except Exception: # pylint: disable=broad-exception-caught
return []
result: list[tuple[datetime, float]] = []
for item in power_data:
try:
offset = float(item[0])
p = float(item[1])
ts = datetime.fromtimestamp(start_ts + offset, tz=start_dt.tzinfo)
result.append((ts, p))
except (TypeError, ValueError, IndexError):
continue
return result
def migrate_power_data_to_offsets(cycle: dict[str, Any]) -> bool:
"""Migrate a single cycle's power_data to offset format in-place.