I am trying to convert a time held in a variable of time_t
to a struct tm*
in some time zone which is not the local time zone.
Building on this post, which discusses the inverse operation going from struct tm*
to time_t
, I have written the following function:
struct tm* localtime_tz(time_t* t, std::string timezone) {
struct tm* ret;
char* tz;
tz = std::getenv("TZ"); // Store currently set time zone
// Set time zone
setenv("TZ", timezone.c_str(), 1);
tzset();
std::cout << "Time zone set to " << std::getenv("TZ") << std::endl;
ret = std::localtime(t); // Convert given Unix time to local time in time zone
std::cout << "Local time is: " << std::asctime(ret);
std::cout << "UTC time is: " << std::asctime(std::gmtime(t));
// Reset time zone to stored value
if (tz)
setenv("TZ", tz, 1);
else
unsetenv("TZ");
tzset();
return ret;
}
However, the conversion fails, and I get
Time zone set to CEST
Local time is: Wed Aug 9 16:39:38 2017
UTC time is: Wed Aug 9 16:39:38 2017
i.e. local time is set to UTC time, instead of UTC+2 for CEST.
The time zone abbreviations shown by date
and other tools are not the names of time zones. The IANA time zone database uses a major city within the relevant region instead. The reason for that is that the abbreviations are not unique, and they do not convey sufficient information to convert past dates because places switch time zones.
In addition, POSIX specifies that the TZ
variable has to be parsed in a specific way, and it pretty much suggests to treat a bare time zone abbreviation like UTC (but with a different abbreviation).
Instead, you have to use the actual time zone name, such as Europe/Berlin
, or a POSIX time zone specifier such as CET-1CEST
.