Unfortunately strptime
expects local time - and you cannot easily change it to UTC, for conversion back to your local time.
There is a POSIX function you can use called timegm
but it’s not implemented on either Arduino or IDF platforms.
I do have a function that does it though - so it can be done. Below yaml will take an ISO DateTime string and convert it to two text sensors - a date and a time, in your local time zone.
First you need to add the function to ESPHome. Create a .h file in the ESPHome directory, in this example it’s called functions.h. Paste the function code into it and save, then add an include to your yaml.
time_t _mkgmtime(const struct tm *tm)
{
// Month-to-day offset for non-leap-years.
static const int month_day[12] =
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
// Most of the calculation is easy; leap years are the main difficulty.
int month = tm->tm_mon % 12;
int year = tm->tm_year + tm->tm_mon / 12;
if (month < 0) { // Negative values % 12 are still negative.
month += 12;
--year;
}
// This is the number of Februaries since 1900.
const int year_for_leap = (month > 1) ? year + 1 : year;
time_t rt = tm->tm_sec // Seconds
+ 60 * (tm->tm_min // Minute = 60 seconds
+ 60 * (tm->tm_hour // Hour = 60 minutes
+ 24 * (month_day[month] + tm->tm_mday - 1 // Day = 24 hours
+ 365 * (year - 70) // Year = 365 days
+ (year_for_leap - 69) / 4 // Every 4 years is leap...
- (year_for_leap - 1) / 100 // Except centuries...
+ (year_for_leap + 299) / 400))); // Except 400s.
return rt < 0 ? -1 : rt;
}
esphome:
name: webinterface
includes:
- functions.h
logger:
esp32:
board: esp32dev
framework:
type: esp-idf
time:
- platform: sntp
id: sntp_time
ota:
platform: esphome
password: "c1c4c455c995776545f45707eaecc11d"
wifi:
ssid: SARWLAN
password: !secret wifi_password
output_power: 8.5db
captive_portal:
api:
reboot_timeout: 0s
globals:
id: time1
type: std::string
initial_value: '"2025-03-02T19:08:12.379Z"'
text_sensor:
- platform: template
name: "Date from string"
id: dfs
lambda: |-
time_t t;
struct tm tm;
strptime(id(time1).c_str(), "%FT%TZ%z", &tm);
t = _mkgmtime(&tm);
struct tm *tml = localtime(&t);
char tout_c[20];
strftime(tout_c, 20, "%Y-%m-%d", tml);
std::string tout = tout_c;
return tout;
- platform: template
name: "Time from string"
id: tfs
lambda: |-
time_t t;
struct tm tm;
strptime(id(time1).c_str(), "%FT%T%z", &tm);
t = _mkgmtime(&tm);
struct tm *tml = localtime(&t);
char tout_c[20];
strftime(tout_c, 20, "%H:%M:%S", tml);
std::string tout = tout_c;
return tout;
@Spockie - note I changed your example time string to a few hours later so I could more easily test in my time zone.