Search code examples
c++timetimezoneposix

C++: converting Unix time to non-local timezone


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.


Solution

  • 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.