tags:

views:

812

answers:

3

I'm looking for something that I presumed would be very simple - given local Unix time in a specific time zone (specified as a string, e.g., "America/New_York" - note that's not my local time), get the corresponding time value in GMT. I.e., something along the lines of

time_t get_gmt_time(time_t local_time,
                    const char* time_zone);

As deceptively simple as it sounds, the closest I could find was the following code snippet from timegm's man page:

       #include <time.h>
       #include <stdlib.h>

       time_t
       my_timegm(struct tm *tm)
       {
           time_t ret;
           char *tz;

           tz = getenv("TZ");
           setenv("TZ", "", 1);
           tzset();
           ret = mktime(tm);
           if (tz)
               setenv("TZ", tz, 1);
           else
               unsetenv("TZ");
           tzset();
           return ret;
       }

There gotta be a better way than this belligerently not thread-safe abomination, right? Right??

A: 

I really thought there was something in glib, but seem to have misremembered. I know you're probably looking for straight-up C code, but here's the best I've got:

I know that Python has some notion of timezones through a tzinfo class - you can read about it in the datetime documentation. You can have a look at the source code for the module (in the tarball, it's in Modules/datetime.c) - it appears to have some documentation, so maybe you can get something out of it.

Jefromi
Yes, I meant straight C API of course - subject's corrected now, thanks!As for looking at the Python implementation, that idea crossed my mind but I really hoped to avoid going that path. Having looked at the source and then the API docs, I found that Python's datetime is blissfully unaware of time zones - all it gives is you is an abstract tzinfo class that you're supposed to implement if you're to do time conversions between time zones. There are a few libraries that implement that but, really - are things really *that* bad?
igor
+3  A: 

From tzfile(5), which documents the files in /usr/share/zoneinfo (on my system) in gruesome detail:

It seems that timezone uses tzfile internally, but glibc refuses to expose it to userspace. This is most likely because the standardised functions are more useful and portable, and actually documented by glibc.

Again, this is probably not what you're looking for (ie. an API), but the information is there and you can parse it without too much pain.

bstpierre
Yeah, this sounds like about the only way to make this work, as ugly as it is. Of course, once implemented, I'll end up with a generic timezone conversion API I was looking for in the first place :oAs I'm currently dealing with a single-threaded forked process, I may not have enough motivation to do this and will likely just opt for the TZ "hack" mentioned in timegm's man page.
igor
+1  A: 

Similar to the Python answer, I can show you what R does:

R> now <- Sys.time()       # get current time
R> format(now)             # format under local TZ
[1] "2009-08-03 18:55:57"
R> format(now,tz="Europe/London")   # format under explicit TZ
[1] "2009-08-04 00:55:57"
R> format(now,tz="America/Chicago") # format under explicit TZ
[1] "2009-08-03 18:55:57"
R>

but R uses an internal representation that extends the usual struct tm --- see R-2.9.1/src/main/datetime.c.

Still, this is a hairy topic and it would be nice if it were the standard library. As it isn't maybe your best bet is to use Boost Date_Time (example)

Dirk Eddelbuettel
From what I understand, Boost's Date_time doesn't make use of system's zoneinfo files and relies on its own timezone database instead - which makes it a non-starter, IMHO. Do correct me if I got it wrong...
igor