C program days between two dates

前端 未结 6 397
悲&欢浪女
悲&欢浪女 2021-01-02 18:30

I have written a program that should find the days between two dates, but it has some hiccups. The logic makes perfect sense in my head when I read through it, so

相关标签:
6条回答
  • 2021-01-02 18:35

    There are multiple problems in your code snippet.. but I must say it is a very good attempt. There are many short cuts to what you're try to achieve.

    I have written the following program which finds the number of days between two given dates. You may use this as a reference.

    #include <stdio.h>
    #include <stdlib.h>
    
    char *month[13] = {"None", "Jan", "Feb", "Mar", 
                       "Apr", "May", "June", "July", 
                       "Aug", "Sept", "Oct", 
                       "Nov", "Dec"};
    
    /*
    daysPerMonth[0] = non leap year
    daysPerMonth[1] = leap year
    */
    int daysPerMonth[2][13] = {{-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                               {-1, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
    
    typedef struct _d {
        int day;        /* 1 to 31 */
        int month;      /* 1 to 12 */
        int year;       /* any */
    }dt;
    
    void print_dt(dt d)
    {
        printf("%d %s %d \n", d.day, month[d.month], d.year);
        return;
    }
    
    int leap(int year)
    {
        return ((year % 4 == 0 && year % 100 != 0) || year % 400 ==0) ? 1 : 0;
    }
    
    int minus(dt d1, dt d2)
    {
        int d1_l = leap(d1.year), d2_l = leap(d2.year);
        int y, m;
        int total_days = 0;
    
        for (y = d1.year; y >= d2.year ; y--) {
            if (y == d1.year) {
                for (m = d1.month ; m >= 1 ; m--) {
                    if (m == d1.month)  total_days += d1.day;
                    else                total_days += daysPerMonth[leap(y)][m];
                    // printf("%d - %5s - %d - %d \n", y, month[m], daysPerMonth[leap(y)][m], total_days);
                }
            } else if (y == d2.year) {
                for (m = 12 ; m >= d2.month ; m--) {
                    if (m == d2.month)  total_days += daysPerMonth[leap(y)][m] - d2.day;
                    else                total_days += daysPerMonth[leap(y)][m];
                    // printf("%d - %5s - %d - %d \n", y, month[m], daysPerMonth[leap(y)][m], total_days);
                }
            } else {
                for (m = 12 ; m >= 1 ; m--) {
                    total_days += daysPerMonth[leap(y)][m];
                    // printf("%d - %5s - %d - %d \n", y, month[m], daysPerMonth[leap(y)][m], total_days);
                }
            }
    
        }
    
        return total_days;
    }
    
    int main(void)
    {
        /* 28 Oct 2018 */
        dt d2 = {28, 10, 2018};
    
        /* 30 June 2006 */
        dt d1 = {30, 6, 2006};
    
        int days; 
    
        int d1_pt = 0, d2_pt = 0;
    
        if (d1.year  > d2.year)     d1_pt += 100;
        else                        d2_pt += 100;
        if (d1.month > d2.month)    d1_pt += 10;
        else                        d2_pt += 10;
        if (d1.day   > d2.day)      d1_pt += 1;
        else                        d2_pt += 1;
    
        days = (d1_pt > d2_pt) ? minus(d1, d2) : minus(d2, d1);
    
        print_dt(d1);
        print_dt(d2);
        printf("number of days: %d \n", days);
    
        return 0;
    }
    

    The output is as follows:

    $ gcc dates.c 
    $ ./a.out 
    30 June 2006 
    28 Oct 2018 
    number of days: 4503 
    $ 
    

    Note: this is not a complete program. It lacks input validation.

    Hope it helps!

    0 讨论(0)
  • 2021-01-02 18:37

    Reduce all month indexes by 1.

    What I mean to say is January will correspond to daysPerMonth[0] or daysPerMonthLeap[0] and not daysPerMonth[1] or daysPerMonthLeap[1]. The reason for this being array indexes start from 0.

    So, wherever you are using month1, month2 insidedaysPerMonth[] or daysPerMonthLeap[], use month1-1 and month2-1 instead.

    I hope this is clear enough. Otherwise, feel free to comment.

    0 讨论(0)
  • 2021-01-02 18:41
    //Difference/Duration between two dates
    //No need to calculate leap year offset or anything
    // Author: Vinay Kaple
    # include <iostream>
    using namespace std;
    int main(int argc, char const *argv[])
    {
        int days_add, days_sub, c_date, c_month, b_date, b_month, c_year, b_year;
        cout<<"Current Date(dd mm yyyy): ";
        cin>>c_date>>c_month>>c_year;
        cout<<"Birth Date(dd mm yyyy): ";
        cin>>b_date>>b_month>>b_year;
        int offset_month[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
        days_add = c_date + offset_month[c_month-1];
        days_sub = b_date + offset_month[b_month-1];
        int total_days = (c_year-b_year)*365.2422 + days_add - days_sub+1;
        cout<<"Total days: "<<total_days<<"\n";
        int total_seconds = total_days*24*60*60;
        cout<<"Total seconds: "<<total_seconds<<"\n";
        return 0;
    }
    
    0 讨论(0)
  • 2021-01-02 18:46

    First, that leap function feels overly complicated; you don't need to do both dates in one function call, and I'm sure that can be written more succinctly so that it is more obviously correct. Here's a version I've got laying around that isn't succinct but I'm confident it is easy to check the logic:

    int is_leap_year(int year) {
            if (year % 400 == 0) {
                    return 1;
            } else if (year % 100 == 0) {
                    return 0;
            } else if (year % 4 == 0) {
                    return 1;
            } else {
                    return 0;
            }
    }
    

    You could call it like this:

    int year1, year2, leap1, leap2;
    year1 = get_input();
    year2 = get_input();
    leap1 = is_leap_year(year1);
    leap2 = is_leap_year(year2);
    

    No pointers and significantly less code duplication. Yes, I know that is_leap_year() can be reduced to a single if(...) statement, but this is easy for me to read.

    Second, I think you're got a mismatch between 0-indexed arrays and 1-indexed human months:

                if(*month1 < 1 || *month1 > 12)
    

    vs

        int daysPerMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
    

    Third, I think that days per month can be calculated slightly nicer:

    int days_in_month(int month, int year) {
            int leap = is_leap_year(year);
            /*               J   F   M   A   M   J   J   A   S   O   N   D */
            int days[2][12] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                               {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
            if (month < 0 || month > 11 || year < 1753)
                    return -1;
    
            return days[leap][month];
    }
    

    Here, I assume January is 0; you would need to force the rest of the code to match. (I learned this double-array trick from The Elements of Programming Style (page 54).) The best part of using a routine like this is that it removes the leap condition from the difference calculation.

    Fourth, you're indexing arrays outside their bounds:

                for(i = month1 + 1; i <= 12; i++)
                {
                    if(leap1 == 1)
                        total += daysPerMonthLeap[i];
    

    This is just another instance of the problem with 0-indexed arrays and 1-indexed months -- but be sure that you fix this, too, when you fix the months.

    I have a fear that I haven't yet found all the issues -- you may find it easier to sort the first and the second date after input and remove all that validation code -- and then use names before and after or something to give names that are easier to think through in the complicated core of the calculation.

    0 讨论(0)
  • 2021-01-02 18:49

    This is not a complete answer. I just wanted to mention a better way to calculate leap year (this is taken from The C Programming Language - Page #41)

    if ((year % 4 == 0 && year % 100 != 0) || year % 400 ==0)
        printf("%d is a leap year \n", year);
    else
        printf("%d is not a leap year \n", year);
    
    0 讨论(0)
  • 2021-01-02 18:55

    Change

    int daysPerMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
    int daysPerMonthLeap[] = {31,29,31,30,31,30,31,31,30,31,30,31};
    

    to

    int daysPerMonth[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int daysPerMonthLeap[] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
    

    i.e. pad the arrays at the beginning since all the code relies on the array values to start at element 1 rather than element 0.

    That will get rid of the error you complained of.

    The other problem is an off-by-one error when you add day2 to the total. In both cases you should add day2 - 1 rather than day2. This is also due to the date indexes starting at 1 instead of 0.

    After I made these changes (plus a couple just to get the code to compile), it works properly.

    0 讨论(0)
提交回复
热议问题