diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index b2f1493e2c..e3db2e3e8d 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -275,7 +275,7 @@ void ESPTime::recalc_timestamp_local() { } // Try both interpretations to match libc mktime() with tm_isdst=-1 - // For ambiguous times (fall-back repeated hour), libc prefers DST + // For ambiguous times (fall-back repeated hour), prefer standard time // For invalid times (spring-forward skipped hour), libc normalizes forward time_t utc_if_dst = this->timestamp + tz.dst_offset_seconds; time_t utc_if_std = this->timestamp + tz.std_offset_seconds; @@ -284,8 +284,8 @@ void ESPTime::recalc_timestamp_local() { bool std_valid = !time::is_in_dst(utc_if_std, tz); if (dst_valid && std_valid) { - // Ambiguous time (repeated hour during fall-back) - prefer DST to match libc - this->timestamp = utc_if_dst; + // Ambiguous time (repeated hour during fall-back) - prefer standard time + this->timestamp = utc_if_std; } else if (dst_valid) { // Only DST interpretation is valid this->timestamp = utc_if_dst; diff --git a/tests/components/time/posix_tz_parser.cpp b/tests/components/time/posix_tz_parser.cpp index d491597e7d..6a1ca016cf 100644 --- a/tests/components/time/posix_tz_parser.cpp +++ b/tests/components/time/posix_tz_parser.cpp @@ -1098,10 +1098,11 @@ TEST(RecalcTimestampLocal, FallBackRepeatedHour) { EXPECT_EQ(esp_result, libc_result); // Test the repeated hour (1:30 AM occurs twice) - // Both implementations should resolve this the same way (typically standard time) - libc_result = libc_mktime(2026, 11, 1, 1, 30, 0); + // libc behavior varies by platform for this edge case, so we verify our + // consistent behavior: prefer standard time (later UTC timestamp) esp_result = esptime_recalc_local(2026, 11, 1, 1, 30, 0); - EXPECT_EQ(esp_result, libc_result); + time_t std_interpretation = esptime_recalc_local(2026, 11, 1, 2, 30, 0) - 3600; // 2:30 CST - 1 hour + EXPECT_EQ(esp_result, std_interpretation); } TEST(RecalcTimestampLocal, SouthernHemisphereDST) {