mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-30 00:27:11 +09:00
SystemService.get_server_time fell through to Python's time.tzname on hosts without /etc/timezone or timedatectl (e.g. Windows dev), yielding a display name like "Eastern Daylight Time" — not a valid IANA/Intl key. The dashboard MetricsGraph then crashed with RangeError: Invalid time zone specified. - Backend: add a cross-platform tzlocal fallback + an IANA-validity guard so timezone_id is always an IANA key or null (display name stays in timezone_name). Declare tzlocal in requirements. - Frontend: MetricsGraph validates the zone and falls back to local time instead of throwing (defense in depth). - Test: test_server_time_timezone.py. ServerKit's timezone feature (get/list/set via /api/v1/system/timezone) is unchanged — this only fixes the value reported on non-Linux hosts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
36 lines
1.5 KiB
Python
36 lines
1.5 KiB
Python
"""SystemService.get_server_time must only ever expose an IANA timezone_id.
|
|
|
|
Regression for a Windows-dev crash: Python's time.tzname yields a platform
|
|
*display* name ("Eastern Daylight Time") which is not a valid IANA/Intl zone key
|
|
and crashed the panel's time-formatting. timezone_id must be IANA-or-null; the
|
|
human display name lives in timezone_name.
|
|
"""
|
|
from app.services.system_service import SystemService
|
|
|
|
|
|
def test_is_iana_timezone():
|
|
assert SystemService._is_iana_timezone('America/New_York') is True
|
|
assert SystemService._is_iana_timezone('Europe/London') is True
|
|
assert SystemService._is_iana_timezone('UTC') is True
|
|
# Windows display names are rejected.
|
|
assert SystemService._is_iana_timezone('Eastern Daylight Time') is False
|
|
assert SystemService._is_iana_timezone('Pacific Standard Time') is False
|
|
assert SystemService._is_iana_timezone('') is False
|
|
assert SystemService._is_iana_timezone(None) is False
|
|
|
|
|
|
def test_get_server_time_timezone_id_is_iana_or_null():
|
|
t = SystemService.get_server_time()
|
|
tzid = t.get('timezone_id')
|
|
# Never a spaced display name; either a real IANA key or null.
|
|
assert tzid is None or SystemService._is_iana_timezone(tzid), tzid
|
|
# The display name is still available separately for the UI clock.
|
|
assert 'timezone_name' in t
|
|
|
|
|
|
def test_get_server_time_shape(app):
|
|
t = SystemService.get_server_time()
|
|
for key in ('current_time', 'current_time_formatted', 'utc_time',
|
|
'timezone_name', 'timezone_id', 'utc_offset'):
|
|
assert key in t
|