I'm trying to convert a time info I reveive as a UTC string to a timestamp using std::mktime
in C++. My problem is that in <ctime>
/ <time.h>
there is no function to convert to UTC; mktime will only return the timestamp as local time.
So I need to figure out the timezone offset and take it into account, but I can't find a platform-independent way that doesn't involve porting the whole code to boost::date_time
. Is there some easy solution which I have overlooked?
mktime() always uses local time zone and converts from UTC If you're working with UTC times, you may be upset to find that mktime() always converts using your local time zone thus wrecking your UTC times.
The gmtime() function in C++ converts the given time since epoch to calendar time which is expressed as UTC time rather than local time. The gmtime() is defined in <ctime> header file.
C library function - mktime() The C library function time_t mktime(struct tm *timeptr) converts the structure pointed to by timeptr into a time_t value according to the local time zone.
long int tm_gmtoff. This field describes the time zone that was used to compute this broken-down time value, including any adjustment for daylight saving; it is the number of seconds that you must add to UTC to get local time. You can also think of this as the number of seconds east of UTC.
timestamp = mktime(&tm) - _timezone;
or platform independent way:
timestamp = mktime(&tm) - timezone;
If you look in the source of mktime() on line 00117, the time is converted to local time:
seconds += _timezone;
mktime() uses tzname for detecting timezone. tzset() initializes the tzname variable from the TZ enviroment variable. If the TZ variable appears in the enviroment but its value is empty or its value cannot be correctly interpreted, UTC is used.
A portable (not threadsafe) version according to the timegm manpage
#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; }
Eric S Raymond has a threadsafe version published in his article Time, Clock, and Calendar Programming In C
time_t my_timegm(register struct tm * t) /* struct tm to seconds since Unix epoch */ { register long year; register time_t result; #define MONTHSPERYEAR 12 /* months per calendar year */ static const int cumdays[MONTHSPERYEAR] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; /*@ +matchanyintegral @*/ year = 1900 + t->tm_year + t->tm_mon / MONTHSPERYEAR; result = (year - 1970) * 365 + cumdays[t->tm_mon % MONTHSPERYEAR]; result += (year - 1968) / 4; result -= (year - 1900) / 100; result += (year - 1600) / 400; if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) && (t->tm_mon % MONTHSPERYEAR) < 2) result--; result += t->tm_mday - 1; result *= 24; result += t->tm_hour; result *= 60; result += t->tm_min; result *= 60; result += t->tm_sec; if (t->tm_isdst == 1) result -= 3600; /*@ -matchanyintegral @*/ return (result); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With