【问题标题】:C program days between two dates两个日期之间的 C 程序天数
【发布时间】:2012-04-25 03:48:48
【问题描述】:

我编写了一个程序,应该找到两个日期之间的天数,但它有一些小问题。当我通读它时,这个逻辑在我的脑海中非常有意义,所以我假设我有一些语法错误,我一直在看或者其他什么。

首先,当输入两个不同年份的日期时,输出总是关闭大约一个月(大多数情况下为 31,但在一种情况下为 32...看图)。其次,两个恰好相隔一个月的日期将返回第二个月的天数(即 1/1/1 到 2/1/1 产生 28)。该程序不可避免地会发生其他一些奇怪的事情,但我希望这些信息足以帮助你们找出我做错了什么。对于我的一生,我无法独自解决这个问题。我对C比较陌生,所以请温柔=)

谢谢

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

【问题讨论】:

  • @mkoryak,也许,这是一个足够好的学习问题......
  • 对于 month1 = 1,您的代码中是 1 月还是 2 月(基于 daysPerMonth 数组)?我认为这是您的代码中的问题之一。您可以在两个数组中添加一个元素 = 0,或者在进行计算时将月份减 1。
  • 请注意,您可能应该在1752 处截断最早的日期;或者1923,如果你想让它对整个欧洲都有好处......
  • @Andbrik:如果您的问题已完全解决,请将其中一个答案标记为“已接受”。
  • @Andbrik 如果您认为我的回答有帮助,请随时投票并选择我的帖子作为答案。谢谢!

标签: c


【解决方案1】:

首先,leap 函数感觉过于复杂;您不需要在一个函数调用中同时执行两个日期,我相信可以更简洁地编写它,以便它更明显正确。这是一个我已经准备好的版本,它并不简洁,但我相信它很容易检查逻辑:

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

你可以这样称呼它:

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

没有指针,代码重复更少。是的,我知道is_leap_year() 可以简化为单个if(...) 语句,但这对我来说很容易阅读。

其次,我认为您在 0 索引数组和 1 索引人类月份之间存在不匹配:

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

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

第三,我认为每月的天数可以计算得稍微好一点:

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

在这里,我假设一月是 0;您需要强制其余代码匹配。 (我从The Elements of Programming Style (page 54) 那里学到了这个双数组技巧。)使用这样的例程最好的部分是它从差异计算中删除了跳跃条件。

第四,您正在对超出范围的数组进行索引:

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

这只是 0 索引数组和 1 索引月份问题的另一个实例 - 但请确保在修复月份时也修复 this

我担心我还没有找到所有问题——您可能会发现在输入后排序第一个和第二个日期并删除所有验证码更容易——并且然后使用名称beforeafter 或其他名称,以便在复杂的计算核心中给出更容易思考的名称。

【讨论】:

  • 不错的风格参考——您是否还建议在年份相等时去掉单独的“if”块?一般解决方案应该处理这种情况
  • 感谢您的帮助。事实证明,我的数组索引是唯一让我搞砸facepalm 的事情。现在效果很好!
  • @Andbrik:虽然数组索引是唯一的问题,但请务必考虑 sarnold 的建议,以使您的程序高效而简短。
  • is_leap_year() 函数可以简化为单个return,不需要if。 :) 只是指出这一点,我知道它已针对可读性进行了优化。
  • 你可以去掉整个 daysPerMonthLeap[] 数组,方法是将 returnis_leap_year() 添加到对应于二月的日期。
【解决方案2】:

这不是一个完整的答案。我只是想提一个更好的计算闰年的方法(取自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);

【讨论】:

    【解决方案3】:

    将所有月份索引减少 1。

    我的意思是一月将对应于daysPerMonth[0]daysPerMonthLeap[0] 而不是daysPerMonth[1]daysPerMonthLeap[1]。 这是数组索引的原因是从0开始的。

    因此,无论您使用month1month2 insidedaysPerMonth[]daysPerMonthLeap[],请改用month1-1month2-1

    我希望这已经足够清楚了。 否则,请随时发表评论。

    【讨论】:

      【解决方案4】:

      改变

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

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

      即在开头填充数组,因为所有代码都依赖于数组值从元素 1 而不是元素 0 开始。

      这将消除您抱怨的错误。

      另一个问题是当您将day2 添加到总数时出现一个错误。在这两种情况下,您都应该添加day2 - 1 而不是day2。这也是由于日期索引从 1 而不是 0 开始的。

      在我进行了这些更改(加上一些只是为了让代码编译)之后,它可以正常工作。

      【讨论】:

      • 关于第 2 天和第 2-1 天的事情:第 2-1 天将给出这两个日期之间的天数(均不包括在内)。但是,当我们通常计算 2 个日期之间的天数时,习惯上包括任一天。例如5 月 4 日和 5 月 1 日之间的差异被视为 3 天......不是 2 天......
      • 这是day2 - day1 的情况,其中的日子在同一个月。要更改的两个任务是添加第 2 天而没有从中减去第 1 天的任务。
      【解决方案5】:

      你的代码 sn-p.. 有多个问题,但我必须说这是一个非常好的尝试。您尝试实现的目标有很多捷径。

      我编写了以下程序,它可以找到两个给定日期之间的天数。您可以将此作为参考。

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

      输出如下:

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

      注意:这不是一个完整的程序。它缺乏输入验证。

      希望对你有帮助!

      【讨论】:

      【解决方案6】:
      //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;
      }
      

      【讨论】:

      • 请分享一些关于代码 sn-p 的信息,而不仅仅是粘贴代码。
      猜你喜欢
      • 2012-12-22
      • 1970-01-01
      • 2014-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      相关资源
      最近更新 更多