From 51a228d203d0b2022e02762b80ed8aa4b5d4bb75 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Sat, 2 May 2026 06:49:43 -0500 Subject: [PATCH] respect ui.timezone when generating fallback export names --- frigate/record/export.py | 15 ++++++++++++++- frigate/test/test_export_progress.py | 27 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/frigate/record/export.py b/frigate/record/export.py index e06b8f68d..a2ed87c65 100644 --- a/frigate/record/export.py +++ b/frigate/record/export.py @@ -13,6 +13,7 @@ from enum import Enum from pathlib import Path from typing import Callable, Optional +import pytz from peewee import DoesNotExist from frigate.config import FfmpegConfig, FrigateConfig @@ -344,7 +345,19 @@ class RecordingExporter(threading.Thread): return proc.returncode, "".join(captured) def get_datetime_from_timestamp(self, timestamp: int) -> str: - # return in iso format + # return in iso format using the configured ui.timezone when set, + # so the auto-generated export name reflects local time rather + # than the container's UTC clock + tz_name = self.config.ui.timezone + if tz_name: + try: + tz = pytz.timezone(tz_name) + except pytz.UnknownTimeZoneError: + tz = None + if tz is not None: + return datetime.datetime.fromtimestamp(timestamp, tz=tz).strftime( + "%Y-%m-%d %H:%M:%S" + ) return datetime.datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S") def _chapter_metadata_path(self) -> str: diff --git a/frigate/test/test_export_progress.py b/frigate/test/test_export_progress.py index 616a63503..1c61aff35 100644 --- a/frigate/test/test_export_progress.py +++ b/frigate/test/test_export_progress.py @@ -363,6 +363,33 @@ class TestBroadcastAggregation(unittest.TestCase): assert job.progress_percent == 33.0 +class TestGetDatetimeFromTimestamp(unittest.TestCase): + """Auto-generated export name should honor config.ui.timezone, not + fall back to the container's UTC clock when a timezone is configured. + """ + + def test_uses_configured_ui_timezone(self) -> None: + exporter = _make_exporter() + exporter.config.ui.timezone = "America/New_York" + # 2025-01-15 12:00:00 UTC is 07:00:00 EST + assert ( + exporter.get_datetime_from_timestamp(1736942400) + == "2025-01-15 07:00:00" + ) + + def test_falls_back_to_local_when_timezone_unset(self) -> None: + exporter = _make_exporter() + exporter.config.ui.timezone = None + # No assertion on the exact wall-clock value — just confirm no + # exception and that pytz isn't required when the field is unset. + assert isinstance(exporter.get_datetime_from_timestamp(1736942400), str) + + def test_invalid_timezone_falls_back_to_local(self) -> None: + exporter = _make_exporter() + exporter.config.ui.timezone = "Not/A_Real_Zone" + assert isinstance(exporter.get_datetime_from_timestamp(1736942400), str) + + class TestSchedulesCleanup(unittest.TestCase): def test_schedule_job_cleanup_removes_after_delay(self) -> None: config = MagicMock()