In C, there is any API which converts time returned by time()
function to a specific timezone?
There is a function strftime()
which converts into current timezone of the system.
But what I want is function input is time (returned by time()
) and timeZone and it will convert the specific formatted time in said timezone format.
Is there such an API?
POSIX specifies
tzset()
:So, you could in theory use something like this to convert
t0
(atime_t
) into US/Eastern time when that is not your default TZ:This preserves a copy of the old time zone (you can't rely on it not changing or going out of scope while you're dinking with this stuff), then sets the target time zone in the environment. It then tells the system to look at $TZ and set the local time zone accordingly. You then convert the given
time_t
value to a broken down local time withlocaltime()
, format the string, then reset the TZ environment variable and tell the system to take another look at it withtzset()
again.In practice, this may or may not work; it depends on the system.
If you need thread-safe versions of this stuff, you'll have to work harder. This is categorically not thread-safe as written.
The sample code has skimped on error checking — it doesn't have any.
I would never claim this is a simple way of doing it; there ought to be a better way.
Test Code
Test Output
Note that when the strings for EST and PST do not have a daylight saving code specified, you get one time zone offset; when there is a daylight saving code set (such as
"EST5EDT"
or"PST8PDT"
) and the time to be printed is at the appropriate time of year (such as end of April), you get the EDT or PDT time value printed.Note, too, that there are conflicting ISO standards on how to handle time zones. ISO 8601 (for date/time formatting) says that time zones east of UTC (Greenwich) are positive and those west of UTC are negative. At least some other standards (e.g. SQL, ISO 9075) use the same notation. On the other hand, POSIX (aka ISO 9945) uses the opposite convention in TZ, as shown in the example code. The conflict is accepted only because of long-standing precedent. The C standard is silent on the format (or existence) of the TZ environment variable (though C99 §7.23.3.5 The
strftime
function does reference ISO 8601 a number of times).And (just as a salutary reminder why error checking is a good idea), on Mac OS X 10.7.3, my environment doesn't have TZ set in it (but it is normally US/Pacific, aka Cupertino, aka America/Los_Angeles, time). So the code above crashes when
getenv()
returns a null pointer. I ran it withTZ=CST6CDT
in the environment, as you can see from the first line of output.There are really three steps to look at here. First, a
time_t
represents an absolute time stamp -- something at least conceptually on the order of a UTC timestamp. It's not (normally) in any particular time zone -- it typically represents the number of seconds since some epoch (often midnight January 1, 1970).You can convert that to a
struct tm
, which breaks that time stamp out into an actual date and time -- a year, month, day, hour, minute, and second. There are two functions to do that conversion:gmtime
, which leaves it as a UTC-style time (i.e., in the Greenwich time zone). The other islocaltime
, which converts it to whatever time zone the environment has been configured to believe represents the location of the machine.The next step is to use
strftime
to convert that to something readable. This is based on the current locale, so (for example) as I write this it's what I think of as "Sunday". If my machine was configured for Spanish, however, that would probably show up as "Domingo", or something on that order.You really have two rather different questions. You can only convert a
time_t
into a time for one of two time zones: the "local" time zone (at least, whatever the machine has been configured to think of a "local"), or Greenwich time. If you want any other time zone, you're pretty much stuck with something like converting to GM time, then adjusting to the timezone of your choice.There is more provision for adjusting formatting. By default the library will always convert for the "C" locale, which is pretty much a simplified version of US English. You can also set the nameless locale ("") which gives you a locale that's suppose to match how the machine has been configured. As a third alternative, most libraries will let you specify a name for a specific locale, so if you wanted your date formatted as somebody in the French-speaking part of Canada would expect, you'd set the locale to something like "French_Canada" and that's what you'd get (though the string you use varies with the standard library, so you might need to use something like "fr-can" instead).