From 09e9b58eb64a14a62bd03b4777d943af3064f747 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 15 Dec 2025 16:38:44 +0000 Subject: [PATCH] Change build_time_str format to ISO 8601 with timezone Use YYYY-MM-DD HH:MM:SS +ZZZZ format instead of the locale-dependent '%b %d %Y, %H:%M:%S' format. This provides: - Unambiguous date format (YYYY-MM-DD) - Timezone information - Locale-independent formatting - Better sortability and parseability Example: "2025-12-15 16:30:27 +0000" instead of "Dec 15 2025, 16:30:27" Tests validate the format using strptime with '%Y-%m-%d %H:%M:%S %z'. --- esphome/writer.py | 2 +- tests/integration/test_build_info.py | 11 ++++++----- tests/unit_tests/test_writer.py | 17 +++++++++-------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/esphome/writer.py b/esphome/writer.py index a2cc0dc446d..183fff8730f 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -340,7 +340,7 @@ def get_build_info() -> tuple[int, int, str]: """ config_hash = CORE.config_hash build_time = int(time.time()) - build_time_str = time.strftime("%b %d %Y, %H:%M:%S", time.localtime(build_time)) + build_time_str = time.strftime("%Y-%m-%d %H:%M:%S %z", time.localtime(build_time)) return config_hash, build_time, build_time_str diff --git a/tests/integration/test_build_info.py b/tests/integration/test_build_info.py index 3c3a89b3abe..c1c655c664b 100644 --- a/tests/integration/test_build_info.py +++ b/tests/integration/test_build_info.py @@ -30,8 +30,8 @@ async def test_build_info( compilation_time = device_info.compilation_time assert compilation_time is not None - # Parse the date string - raises ValueError if format is wrong - parsed = datetime.strptime(compilation_time, "%b %d %Y, %H:%M:%S") + # Validate the ISO format: "YYYY-MM-DD HH:MM:SS +ZZZZ" + parsed = datetime.strptime(compilation_time, "%Y-%m-%d %H:%M:%S %z") assert parsed.year >= time.localtime().tm_year # Get entities @@ -98,13 +98,14 @@ async def test_build_info( f"build_time {build_time} should be within the last hour" ) - # Validate build_time_str matches the same format as compilation_time + # Validate build_time_str matches the new ISO format build_time_str = build_time_str_state.state - parsed_build_time = datetime.strptime(build_time_str, "%b %d %Y, %H:%M:%S") + # Format: "YYYY-MM-DD HH:MM:SS +ZZZZ" + parsed_build_time = datetime.strptime(build_time_str, "%Y-%m-%d %H:%M:%S %z") assert parsed_build_time.year >= time.localtime().tm_year # Verify build_time_str matches what we get from build_time timestamp - expected_str = time.strftime("%b %d %Y, %H:%M:%S", time.localtime(build_time)) + expected_str = time.strftime("%Y-%m-%d %H:%M:%S %z", time.localtime(build_time)) assert build_time_str == expected_str, ( f"build_time_str '{build_time_str}' should match timestamp '{expected_str}'" ) diff --git a/tests/unit_tests/test_writer.py b/tests/unit_tests/test_writer.py index d74919dc3ee..858101026e2 100644 --- a/tests/unit_tests/test_writer.py +++ b/tests/unit_tests/test_writer.py @@ -1194,7 +1194,7 @@ def test_get_build_info_new_build( assert build_time > 0 assert isinstance(build_time_str, str) # Verify build_time_str format matches expected pattern - assert len(build_time_str) > 10 # e.g., "Dec 13 2025, 12:00:00" + assert len(build_time_str) >= 19 # e.g., "2025-12-15 16:27:44 +0000" @patch("esphome.writer.CORE") @@ -1209,7 +1209,7 @@ def test_get_build_info_always_returns_current_time( # Create existing build_info.json with matching config_hash and version existing_build_time = 1700000000 - existing_build_time_str = "Nov 14 2023, 22:13:20" + existing_build_time_str = "2023-11-14 22:13:20 +0000" build_info_path.write_text( json.dumps( { @@ -1248,7 +1248,7 @@ def test_get_build_info_config_changed( { "config_hash": 0x12345678, # Different "build_time": existing_build_time, - "build_time_str": "Nov 14 2023, 22:13:20", + "build_time_str": "2023-11-14 22:13:20 +0000", "esphome_version": "2025.1.0-dev", } ) @@ -1279,7 +1279,7 @@ def test_get_build_info_version_changed( { "config_hash": 0x12345678, "build_time": existing_build_time, - "build_time_str": "Nov 14 2023, 22:13:20", + "build_time_str": "2023-11-14 22:13:20 +0000", "esphome_version": "2024.12.0", # Old version } ) @@ -1346,8 +1346,9 @@ def test_get_build_info_build_time_str_format( config_hash, build_time, build_time_str = get_build_info() - # Verify the format matches "%b %d %Y, %H:%M:%S" (e.g., "Dec 13 2025, 14:30:45") - parsed = datetime.strptime(build_time_str, "%b %d %Y, %H:%M:%S") + # Verify the format matches "%Y-%m-%d %H:%M:%S %z" + # e.g., "2025-12-15 16:27:44 +0000" + parsed = datetime.strptime(build_time_str, "%Y-%m-%d %H:%M:%S %z") assert parsed.year >= 2024 @@ -1355,14 +1356,14 @@ def test_generate_build_info_data_h_format() -> None: """Test generate_build_info_data_h produces correct header content.""" config_hash = 0x12345678 build_time = 1700000000 - build_time_str = "Nov 14 2023, 22:13:20" + build_time_str = "2023-11-14 22:13:20 +0000" result = generate_build_info_data_h(config_hash, build_time, build_time_str) assert "#pragma once" in result assert "#define ESPHOME_CONFIG_HASH 0x12345678U" in result assert "#define ESPHOME_BUILD_TIME 1700000000" in result - assert 'ESPHOME_BUILD_TIME_STR[] = "Nov 14 2023, 22:13:20"' in result + assert 'ESPHOME_BUILD_TIME_STR[] = "2023-11-14 22:13:20 +0000"' in result def test_generate_build_info_data_h_esp8266_progmem() -> None: