Converting Between Local Times and GMT/UTC in C/C++
Asked Answered
T

3

32

What's the best way to convert datetimes between local time and UTC in C/C++?

By "datetime", I mean some time representation that contains date and time-of-day. I'll be happy with time_t, struct tm, or any other representation that makes it possible.

My platform is Linux.

Here's the specific problem I'm trying to solve: I get a pair of values containing a julian date and a number of seconds into the day. Those values are in GMT. I need to convert that to a local-timezone "YYYYMMDDHHMMSS" value. I know how to convert the julian date to Y-M-D, and obviously it is easy to convert seconds into HHMMSS. However, the tricky part is the timezone conversion. I'm sure I can figure out a solution, but I'd prefer to find a "standard" or "well-known" way rather than stumbling around.


A possibly related question is Get Daylight Saving Transition Dates For Time Zones in C

Topmost answered 17/4, 2009 at 19:11 Comment(0)
S
24

You're supposed to use combinations of gmtime/localtime and timegm/mktime. That should give you the orthogonal tools to do conversions between struct tm and time_t.

For UTC/GMT:

time_t t;
struct tm tm;
struct tm * tmp;
...
t = timegm(&tm);
...
tmp = gmtime(t);

For localtime:

t = mktime(&tm);
...
tmp = localtime(t);

All tzset() does is set the internal timezone variable from the TZ environment variable. I don't think this is supposed to be called more than once.

If you're trying to convert between timezones, you should modify the struct tm's tm_gmtoff.

Simplicidentate answered 17/4, 2009 at 19:17 Comment(8)
Thanks! I knew something like timegm() had to exist, but didn't know the name.Topmost
Glad to help. Time conversion can be a rather tricky area. It's usually a good idea to store everything in UTC whenever possible. Converting between timezones is even trickier!Simplicidentate
Yeah, unfortunately the system's designers chose local time as the "standard" timestamp format for the messaging protocol. I hate it when people do that.Topmost
There is no timegm in Windows.Enwomb
I'll likely ask this as a separate question (digging through questions that mention tm_gmtoff now, and the list is pretty short), but: Could you perhaps give an example of modifying tm_gmtoff and having that do anything useful? It doesn't seem to change the output of, e.g, strftime(buf, BUFSIZ, "%FT%T%z (%+ %z)", tm);, when I do it. ??Saarinen
It doesn't appear that tm_gmtoff is a standard member of struct tm. cplusplus.com/reference/clibrary/ctime/tmKrauss
As mentioned by @stepancheg, timegm is a non-standard GNU/BSD extension and is not available on Windows, etc. The Linux man page for timegm shows a portable approach based on changing TZ in the environment. Unfortunately, this too isn't immediately portable to Windows, due to its lack of setenv.Parallel
On Windows you can use _mkgmtime(&tm);, it interprets the struct tm to be in UTC rather than in your current TZ.Reminiscent
S
19

If on Windows, you don't have timegm() available to you:

struct tm *tptr;
time_t secs, local_secs, gmt_secs;
time( &secs );  // Current time in GMT
// Remember that localtime/gmtime overwrite same location
tptr = localtime( &secs );
local_secs = mktime( tptr );
tptr = gmtime( &secs );
gmt_secs = mktime( tptr );
long diff_secs = long(local_secs - gmt_secs);

or something similar...

Speed answered 17/4, 2009 at 19:11 Comment(3)
Shouldn't secs and gmt_secs be identical? I would think you could simplify this quite a bit.Validate
I tried this. I tried to verify it by testing the result against the inverse. For some times it works, and for others, it is off by an hour. I'm guessing that's because DST starts and stops at different dates in the different locations I'm trying (using GMT, but converting against PST localtime). Is there any way to compensate for that?Respiration
This version, which uses the Boost POSIX time library, seems to work despite differing DST dates across timezones: https://mcmap.net/q/368175/-how-do-i-convert-boost-posix_time-ptime-to-time_t .Respiration
D
3

If you need to worry about converting date/time with timezone rules, you might want to look into ICU.

Dalpe answered 18/4, 2009 at 2:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.