mirror of
https://github.com/esphome/esphome.git
synced 2026-05-30 15:28:34 +08:00
no setz
This commit is contained in:
@@ -3,6 +3,13 @@
|
|||||||
|
|
||||||
namespace esphome::time {
|
namespace esphome::time {
|
||||||
|
|
||||||
|
// Global timezone for ESPTime::from_epoch_local() to use
|
||||||
|
static ParsedTimezone global_tz_{};
|
||||||
|
|
||||||
|
void set_global_tz(const ParsedTimezone &tz) { global_tz_ = tz; }
|
||||||
|
|
||||||
|
const ParsedTimezone &get_global_tz() { return global_tz_; }
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// Helper to parse an unsigned integer from string, updating pointer
|
// Helper to parse an unsigned integer from string, updating pointer
|
||||||
|
|||||||
@@ -53,6 +53,14 @@ bool parse_posix_tz(const char *tz_string, ParsedTimezone &result);
|
|||||||
/// @return true on success
|
/// @return true on success
|
||||||
bool epoch_to_local_tm(time_t utc_epoch, const ParsedTimezone &tz, struct tm *out_tm);
|
bool epoch_to_local_tm(time_t utc_epoch, const ParsedTimezone &tz, struct tm *out_tm);
|
||||||
|
|
||||||
|
/// Set the global timezone used by epoch_to_local_tm() when called without a timezone.
|
||||||
|
/// This is called by RealTimeClock::apply_timezone_() to enable ESPTime::from_epoch_local()
|
||||||
|
/// to work without libc's localtime().
|
||||||
|
void set_global_tz(const ParsedTimezone &tz);
|
||||||
|
|
||||||
|
/// Get the global timezone.
|
||||||
|
const ParsedTimezone &get_global_tz();
|
||||||
|
|
||||||
// Internal helper functions exposed for testing
|
// Internal helper functions exposed for testing
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|||||||
@@ -25,17 +25,16 @@ RealTimeClock::RealTimeClock() = default;
|
|||||||
|
|
||||||
void RealTimeClock::dump_config() {
|
void RealTimeClock::dump_config() {
|
||||||
#ifdef USE_TIME_TIMEZONE
|
#ifdef USE_TIME_TIMEZONE
|
||||||
int std_hours = -this->parsed_tz_.std_offset_seconds / 3600;
|
const auto &tz = get_global_tz();
|
||||||
int std_mins = abs(this->parsed_tz_.std_offset_seconds % 3600) / 60;
|
int std_hours = -tz.std_offset_seconds / 3600;
|
||||||
|
int std_mins = abs(tz.std_offset_seconds % 3600) / 60;
|
||||||
ESP_LOGCONFIG(TAG, "Timezone: UTC%+d:%02d", std_hours, std_mins);
|
ESP_LOGCONFIG(TAG, "Timezone: UTC%+d:%02d", std_hours, std_mins);
|
||||||
if (this->parsed_tz_.has_dst) {
|
if (tz.has_dst) {
|
||||||
int dst_hours = -this->parsed_tz_.dst_offset_seconds / 3600;
|
int dst_hours = -tz.dst_offset_seconds / 3600;
|
||||||
// Always use M format - tzdata and aioesphomeapi only generate M format rules
|
// Always use M format - tzdata and aioesphomeapi only generate M format rules
|
||||||
ESP_LOGCONFIG(TAG, " DST: UTC%+d, M%d.%d.%d/%" PRId32 " - M%d.%d.%d/%" PRId32, dst_hours,
|
ESP_LOGCONFIG(TAG, " DST: UTC%+d, M%d.%d.%d/%" PRId32 " - M%d.%d.%d/%" PRId32, dst_hours, tz.dst_start.month,
|
||||||
this->parsed_tz_.dst_start.month, this->parsed_tz_.dst_start.week,
|
tz.dst_start.week, tz.dst_start.day_of_week, tz.dst_start.time_seconds / 3600, tz.dst_end.month,
|
||||||
this->parsed_tz_.dst_start.day_of_week, this->parsed_tz_.dst_start.time_seconds / 3600,
|
tz.dst_end.week, tz.dst_end.day_of_week, tz.dst_end.time_seconds / 3600);
|
||||||
this->parsed_tz_.dst_end.month, this->parsed_tz_.dst_end.week, this->parsed_tz_.dst_end.day_of_week,
|
|
||||||
this->parsed_tz_.dst_end.time_seconds / 3600);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
auto time = this->now();
|
auto time = this->now();
|
||||||
@@ -96,24 +95,23 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) {
|
|||||||
|
|
||||||
#ifdef USE_TIME_TIMEZONE
|
#ifdef USE_TIME_TIMEZONE
|
||||||
void RealTimeClock::apply_timezone_(const char *tz) {
|
void RealTimeClock::apply_timezone_(const char *tz) {
|
||||||
|
ParsedTimezone parsed{};
|
||||||
|
|
||||||
// Handle null input
|
// Handle null input
|
||||||
if (tz == nullptr) {
|
if (tz == nullptr) {
|
||||||
ESP_LOGW(TAG, "Failed to parse timezone: (null)");
|
ESP_LOGW(TAG, "Failed to parse timezone: (null)");
|
||||||
this->parsed_tz_ = ParsedTimezone{};
|
set_global_tz(parsed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set TZ env var for components using libc's localtime() directly
|
// Parse the POSIX TZ string using our custom parser
|
||||||
// (e.g., sun, datetime, wireguard, deep_sleep)
|
if (!parse_posix_tz(tz, parsed)) {
|
||||||
setenv("TZ", tz, 1);
|
|
||||||
tzset();
|
|
||||||
|
|
||||||
// Parse the POSIX TZ string using our custom parser for RealTimeClock::now()
|
|
||||||
if (!parse_posix_tz(tz, this->parsed_tz_)) {
|
|
||||||
ESP_LOGW(TAG, "Failed to parse timezone: %s", tz);
|
ESP_LOGW(TAG, "Failed to parse timezone: %s", tz);
|
||||||
// Reset to UTC on parse failure
|
// parsed stays as default (UTC) on failure
|
||||||
this->parsed_tz_ = ParsedTimezone{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set global timezone for all time conversions
|
||||||
|
set_global_tz(parsed);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class RealTimeClock : public PollingComponent {
|
|||||||
#ifdef USE_TIME_TIMEZONE
|
#ifdef USE_TIME_TIMEZONE
|
||||||
time_t epoch = this->timestamp_now();
|
time_t epoch = this->timestamp_now();
|
||||||
struct tm local_tm;
|
struct tm local_tm;
|
||||||
if (epoch_to_local_tm(epoch, this->parsed_tz_, &local_tm)) {
|
if (epoch_to_local_tm(epoch, get_global_tz(), &local_tm)) {
|
||||||
return ESPTime::from_c_tm(&local_tm, epoch);
|
return ESPTime::from_c_tm(&local_tm, epoch);
|
||||||
}
|
}
|
||||||
// Fallback to UTC if parsing failed
|
// Fallback to UTC if parsing failed
|
||||||
@@ -74,7 +74,6 @@ class RealTimeClock : public PollingComponent {
|
|||||||
void synchronize_epoch_(uint32_t epoch);
|
void synchronize_epoch_(uint32_t epoch);
|
||||||
|
|
||||||
#ifdef USE_TIME_TIMEZONE
|
#ifdef USE_TIME_TIMEZONE
|
||||||
ParsedTimezone parsed_tz_{};
|
|
||||||
void apply_timezone_(const char *tz);
|
void apply_timezone_(const char *tz);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef USE_TIME_TIMEZONE
|
||||||
|
#include "esphome/components/time/posix_tz.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
||||||
template<typename T> bool increment_time_value(T ¤t, uint16_t begin, uint16_t end);
|
template<typename T> bool increment_time_value(T ¤t, uint16_t begin, uint16_t end);
|
||||||
@@ -105,11 +109,20 @@ struct ESPTime {
|
|||||||
* @return The generated ESPTime
|
* @return The generated ESPTime
|
||||||
*/
|
*/
|
||||||
static ESPTime from_epoch_local(time_t epoch) {
|
static ESPTime from_epoch_local(time_t epoch) {
|
||||||
|
#ifdef USE_TIME_TIMEZONE
|
||||||
|
struct tm local_tm;
|
||||||
|
if (time::epoch_to_local_tm(epoch, time::get_global_tz(), &local_tm)) {
|
||||||
|
return ESPTime::from_c_tm(&local_tm, epoch);
|
||||||
|
}
|
||||||
|
// Fallback to UTC if conversion failed
|
||||||
|
return ESPTime::from_epoch_utc(epoch);
|
||||||
|
#else
|
||||||
struct tm *c_tm = ::localtime(&epoch);
|
struct tm *c_tm = ::localtime(&epoch);
|
||||||
if (c_tm == nullptr) {
|
if (c_tm == nullptr) {
|
||||||
return ESPTime{}; // Return an invalid ESPTime
|
return ESPTime{}; // Return an invalid ESPTime
|
||||||
}
|
}
|
||||||
return ESPTime::from_c_tm(c_tm, epoch);
|
return ESPTime::from_c_tm(c_tm, epoch);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/** Convert an UTC epoch timestamp to a UTC time ESPTime instance.
|
/** Convert an UTC epoch timestamp to a UTC time ESPTime instance.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user