Confusing behaviour of mktime() function : increasing tm_hour count by one

Dhiraj Neve picture Dhiraj Neve · Aug 25, 2012 · Viewed 9.2k times · Source

I am executing below code.

int main()
{
struct tm storage={0,0,0,0,0,0,0,0,0};
char *p = NULL; 
p = (char *)strptime("2012-08-25 12:23:12","%Y-%m-%d %H:%M:%S",&storage);
char buff[1024]={0};
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
storage.tm_sec += 20;
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
mktime(&storage);
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
return 0;
}

If above Program executed, It prints ' 2012-08-25 13:23:32' instead of '2012-08-25 12:23:32'. Please Help, why it is increasing tm_hour value. This works correctly if I put input date as '2012-02-25 12:23:32' in program, which is confusing.

OUtput ->

[user@rtpkvm55-vm2 root]$ ./a.out
2012-08-25 12:23:12
2012-08-25 12:23:32
2012-08-25 13:23:32
[user@rtpkvm55-vm2 root]$

Date Info on my system, -->

[user@rtpkvm55-vm2 root]$ date
Sat Aug 25 08:28:26 EDT 2012

Answer

rve picture rve · Aug 25, 2012

What happens

The date you specified has daylight savings in effect but when calling mktime, storage.tm_isdst is zero. mktime sees this and thinks "hey, they gave me a date with an incorrect daylight savings flag, lets fix it". Then it sets tm_isdst to 1 and changes tm_hour.

See also this answer.

To fix it

  • use timegm instead of mktime
  • set the timezone to UTC before calling mktime (see also example from timegm) :
    setenv("TZ", "", 1);
    tzset();
    mktime();
  • use a good date-time library (like boost::locale::date_time/boost::date_time, but read the Q&A section on the boost::locale::date_time page before picking one)