From 5861cf37f96628810e59526deeb8f386c66a391e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 25 Oct 2025 11:20:06 -0700 Subject: [PATCH 1/3] [core] Simplify ESPTime::strftime() and save 20 bytes flash --- esphome/core/time.cpp | 22 ++++++++-------------- esphome/core/time.h | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/esphome/core/time.cpp b/esphome/core/time.cpp index 1285ec6448..9a1a0dc492 100644 --- a/esphome/core/time.cpp +++ b/esphome/core/time.cpp @@ -46,24 +46,18 @@ struct tm ESPTime::to_c_tm() { return c_tm; } -std::string ESPTime::strftime(const std::string &format) { - std::string timestr; - timestr.resize(format.size() * 4); +std::string ESPTime::strftime(const char *format, size_t format_len) { struct tm c_tm = this->to_c_tm(); - size_t len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm); - while (len == 0) { - if (timestr.size() >= 128) { - // strftime has failed for reasons unrelated to the size of the buffer - // so return a formatting error - return "ERROR"; - } - timestr.resize(timestr.size() * 2); - len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm); + char buf[128]; + size_t len = ::strftime(buf, sizeof(buf), format, &c_tm); + if (len > 0) { + return std::string(buf, len); } - timestr.resize(len); - return timestr; + return "ERROR"; } +std::string ESPTime::strftime(const std::string &format) { return this->strftime(format.c_str(), format.size()); } + bool ESPTime::strptime(const std::string &time_to_parse, ESPTime &esp_time) { uint16_t year; uint8_t month; diff --git a/esphome/core/time.h b/esphome/core/time.h index a53fca2346..0d47ce820b 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -55,6 +55,23 @@ struct ESPTime { */ std::string strftime(const std::string &format); + /** Convert this ESPTime struct to a string as specified by the format argument. + * @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime + * + * This overload is optimized for string literals and avoids std::string parameter overhead. + * + * @param format The format string (null-terminated C string) + * @param format_len Optional length of the format string. If 0 (default), strlen() will be called. + * + * @warning This method uses dynamically allocated strings which can cause heap fragmentation with some + * microcontrollers. + * + * @warning This method can return "ERROR" when the underlying strftime() call fails, e.g. when the + * format string contains unsupported specifiers or when the format string doesn't produce any + * output. + */ + std::string strftime(const char *format, size_t format_len = 0); + /// Check if this ESPTime is valid (all fields in range and year is greater than 2018) bool is_valid() const { return this->year >= 2019 && this->fields_in_range(); } From 960c80b202293c6b36377afffc872b35fae6fd82 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 25 Oct 2025 11:21:22 -0700 Subject: [PATCH 2/3] [core] Simplify ESPTime::strftime() and save 20 bytes flash --- esphome/core/time.h | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/esphome/core/time.h b/esphome/core/time.h index 0d47ce820b..13a0127156 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -44,32 +44,14 @@ struct ESPTime { size_t strftime(char *buffer, size_t buffer_len, const char *format); /** Convert this ESPTime struct to a string as specified by the format argument. - * @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime + * @see https://en.cppreference.com/w/c/chrono/strftime * - * @warning This method uses dynamically allocated strings which can cause heap fragmentation with some - * microcontrollers. - * - * @warning This method can return "ERROR" when the underlying strftime() call fails, e.g. when the - * format string contains unsupported specifiers or when the format string doesn't produce any - * output. + * @warning This method can return "ERROR" when the underlying strftime() call fails or when the + * output exceeds 128 bytes. */ std::string strftime(const std::string &format); - /** Convert this ESPTime struct to a string as specified by the format argument. - * @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime - * - * This overload is optimized for string literals and avoids std::string parameter overhead. - * - * @param format The format string (null-terminated C string) - * @param format_len Optional length of the format string. If 0 (default), strlen() will be called. - * - * @warning This method uses dynamically allocated strings which can cause heap fragmentation with some - * microcontrollers. - * - * @warning This method can return "ERROR" when the underlying strftime() call fails, e.g. when the - * format string contains unsupported specifiers or when the format string doesn't produce any - * output. - */ + /// @copydoc strftime(const std::string &format) std::string strftime(const char *format, size_t format_len = 0); /// Check if this ESPTime is valid (all fields in range and year is greater than 2018) From ace2fce3a223122214c3b071809c3b34d12c27a5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 25 Oct 2025 11:23:23 -0700 Subject: [PATCH 3/3] [core] Simplify ESPTime::strftime() and save 20 bytes flash --- esphome/core/time.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/core/time.h b/esphome/core/time.h index 13a0127156..080a0793e0 100644 --- a/esphome/core/time.h +++ b/esphome/core/time.h @@ -46,6 +46,9 @@ struct ESPTime { /** Convert this ESPTime struct to a string as specified by the format argument. * @see https://en.cppreference.com/w/c/chrono/strftime * + * @warning This method returns a dynamically allocated string which can cause heap fragmentation with some + * microcontrollers. + * * @warning This method can return "ERROR" when the underlying strftime() call fails or when the * output exceeds 128 bytes. */