简体   繁体   English

两个日期之间的C程序天数

[英]C program days between two dates

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 I'm assuming I have some syntax errors that I keep glancing over or something. 当我阅读它时,逻辑在我的头脑中非常有意义,所以我假设我有一些语法错误,我一直在看一看或者什么。

Firstly, when entering two dates in different years, the output is always off by about one month (31 in most cases, but 32 in one case...go figure). 首先,当在不同年份输入两个日期时,输出总是关闭大约一个月(在大多数情况下为31,但在一种情况下为32 ......去图)。 Second, two dates exactly one month apart will return the number of days in the second month (ie 1/1/1 to 2/1/1 yields 28). 第二,相隔一个月的两个日期将返回第二个月的天数(即1/1/1到2/1/1的收益率28)。 There are inevitably some other weird things that this program does, but I am hoping that is enough information to help you guys figure out what I'm doing wrong. 这个程序不可避免地会有一些其他奇怪的东西,但是我希望这些信息可以帮助你们弄清楚我做错了什么。 For the life of me I can't figure this one out on my own. 对于我的生活,我无法独自思考这一点。 I am relatively new to C, so please be gentle =) 我对C比较新,所以请温柔=)

Thanks 谢谢

// Calculates the number of calendar days between any two dates in history (beginning with 1/1/1).

#include <stdio.h>
#include <stdlib.h>

void leap(int year1, int year2, int *leap1, int *leap2);
void date(int *month1, int *day1, int *year1, int *month2, int *day2, int *year2, int *leap1, int *leap2);

int main(void)
{
        int month1, day1, year1, month2, day2, year2, leap1, leap2;
        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};

        leap(year1, year2, &leap1, &leap2);
        date(&month1, &day1, &year1, &month2, &day2, &year2, &leap1, &leap2);

        if(year1 == year2)
        {
                int i, total;

                if(month1 == month2)                            // Total days if month1 == month2
                {
                        total = day2 - day1;
                        printf("There are %d days between the two dates.", total);
                }
                else
                {
                    if(leap1 == 1)
                        total = daysPerMonthLeap[month1] - day1;
                    else
                        total = daysPerMonth[month1] - day1;

                    for(i = month1 + 1; i < month2; i++)        // Days remaining between dates (excluding last month)
                    {
                        if(leap1 == 1)
                            total += daysPerMonthLeap[i];
                        else
                            total += daysPerMonth[i];
                    }

                    total += day2;                              // Final sum of days between dates (including last month)

                    printf("There are %d days between the two dates.", total);
                }
        }
        else                                                    // If year1 != year2 ...
        {
                int i, total, century1 = ((year1 / 100) + 1) * 100, falseleap = 0;

                if(leap1 == 1)
                    total = daysPerMonthLeap[month1] - day1;
                else
                    total = daysPerMonth[month1] - day1;

                for(i = month1 + 1; i <= 12; i++)               // Day remaining in first year
                {
                    if(leap1 == 1)
                        total += daysPerMonthLeap[i];
                    else
                        total += daysPerMonth[i];
                }

                for(i = 1; i < month2; i++)                     // Days remaining in final year (excluding last month)
                {
                    if(leap2 == 1)
                        total += daysPerMonthLeap[i];
                    else
                        total += daysPerMonth[i];
                }

                int leapcount1 = year1 / 4;                     // Leap years prior to and including first year
                int leapcount2 = year2 / 4;                     // Leap years prior to and NOT including final year
                if(year2 % 4 == 0)
                        leapcount2 -= 1;

                int leaptotal = leapcount2 - leapcount1;        // Leap years between dates

                for(i = century1; i < year2; i += 100)          // "False" leap years (divisible by 100 but not 400)
                {
                        if((i % 400) != 0)
                                falseleap += 1;
                }

                total += 365 * (year2 - year1 - 1) + day2 + leaptotal - falseleap;      // Final calculation
                printf("There are %d days between the two dates.", total);
        }
        return 0;
}

void leap(int year1, int year2, int *leap1, int *leap2)             // Determines if first and final years are leap years
{
        if(year1 % 4 == 0)
        {
                if(year1 % 100 == 0)
                {
                        if(year1 % 400 == 0)
                                *leap1 = 1;
                        else
                                *leap1 = 0;
                }
                else
                        *leap1 = 1;
        }
        else
                *leap1 = 0;

        if(year2 % 4 == 0)
        {
                if(year2 % 100 == 0)
                {
                        if(year2 % 400 == 0)
                                *leap2 = 1;
                        else
                                *leap2 = 0;
                                }
                else
                        *leap2 = 1;
        }
        else
                *leap2 = 0;
}

void date(int *month1, int *day1, int *year1, int *month2, int *day2, int *year2, int *leap1, int *leap2)
{
        for(;;)                     // Infinite loop (exited upon valid input)
        {
                int fail = 0;
                printf("\nEnter first date: ");
                scanf("%d/%d/%d", month1, day1, year1);
                if(*month1 < 1 || *month1 > 12)
                {
                        printf("Invalid entry for month.\n");
                        fail += 1;
                }
                if(*day1 < 1 || *day1 > 31)
                {
                        printf("Invalid entry for day.\n");
                        fail += 1;
                }
                if(*year1 < 1)
                {
                        printf("Invalid entry for year.\n");
                        fail += 1;
                }
                if(daysPerMonth[month1] == 30 && *day1 > 30)
                {
                        printf("Invalid month and day combination.\n");
                        fail += 1;
                }
                if(*month1 == 2)
                {
                        if(*leap1 == 1 && *day1 > 29)
                        {
                            printf("Invalid month and day combination.\n");
                            fail += 1;
                        }
                        else if(*day1 > 28)
                        {
                            printf("Invalid month and day combination.\n");
                            fail += 1;
                        }
                }
                if(fail > 0)
                        continue;
                else
                        break;
        }

        for(;;)
        {
                int fail = 0;
                printf("\nEnter second date: ");
                scanf("%d/%d/%d", month2, day2, year2);
                if(*year1 == *year2)
                {
                        if(*month1 > *month2)
                        {
                                printf("Invalid entry.\n");
                                fail += 1;
                        }
                        if(*month1 == *month2 && *day1 > *day2)
                        {
                                printf("Invalid entry.\n");
                                fail += 1;
                        }
                }
                if(*month2 < 1 || *month2 > 12)
                {
                        printf("Invalid entry for month.\n");
                        fail += 1;
                }
                if(*day2 < 1 || *day2 > 31)
                {
                        printf("Invalid entry for day.\n");
                        fail += 1;
                }
                if(*year2 < 1)
                {
                        printf("Invalid entry for year.\n");
                        fail += 1;
                }
                if(daysPerMonth[month2] == 30 && *day2 > 30)
                {
                        printf("Invalid month and day combination.\n");
                        fail += 1;
                }
                if(*month2 == 2)
                {
                        if(*leap2 == 1 && *day2 > 29)
                        {
                            printf("Invalid month and day combination.\n");
                            fail += 1;
                        }
                        else if(*day2 > 28)
                        {
                            printf("Invalid month and day combination.\n");
                            fail += 1;
                        }
                }
                if(fail > 0)
                        continue;
                else
                        break;
        }
}

First, that leap function feels overly complicated; 首先, leap功能感觉过于复杂; 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. 是的,我知道is_leap_year()可以简化为单个if(...)语句,但这对我来说很容易阅读。

Second, I think you're got a mismatch between 0-indexed arrays and 1-indexed human months: 其次,我认为你在0索引数组和1索引人类月份之间存在不匹配:

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

vs 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; 在这里,我假设1月是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. (我从编程风格元素第54页 )中学到了这个双阵列技巧。)使用这样的例程的最佳部分是它从差异计算中删除了跳跃条件。

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. 这只是0索引数组和1索引月数问题的另一个实例 - 但是当你修复月份时,请确保你也解决了这个问题。

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. 我担心我还没有找到所有问题 - 你可能会发现输入后第一个和第二个日期排序更容易并删除所有验证代码 - 然后使用beforeafter名称或者给出一些东西来给出在复杂的计算核心中更容易思考的名称。

Reduce all month indexes by 1. 将所有月份索引减少1。

What I mean to say is January will correspond to daysPerMonth[0] or daysPerMonthLeap[0] and not daysPerMonth[1] or daysPerMonthLeap[1] . 我的意思是1月将对应于daysPerMonth[0]daysPerMonthLeap[0]而不是daysPerMonth[1]daysPerMonthLeap[1] The reason for this being array indexes start from 0. 这是数组索引从0开始的原因。

So, wherever you are using month1 , month2 inside daysPerMonth[] or daysPerMonthLeap[] , use month1-1 and month2-1 instead. 所以,无论你正在使用month1month2daysPerMonth[]daysPerMonthLeap[]使用month1-1month2-1代替。

I hope this is clear enough. 我希望这很清楚。 Otherwise, feel free to comment. 否则,请随时发表评论。

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) 我只想提一个更好的计算闰年的方法(这取自The C Programming Language - 第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);

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};

ie pad the arrays at the beginning since all the code relies on the array values to start at element 1 rather than element 0. 即在开头填充数组,因为所有代码都依赖于数组值从元素1而不是元素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. 另一个问题是当你将day2添加到总数时会出现一个错误。 In both cases you should add day2 - 1 rather than day2 . 在这两种情况下,您都应该添加day2 - 1而不是day2 This is also due to the date indexes starting at 1 instead of 0. 这也是由于日期索引从1而不是0开始。

After I made these changes (plus a couple just to get the code to compile), it works properly. 在我做了这些更改(加上一对只是为了让代码编译)之后,它正常工作。

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! 希望能帮助到你!

//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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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