Andrey Savov Andrey Savov - 28 days ago 7
C Question

How can I convert IANA time zone name to UTC offset at present in Ubuntu C/C++

In Python or Java you can get the UTC offset (at present time) given the IANA name of the timezone ("America/Los_Angeles" for instance). See get UTC offset from time zone name in python for example.

How can you do the same using C/C++ on Ubuntu 14.04?

EDIT: Preferably in a thread-safe way (no environment variables).

Answer

You alluded to this fact, but it's important to note that the offset between UTC and the time in a time zone is not necessarily constant. If the time zone performs daylight saving (summer) time adjustments, the offset will vary depending on the time of year.

One way to find the offset is to take the time you're interested in, hand it to the localtime() function, then look at the tm_gmtoff field. Do this with the TZ environment variable set to the zone name you're interested in. Here's an example that does so for the current time:

#include <time.h>
#include <stdio.h>

int main()
{
    setenv("TZ", "America/Los_Angeles", 1);
    time_t t = time(NULL);
    struct tm *tmp = localtime(&t);
    printf("%ld\n", tmp->tm_gmtoff);
}

At the moment this prints -25200, indicating that Los Angeles is 25200 seconds, or 420 minutes, or 7 hours west of Greenwich. But next week (actually tomorrow) the U.S goes off of DST, at which point this code will start printing -28800.

This isn't guaranteed to work, since the tm_gmtoff field is not portable. But I believe all versions of Linux will have it. (You might have to compile with -D_BSD_SOURCE or something, or refer to the field as __tm_gmtoff. But in my experience it tends to work by default, as plain tm_gmtoff.)

The other way is to go back and forth with gmtime and mktime, as described in Sam Varshavchik's answer.


Addendum: You asked about not using environment variables. There is a way, but unfortunately it's even less standard. There are BSD functions tzalloc and localtime_rz which do the job, but they do not exist on Linux. Here's how the code looks:

    timezone_t tz = tzalloc("America/Los_Angeles");
    if(tz == NULL) return 1;
    time_t t = time(NULL);
    struct tm tm, *tmp = localtime_rz(tz, &t, &tm);
    printf("%ld\n", tmp->tm_gmtoff);

For me this prints -28800 (because PDT fell back to PST just a few minutes ago).

If you had it, you could also use localtime_rz along with mktime in Sam Varshavchik's answer. And of course Howard Hinnant's library is pretty obviously thread-safe, not requiring mucking with TZ at all.

Comments