Document the manual, admin-set application timezone (task e9aa78f3)

Add an "Application timezone" section to docs/ARCHITECTURE.md: the
timezone is set only by an admin from the admin app (GET/PATCH
/api/v1/admin/settings), is the single source of local time for the
panel, completions, the missed-sweep scheduler and the admin app, means
the API host's local zone while empty (published as the effective zone),
and an admin save of timezone or day_rollover_time re-plans the sweep.

Correct docstrings and comments that still described the local date as
Home Assistant's ("HA-local", read from hass.config.time_zone by the
integration) or the stored zone as reported from Home Assistant.
Comment and docstring changes only; no behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 10:38:32 -04:00
co-authored by Claude Opus 5.5
parent 0e726ac64f
commit 47966af6aa
15 changed files with 105 additions and 69 deletions
+2 -2
View File
@@ -1017,8 +1017,8 @@ def make_hass() -> tuple:
hass.bus = EventBus()
hass.http = HttpRegistry()
hass.extra_js_urls: list[str] = []
# A valid IANA time zone (the day-rollover listener reads it to
# compute "today" in HA local time).
# A valid IANA time zone for the fake Home Assistant config (the
# NestQuest application timezone is the admin-set setting, not this).
hass.config.time_zone = "UTC"
# The minimal entity registry: entities self-register through
+1 -1
View File
@@ -834,7 +834,7 @@ def test_complete_instance_no_due_time_after_due_date_is_late(
def test_complete_instance_ha_local_wall_clock_not_utc(tmp_path) -> None:
"""HA-local 11:00 with due_time 12:00 is on time even when UTC is 19:00.
"""Household-local 11:00, due 12:00, is on time even when UTC is 19:00.
The helper's zone is UTC-8, so 11:00 local is 19:00 UTC. Converting
to UTC before comparing would mark this late.
+1 -1
View File
@@ -136,7 +136,7 @@ async def test_build_snapshot_explicit_values(hass, make_entry, tmp_path) -> Non
# Single clock read for the seed/snapshot anchor (no midnight skew);
# the coordinator no longer owns a clock read (the API serves the
# snapshot), so the test resolves the HA-local zone directly.
# snapshot), so the test resolves its own local zone directly.
time_zone = ZoneInfo(hass.config.time_zone)
today = datetime.datetime.now(time_zone).date()
# Pin the build instant at 12:00 local: past Ada's 10:00 due time
+9 -8
View File
@@ -940,14 +940,15 @@ def test_materialize_rejects_malformed_or_inverted_bounds(tmp_path) -> None:
def test_materialize_accepts_ha_local_today_behind_host(tmp_path) -> None:
"""The clamp and no-past guard compare against a caller-supplied HA-local today.
"""The clamp and no-past guard compare against a caller-supplied today.
A household time zone behind the host clock around midnight resolves a
HA-local "today" one calendar day earlier than the host's
household-local "today" one calendar day earlier than the host's
``date.today()``. The walk clamps its start to that anchor: without
a pinned HA-local date the effective start is the host's today (one
day after ha_today), so the now-past day is skipped rather than
rejected, and only the host-today-onward days materialize.
a pinned household-local date the effective start is the host's
today (one day after ha_today), so the now-past day is skipped
rather than rejected, and only the host-today-onward days
materialize.
"""
async def _body(database):
children = ChildrenDao(database)
@@ -963,9 +964,9 @@ def test_materialize_accepts_ha_local_today_behind_host(tmp_path) -> None:
["morning"],
)
# Without a pinned HA-local today, the walk clamps its start to the
# host's today (one day after ha_today); the past day is dropped and
# the 14 host-today-onward days materialize.
# Without a pinned household-local today, the walk clamps its start
# to the host's today (one day after ha_today); the past day is
# dropped and the 14 host-today-onward days materialize.
without_pin = await materialize(database, start_iso, end_iso)
assert without_pin == 14