I have a function that I wrote (if there is a good standard substitute, please let me know...)
time_t get_unix_time(string time_str) {
time_t loctime;
time(&loctime);
struct tm *given_time;
time_str = time_str.substr(0, time_str.find_first_of('.'));
replace(time_str.begin(), time_str.end(), ':', ',');
replace(time_str.begin(), time_str.end(), '-', ',');
replace(time_str.begin(), time_str.end(), '/', ',');
replace(time_str.begin(), time_str.end(), ' ', ',');
given_time = localtime(&loctime);
vector<string> trecord = split_string(time_str, ',');
given_time->tm_year = atoi(trecord.at(0).c_str()) - 1900;
given_time->tm_mon = atoi(trecord.at(1).c_str()) - 1;
given_time->tm_mday = atoi(trecord.at(2).c_str());
given_time->tm_hour = atoi(trecord.at(3).c_str());
given_time->tm_min = atoi(trecord.at(4).c_str());
given_time->tm_sec = atoi(trecord.at(5).c_str());
return mktime(given_time);
}
The input (time_str) to the function is of the format 1970-01-01 00:00:00.0. The split_string() function splits the string time_str
into a vector containing:
{ 1970, 01, 01, 00, 00, 00 }
which is used to fill in the given_time structure.
I wrote a function to test it, and passed it exactly that input (start of epoch). However, the time it gives me back is 21600, which is 1970-01-01 06:00:00, or UTC+6. The expected output is 0 (start of the epoch).
Note: that I am in the US-Central time zone, which is UTC - 6. At midnight on 1st Jan 1970 CST, time @ UTC would be 1st Jan 1970 06:00:00.
Is there anything in my function that is making it specific to my timezone? Am I doing something wrong in this function, or can I do something different to make it zone independent, or at least always UTC.
Maybe you should use
gmtime
instead oftime
, to rid yourself of timezone issues.Edit: I don't really understand why you fill the structure with the current time, then overwrite all its components. Why not just:
Another edit:
Ugh,
mktime
considers local time too. I'm not really sure how you can get around this other than setting your timezone locale to UTC.mktime
takes a time in the local time zone. So, if you pass it 1970-01-01 00:00:00 local time, it returns 1970-01-01 06:00:00 UTC, as it should.As an alternative, you can call timegm, if you're using glibc. If you're not using glibc, you temporarily change the local time to UTC when calling mktime by messing with the TZ environment variable, as described on the timegm manpage:
Also, your call to
localtime
is unnecessary, and you probably ought to setgiven_time->tm_isdst
, to avoid possible daylight savings time issues.You could write a wrapper around
strptime
to do the parsing.@Josh Kelley's answer explains the timezone issue thoroughly.
If you are using glibc you have the
timegm
function at your disposal, which is a version ofmktime
that always interprets the time as if it were in theGMT
timezone. Unfortunately, the documentation for that function basically states that it cannot otherwise be implemented using standard library calls. So you're sort of out of luck unless you have it.Just avoid these awkward functions and do the math yourself. POSIX specifies that
time_t
is an arithmetic type in the form of seconds since "the epoch" (1970-01-01 00:00:00 GMT) without any leapsecond nonsense (all days are exactly 86400 calendar seconds, which differ from SI seconds by a tiny amount), so aside from a little leapyear logic, the computation is extremely straightforward.Calendar calculations like this are a standard introductory programming exercise so I'm sure you can work it out or find solutions on the web.
As an aside, perhaps the reason ISO C and POSIX omit such a function is that, unlike conversions involving timezones which can be arbitrarily complex and which only the host's library can perform reliably and consistently across different applications, GMT conversions are pure arithmetic with no external parameters.
When you call mktime, it interpretes the parameter as a local time. You have also used function like "localtime" that seems to be useless and I think you can drop them.