Search code examples
ctimeinitializationundefined-behaviorinteger-overflow

Negative time conversion gives random values


I'm trying to calculate a difference between two points in time in C and because those points are before 1900, I need to use negative values.

While converting is supposed to write the variable jahr_tod_negative into ts.tm_year, but almost every time I run the program, it gives me a completely different date, even day and month are mixed up. The year is the only value that needs to be negative. How can I prevent that?

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

int main ()
{

    time_t t;
    struct tm ts;
    char str[90];

    int tag_tod;
    int monat_tod;
    int jahr_tod;
    unsigned int jahr_tod_von_1900;
    int jahr_tod_negative;


    printf("Tag eingeben: ");
    scanf("%d", &tag_tod);
    printf("\nMonat eingeben: ");
    scanf("%d", &monat_tod);
    printf("\nJahr eingeben: ");
    scanf("%d", &jahr_tod);
    jahr_tod_von_1900 = 1900 - jahr_tod;
    jahr_tod_negative = -jahr_tod_von_1900;
    printf("jahr_tod_negative: %d\n", jahr_tod_negative);


    //ts.tm_sec     = 0;
    //ts.tm_min     = 0;
    //ts.tm_hour  = 0;
    ts.tm_mday  = tag_tod;
    ts.tm_mon   = monat_tod;
    ts.tm_year  = jahr_tod_negative;     /* Jahr - 1900 */
    //ts.tm_wday  = 0;
    //ts.tm_yday  = 0;
    //ts.tm_isdst = 0;

    t = mktime(&ts);
    //printf("%s", asctime(&ts));
    printf("ts.tm_year: %d\n", ts.tm_year);
    strftime(str, 90, "%d. %B %Y", &ts);
    printf("Eingegebenes Datum: %s\n", str);

    return 0;
}

Solution

  • For starters: You want to properly initialise

    struct tm ts;
    

    before using it. Else the code might very well run into undefined behaviour, so anything can happen.

    Do

    struct tm ts = {0};
    

    at least.


    Furthermore assuming

    unsigned int jahr_tod_von_1900;
    int jahr_tod_negative;
    

    this statement

     jahr_tod_von_1900 = 1900 - jahr_tod;
    

    cause a signed integer wrap around for jahr_tod > 1900. This latter "overflow" causes undefined behaviour as well then. Do not do this.

    As you are assigning to an unsigned anyway, to fix this make sure you do an "unsigned" subtraction like for example this way:

    jahr_tod_von_1900 = 1900U - (unsigned int) jahr_tod;