简体   繁体   中英

C calculate difference between dates

I've been searching a lot about how to get the difference in months between two dates using C but I've not been able to solve it. So I figured I start simple to get an understanding of it and go from there.

Building from some of the examples I've seen that is supposed to calculate the hours between two dates, this is the code I came up with:

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

int main()
{
        char *time1 = "2015-08-10";
        char *time2 = "2017-05-16";
        struct tm tm1;
        struct tm tm2;
        time_t t1;
        time_t t2;
        double hours;

        strptime(time1, "%Y-%m-%d", &tm1);
        strptime(time2, "%Y-%m-%d", &tm2);

        printf("time1: %s\n", time1);
        printf("tm1.year: %d\n", tm1.tm_year);
        printf("tm1.mon : %d\n", tm1.tm_mon);
        printf("tm1.day : %d\n", tm1.tm_mday);

        printf("time2: %s\n", time2);
        printf("tm2.year: %d\n", tm2.tm_year);
        printf("tm2.mon : %d\n", tm2.tm_mon);
        printf("tm2.day : %d\n", tm2.tm_mday);

        t1 = mktime(&tm1);
        t2 = mktime(&tm2);

        hours = difftime(t2, t1) / 60 / 60;

        printf("diff: %lf\n", hours);

        return 0;
}

It compiles and runs but it gives me different hours every time I execute it? Can't understand why?

Compile:

$ gcc -Wall main.c -o timespan

And executions:

$ ./timespan 
time1: 2015-08-10
tm1.year: 115
tm1.mon : 7
tm1.day : 10
time2: 2017-05-16
tm2.year: 117
tm2.mon : 4
tm2.day : 16
diff: -1885271229.700556
$ ./timespan 
time1: 2015-08-10
tm1.year: 115
tm1.mon : 7
tm1.day : 10
time2: 2017-05-16
tm2.year: 117
tm2.mon : 4
tm2.day : 16
diff: -652404645.977222

The strings you're reading in don't have a time component, so those fields aren't set by strptime .

From the man page :

Notes

In principle, this function does not initialize tm but only stores the values specified. This means that tm should be initialized before the call. Details differ a bit between different UNIX systems. The glibc implementation does not touch those fields which are not explicitly specified, except that it recomputes the tm_wday and tm_yday field if any of the year, month, or day elements changed.

When you then call mktime , it reads those uninitialized fields, invoking undefined behavior .

You need to initialize these structs:

struct tm tm1 = {0};
struct tm tm2 = {0};

Then you'll get consistent results:

time1: 2015-08-10
tm1.year: 115
tm1.mon : 7
tm1.day : 10
time2: 2017-05-16
tm2.year: 117
tm2.mon : 4
tm2.day : 16
diff: 15480.000000

Also, for printing values of type double , use the %f format specifier. %lf is valid, but has no effect.

Thanks for all the help. I managed to solve the initial problem (diff in months) and for those interested, this is the product.

#define _XOPEN_SOURCE 800
#include <time.h>
#include <stdio.h>

struct date_stamp {
        int yer;
        int mon;
        int day;
        int hrs;
        int min;
        int sec;
};

int main()
{
        char *time1 = "2015-08-10";
        char *time2 = "2016-08-10";
        struct tm tm1 = {0}; /* tm structs need to be initialized */
        struct tm tm2 = {0};
        struct date_stamp diff_date;      
        time_t t1;
        time_t t2;
        double diff;

        /* convert the time strings into tm structs */
        strptime(time1, "%Y-%m-%d", &tm1);
        strptime(time2, "%Y-%m-%d", &tm2);

        /* make the time_t variables*/
        t1 = mktime(&tm1);
        t2 = mktime(&tm2);

        /* calculate the diffrence in seconds */
        diff = difftime(t2, t1);

        /* 
         * appearently there goes 2629746 seconds 
         * in one gregorian month
         */
        diff_date.sec = diff;
        diff_date.min = diff / 60;
        diff_date.hrs = diff / 60 / 60;
        diff_date.day = diff / 60 / 60 / 24;
        diff_date.mon = diff / 2629746;
        diff_date.yer = diff / 60 / 60 / 24 / 365;

        printf("start  : %s\n", time1);
        printf("end    : %s\n", time2);
        puts(  "-------+-----------");
        printf("Year   : %d\n", diff_date.yer);
        printf("Months : %d\n", diff_date.mon);
        printf("Days   : %d\n", diff_date.day);
        printf("Hours  : %d\n", diff_date.hrs);
        printf("Minutes: %d\n", diff_date.min);
        printf("Seconds: %d\n", diff_date.sec);

        return 0;
}

Don't think the calculations are rock solid thou (366 days in a year ?!?). But I'll tweak that later, at least I have a base to build from.

$ gcc -Wall main.c -o timespan 
$ ./timespan 
start  : 2015-08-10
end    : 2016-08-10
-------+-----------
Year   : 1
Months : 12
Days   : 366
Hours  : 8784
Minutes: 527040
Seconds: 31622400

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM