From a91a5766545a1f813cb849c551fdb8e61816df38 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 18 Jun 2026 16:27:15 -0500 Subject: [PATCH] merge --- esphome/components/time/real_time_clock.cpp | 31 +++++++++++++++++++++ esphome/components/time/real_time_clock.h | 28 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/esphome/components/time/real_time_clock.cpp b/esphome/components/time/real_time_clock.cpp index 894e7aed52..4e623942ac 100644 --- a/esphome/components/time/real_time_clock.cpp +++ b/esphome/components/time/real_time_clock.cpp @@ -107,4 +107,35 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) { this->time_sync_callback_.call(); } +#ifdef USE_TIME_TIMEZONE +void RealTimeClock::apply_timezone_(const char *tz) { + ParsedTimezone parsed{}; + + // Handle null or empty input - use UTC + if (tz == nullptr || *tz == '\0') { + // Skip if already UTC + if (!get_global_tz().has_dst() && get_global_tz().std_offset_seconds == 0) { + return; + } + set_global_tz(parsed); + return; + } + +#ifdef USE_HOST + // On host platform, also set TZ environment variable for libc compatibility + setenv("TZ", tz, 1); + tzset(); +#endif + + // Parse the POSIX TZ string using our custom parser + if (!parse_posix_tz(tz, parsed)) { + ESP_LOGW(TAG, "Failed to parse timezone: %s", tz); + return; + } + + // Set global timezone for all time conversions + set_global_tz(parsed); +} +#endif + } // namespace esphome::time diff --git a/esphome/components/time/real_time_clock.h b/esphome/components/time/real_time_clock.h index 931cd1e946..06ee2ea5af 100644 --- a/esphome/components/time/real_time_clock.h +++ b/esphome/components/time/real_time_clock.h @@ -22,6 +22,30 @@ class RealTimeClock : public PollingComponent { public: explicit RealTimeClock(); +#ifdef USE_TIME_TIMEZONE + /// Set the time zone from a POSIX TZ string. + void set_timezone(const char *tz) { this->apply_timezone_(tz); } + + /// Set the time zone from a character buffer with known length. + /// The buffer does not need to be null-terminated. + void set_timezone(const char *tz, size_t len) { + if (tz == nullptr) { + this->apply_timezone_(nullptr); + return; + } + // Stack buffer - TZ strings from tzdata are typically short (< 50 chars) + char buf[128]; + if (len >= sizeof(buf)) + len = sizeof(buf) - 1; + memcpy(buf, tz, len); + buf[len] = '\0'; + this->apply_timezone_(buf); + } + + /// Set the time zone from a std::string. + void set_timezone(const std::string &tz) { this->apply_timezone_(tz.c_str()); } +#endif + /// Get the time in the currently defined timezone. ESPTime now(); @@ -41,6 +65,10 @@ class RealTimeClock : public PollingComponent { /// Report a unix epoch as current time. void synchronize_epoch_(uint32_t epoch); +#ifdef USE_TIME_TIMEZONE + void apply_timezone_(const char *tz); +#endif + LazyCallbackManager time_sync_callback_; };