The set_time()
function is supposed to take a particular time and add the specified number of minutes to this time and save it in *t
.
#include <stdio.h>
#include <time.h>
enum {JAN, FEB, MAR, APR, MAY, JUNE, JULY, AUG, SEP, OCT, NOV, DEC};
void set_time(struct tm *t,
int year, int mon, int day,
int hour, int min, int sec,
int mins_to_add)
{
/* Copy all the values. */
t->tm_year = (year - 1900);
t->tm_mon = mon;
t->tm_mday = day;
t->tm_hour = hour;
t->tm_min = min;
t->tm_sec = sec;
// No DST since we are storing UTC time.
t->tm_isdst = 0;
/* Add minutes to time. */
t->tm_min += mins_to_add;
mktime(t);
/* Debug print */
printf("%s\n", asctime(t));
}
int main(int argc, char **argv)
{
struct tm t;
set_time(&t, 2011, AUG, 1, 10, 00, 00, 0);
return 0;
}
So, I ask set_time()
to add nothing to Aug 01 10:00:00 2011. However, if my Windows system is set to EST time zone, the output I get is: Mon Aug 01 11:00:00 2011
The error happens because I do the task of adding the specified number of minutes (0 in the above example) to the specified time (Aug 01 10:00:00 2011 in the above example) with this part of the code:
/* Add minutes to time. */
t->tm_min += mins_to_add;
mktime(t);
mktime()
is called to adjust all other member variables of the structure in case t->tm_min
exceeds 59 due to the addition. But mktime()
treats the time in struct tm
object as local time. So, when it sees that the date is Aug 01 2011 and local time zone as EST, it assumes that DST needs to be applied but it finds that t->tm_isdst
is set to 0
(meaning DST isn't applied to the time in *t
). So, it applies DST, adjusts the date from Aug 01 10:00:00 2011 to Aug 01 11:00:00 2011 and sets t->tm_isdst
to 1
.
Had I initialized t->tm_isdst
to 1
, this issue wouldn't have occurred because mktime()
would have found that the time in *t
already has DST applied to it. However, it would have messed up the result if I asked set_time()
to add nothing to a date on which DST should not not applied, say Jan 01 10:00:00 2011. Now, it would try to turn off DST in *t
thereby setting t->tm_isdst
to 0 and re-adjusting the date to Jan 01 09:00:00 2011.
As a result, this has the undesirable effect of adding an extra hour to or subtracting an extra hour from the specified time when I wanted to add nothing to it. This happens because when mktime()
finds that the DST setting in t->tm_isdst
is not what it should be as per the local time-zone of the system, it tries to set it correctly by readjusting the time in *t
.
What is the right way to solve this problem?