Date calculation error using struct tm

Asked

Viewed 79 times

1

My software is incremented the date in 5 minutes and works perfectly the way I am doing, Searching I found a bug that only on 16/02 of this year the calculation is not correct, follows example:

16/1/119 23:55:0
16/1/119 23:55:0

16/1/119 23:60:0
16/1/119 23:0:0

16/1/119 23:5:0
16/1/119 23:5:0

16/1/119 23:10:0
16/1/119 23:10:0

16/1/119 23:15:0
16/1/119 23:15:0

Instead of going to midnight on the 17th he goes back to the 23rd of the 16th, I tested with other days and that doesn’t happen, I’m using the lib time.h:

#include <stdio.h>
#include <time.h>

int main() 
{
    struct tm dt_stream;
    int i;

    dt_stream.tm_mday = 16;
    dt_stream.tm_mon = 1; //02 Fev;
    dt_stream.tm_year = 19 + 2000 - 1900; //2019
    dt_stream.tm_hour = 23;
    dt_stream.tm_min = 50;
    dt_stream.tm_sec = 0;


    for ( i=0; i<5; i++) {
        dt_stream.tm_min = dt_stream.tm_min + 5;

        printf("%d/%d/%d %d:%d:%d\n", dt_stream.tm_mday, dt_stream.tm_mon, dt_stream.tm_year, \
                               dt_stream.tm_hour,dt_stream.tm_min, dt_stream.tm_sec);


        mktime(&dt_stream);

        printf("%d/%d/%d %d:%d:%d\n", dt_stream.tm_mday, dt_stream.tm_mon, dt_stream.tm_year, \
                              dt_stream.tm_hour,dt_stream.tm_min, dt_stream.tm_sec);

        printf("*****\n");
    }

    return 0;
}

Does anyone have any idea why this is happening? Compiling with gcc, running on Linux.

tm_mon = 0-11
tm_year = year-1900
  • It’s probably the end of Brazilian daylight saving time: at midnight on the 17th, the clocks are put back an hour, back to 11 pm. Did you try to keep adding to see if then it changes to day 17? Check the field value tm_isdst also, as it indicates whether or not it is in daylight: http://www.cplusplus.com/reference/ctime/tm/

  • Yes, if I loop 15 times, for example, it arrives again at 23:55 and moves to the day 17 to 0h As for the ISDST it looks like this 16/1/119 23:55:0 ISDST 4196256 16/1/119 23:55:0 ISDST 1 ***** 16/1/119 23:60:0 ISDST 1&Xa;16/1/119 23:0:0 ISDST 0

  • The program must be using Timezone configured on Linux. I do not remember how to programmatically configure the Timezone used, but you can do it via the command line. If you don’t want to have summer time effects, you can bash something like TZ=UTC ./seuprograma. Then the program starts to use UTC (instead of the Timezone of the operating system), and as UTC has no daylight saving time, these cases will no longer occur.

1 answer

1

Probably the cause is the end of Brazilian daylight saving time: At midnight of the day 17/02/2019, the clocks are delayed by an hour, back to the 23h of the day 16. That is, when the clock is at 23:59:59.999 (in daylight) instead of changing to midnight, it changes to 23:00 (in the "normal time)").

Therefore, every minute between 23:00 and 23:59 occurs twice: one during daylight saving time, the other during "normal hours". That’s not a bug, but that’s exactly how it works. When a time occurs twice (one in daylight time and the other in "normal" time), it is called overlap.

To verify that, I modified your loop to continue for a few more iterations. I also printed the field value tm_isdst, that according to the documentation, prints a value greater than zero when it is in daylight saving time, and zero when it is not in daylight saving time:

for (i = 0; i < 20; i++) {
    dt_stream.tm_min = dt_stream.tm_min + 5;

    mktime(&dt_stream);

    printf("%d/%d/%d %d:%d:%d - %d\n", dt_stream.tm_mday, dt_stream.tm_mon, dt_stream.tm_year, \
                          dt_stream.tm_hour,dt_stream.tm_min, dt_stream.tm_sec, dt_stream.tm_isdst);

    printf("*****\n");
}

The result:

16/1/119 23:55:0 - 1
*****
16/1/119 23:0:0 - 0
*****
16/1/119 23:5:0 - 0
*****
16/1/119 23:10:0 - 0
*****
16/1/119 23:15:0 - 0
*****
16/1/119 23:20:0 - 0
*****
16/1/119 23:25:0 - 0
*****
16/1/119 23:30:0 - 0
*****
16/1/119 23:35:0 - 0
*****
16/1/119 23:40:0 - 0
*****
16/1/119 23:45:0 - 0
*****
16/1/119 23:50:0 - 0
*****
16/1/119 23:55:0 - 0
*****
17/1/119 0:0:0 - 0
*****
17/1/119 0:5:0 - 0
*****
17/1/119 0:10:0 - 0
*****
17/1/119 0:15:0 - 0
*****
17/1/119 0:20:0 - 0
*****
17/1/119 0:25:0 - 0
*****
17/1/119 0:30:0 - 0
*****

Note that on the first line, the value of tm_isdst is 1 as it is in daylight time. On the second line onwards, the clock has been set back to 23h and is no longer in daylight time (therefore, tm_isdst becomes 0).

Then continuing the loop, we see that now when it arrives at 23:55, in the next iteration it changes to the 17th.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.