I am trying to code a function which populates a struct tm
from year, month, day, hour and minutes values.
The application deals with no time zone information, i.e., we assume that the input data time zone matches with the application and user time zone.
I have tried this:
void timeCreate(struct tm* pTm1, int year, int month, int day, int hour, int minute) {
pTm1->tm_year = year - 1900;
pTm1->tm_mon = month - 1;
pTm1->tm_mday = day;
pTm1->tm_hour = hour;
pTm1->tm_min = minute;
pTm1->tm_sec = 0;
pTm1->tm_isdst = -1;
mktime(pTm1);
}
If I don't do anything else, I get the CET time set by mktime (CET is my local timezone) and it seems that mktime changes the time and date, so it is no longer 2014/01/01 00:00 but the day before.
If I do this:
pTm1->tm_gmtoff = 0;
pTm1->tm_zone = "UTC";
Then I do not get any correction.
I have also seen the function gmtime()
instead of mktime()
. Which would be the "right" way of setting up this struct?
Also I get a random value for tm_wday
, can that value be calculated automatically?
mktime
only works with local time, and its behavior is constrained by the specification so that it cannot examine any nonstandard fields of struct tm
like tm_gmtoff
. And gmtime
is not an analog of mktime
but of localtime
- it converts in the opposite direction. If you want a normalization/conversion of broken-down UTC time in struct tm
format to time_t
, you need to either use the nonstandard but widely available timegm
function, or write it out yourself. Thankfully POSIX exactly specifies the formula:
tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
(tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
Note that if copied as written to C code, this is full of integer overflows, so some type promotions or other fixes need to be introduced to make it valid.
If you need the normalization aspect timegm
also performs, but need it done portably without depending on the nonportable timegm
, you can just call gmtime_r
after using the above formula to invert it and get a normalized result.