mirror of
https://github.com/esphome/esphome.git
synced 2026-05-10 22:19:21 +08:00
[time] Fix RTC is_valid() rejecting valid times after day_of_year cleanup (#15763)
This commit is contained in:
committed by
Jesse Hills
parent
914ed10bcc
commit
aa80bdbbc6
@@ -63,7 +63,7 @@ void BM8563::read_time() {
|
||||
rtc_time.day_of_week, rtc_time.hour, rtc_time.minute, rtc_time.second);
|
||||
|
||||
rtc_time.recalc_timestamp_utc(false);
|
||||
if (!rtc_time.is_valid()) {
|
||||
if (!rtc_time.is_valid(/*check_day_of_week=*/true, /*check_day_of_year=*/false)) {
|
||||
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ void DS1307Component::read_time() {
|
||||
.year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000),
|
||||
};
|
||||
rtc_time.recalc_timestamp_utc(false);
|
||||
if (!rtc_time.is_valid()) {
|
||||
if (!rtc_time.is_valid(/*check_day_of_week=*/true, /*check_day_of_year=*/false)) {
|
||||
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ void PCF85063Component::read_time() {
|
||||
.year = uint16_t(pcf85063_.reg.year + 10u * pcf85063_.reg.year_10 + 2000),
|
||||
};
|
||||
rtc_time.recalc_timestamp_utc(false);
|
||||
if (!rtc_time.is_valid()) {
|
||||
if (!rtc_time.is_valid(/*check_day_of_week=*/true, /*check_day_of_year=*/false)) {
|
||||
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ void PCF8563Component::read_time() {
|
||||
.year = uint16_t(pcf8563_.reg.year + 10u * pcf8563_.reg.year_10 + 2000),
|
||||
};
|
||||
rtc_time.recalc_timestamp_utc(false);
|
||||
if (!rtc_time.is_valid()) {
|
||||
if (!rtc_time.is_valid(/*check_day_of_week=*/true, /*check_day_of_year=*/false)) {
|
||||
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ void RX8130Component::read_time() {
|
||||
.year = static_cast<uint16_t>(bcd2dec(date[6]) + 2000),
|
||||
};
|
||||
rtc_time.recalc_timestamp_utc(false);
|
||||
if (!rtc_time.is_valid()) {
|
||||
if (!rtc_time.is_valid(/*check_day_of_week=*/true, /*check_day_of_year=*/false)) {
|
||||
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
|
||||
return;
|
||||
}
|
||||
|
||||
+6
-2
@@ -76,8 +76,12 @@ struct ESPTime {
|
||||
/// @copydoc strftime(const std::string &format)
|
||||
std::string strftime(const char *format);
|
||||
|
||||
/// Check if this ESPTime is valid (all fields in range and year is greater than or equal to 2019)
|
||||
bool is_valid() const { return this->year >= 2019 && this->fields_in_range(); }
|
||||
/// Check if this ESPTime is valid (year >= 2019 and the requested fields are in range).
|
||||
/// @param check_day_of_week validate day_of_week (not always available when constructing from date/time fields)
|
||||
/// @param check_day_of_year validate day_of_year (not always available when constructing from date/time fields)
|
||||
bool is_valid(bool check_day_of_week = true, bool check_day_of_year = true) const {
|
||||
return this->year >= 2019 && this->fields_in_range(check_day_of_week, check_day_of_year);
|
||||
}
|
||||
|
||||
/// Check if time fields are in range.
|
||||
/// @param check_day_of_week validate day_of_week (not always available when constructing from date/time fields)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// Regression tests for ESPTime::is_valid() optional checks.
|
||||
//
|
||||
// The RTC components (ds1307, bm8563, pcf85063, pcf8563, rx8130) read date/time
|
||||
// fields from hardware but do not populate day_of_year. They call
|
||||
// recalc_timestamp_utc(false) -- which skips day_of_year -- and then is_valid().
|
||||
// These tests ensure the is_valid() overload can skip day_of_year validation so
|
||||
// RTCs don't log "Invalid RTC time, not syncing to system clock." for valid times.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
namespace esphome::testing {
|
||||
|
||||
// Build an ESPTime that mirrors what the RTC components construct: all fields
|
||||
// populated from hardware except day_of_year (left zero-initialized).
|
||||
static ESPTime make_rtc_like_time() {
|
||||
ESPTime t{};
|
||||
t.second = 30;
|
||||
t.minute = 15;
|
||||
t.hour = 12;
|
||||
t.day_of_week = 4; // thursday
|
||||
t.day_of_month = 15;
|
||||
t.month = 4;
|
||||
t.year = 2026;
|
||||
// day_of_year intentionally left at 0 -- RTCs don't compute it.
|
||||
return t;
|
||||
}
|
||||
|
||||
TEST(ESPTimeIsValid, DefaultRejectsZeroDayOfYear) {
|
||||
// Default is_valid() checks day_of_year; zero-init is out of range.
|
||||
ESPTime t = make_rtc_like_time();
|
||||
EXPECT_FALSE(t.is_valid());
|
||||
}
|
||||
|
||||
TEST(ESPTimeIsValid, SkipDayOfYearAcceptsRTCLikeTime) {
|
||||
// RTC code path: skip day_of_year validation.
|
||||
ESPTime t = make_rtc_like_time();
|
||||
EXPECT_TRUE(t.is_valid(/*check_day_of_week=*/true, /*check_day_of_year=*/false));
|
||||
}
|
||||
|
||||
TEST(ESPTimeIsValid, SkipDayOfYearStillRejectsOutOfRangeFields) {
|
||||
ESPTime t = make_rtc_like_time();
|
||||
t.hour = 25;
|
||||
EXPECT_FALSE(t.is_valid(/*check_day_of_week=*/true, /*check_day_of_year=*/false));
|
||||
}
|
||||
|
||||
TEST(ESPTimeIsValid, SkipDayOfYearStillRejectsYearBefore2019) {
|
||||
ESPTime t = make_rtc_like_time();
|
||||
t.year = 2000;
|
||||
EXPECT_FALSE(t.is_valid(/*check_day_of_week=*/true, /*check_day_of_year=*/false));
|
||||
}
|
||||
|
||||
TEST(ESPTimeIsValid, SkipBothDayChecksAcceptsGPSLikeTime) {
|
||||
// GPS path (gps_time.cpp) populates neither day_of_week nor day_of_year.
|
||||
ESPTime t{};
|
||||
t.second = 30;
|
||||
t.minute = 15;
|
||||
t.hour = 12;
|
||||
t.day_of_month = 15;
|
||||
t.month = 4;
|
||||
t.year = 2026;
|
||||
EXPECT_TRUE(t.is_valid(/*check_day_of_week=*/false, /*check_day_of_year=*/false));
|
||||
EXPECT_FALSE(t.is_valid()); // default still rejects
|
||||
}
|
||||
|
||||
TEST(ESPTimeIsValid, FullyPopulatedAcceptsWithDefaults) {
|
||||
ESPTime t = make_rtc_like_time();
|
||||
t.day_of_year = 105;
|
||||
EXPECT_TRUE(t.is_valid());
|
||||
}
|
||||
|
||||
} // namespace esphome::testing
|
||||
Reference in New Issue
Block a user