【问题标题】:Determining the difference between dates确定日期之间的差异
【发布时间】:2012-04-16 18:29:34
【问题描述】:

我正在尝试找出一种方法让我的程序获取一个日期(如 2003 年 2 月 2 日),并用另一个日期(如 2012 年 4 月 2 日)显示两者之间的差异,不包括闰年。到目前为止,我只能通过减去“天”来确定日期是否在同一个月内。在这个程序中,我使用 2 组“月”、“日”和“年”整数。我几乎不知道从哪里去。这是我的任务的一个完全可选的部分,但我想知道如何让它工作。这对我来说似乎很麻烦,但也许我没有考虑一个简单的数学公式?

抱歉,这部分我没有任何预先存在的代码,因为剩下的作业只涉及让用户输入日期,然后加减一天。

【问题讨论】:

    标签: c++ visual-studio visual-studio-2010 visual-c++


    【解决方案1】:

    我做了类似的程序,但它只计算一年或几年边界内的天数

    PS 我在 C++ 编程只有两个月左右

        #include<iostream>
    
        int calculateDaysInYears(int intYear, int endYear);
        int checkYear(int intYear);
        int checkMonth(int i, int intYear);
    
        int getUserData()
    {
        int dayOrMonthOrYear;
        std::cin >> dayOrMonthOrYear;
        return dayOrMonthOrYear;
    }
        int calculateMonthInYears(int initialMonth, int endMonth, int initialYear)
    {
        //Подсчет дней начальной даты для варианта с несколькими годами
        int x(0);
    
        initialMonth++;
    
        for (int i = initialMonth; i <= endMonth; i++)
            x += checkMonth(i, initialYear);
    
        return x;
    }
        int calculateMonth(int startMonth, int endMonth, int initialYear)
    {
        //Формула для подсчета кол-вa дней промежуточных месяцев
        //Расчет в пределах года
        
        startMonth++;
    
        int x(0);
    
        for (int i = startMonth; i < endMonth; i++)
    
            x += checkMonth(i, initialYear);
    
        return x;
    }
        int calculateMonthForEndYear(int endMonth, int endYear)
    {
        //Подсчет дней в конечном году
        int x(0);
    
        //Декремент кол-ва конечных месяцев для компенсации дней последнего месяца
        --endMonth;
    
        for (int i = 1; i <= endMonth; i++)
            x += checkMonth(i, endYear);
    
        return x;
    }
        int checkMonth(int i, int intYear)
    {
            if (i == 1 || i == 3 || i == 5 || i == 7 || i == 8 || i == 10 || i == 12)
                return 31;
            else 
                if (i == 2)
                {
                    //Если год високосный, то делится на 4 и 400 без остатка, а на 100 с остатком
                    if ((intYear % 4 == 0) && (intYear % 100 != 0 ) || (intYear % 400 == 0))
                        return 29;                                                  
                    else
                        return 28;
                }
            else
                return 30;
    
    }
        int calculateAmountOfDays(int initialDay, int initialMonth, int initialYear)
    {
        //Подсчет дней до конца стартового месяца
        int month = checkMonth(initialMonth, initialYear);
        int days = month - initialDay;
        return days;
    }
        int allDays(int initilDays, int endDays, int midleMonth)
    {
        int totalDays;
        
        //Подсчет всех дней от начала до конца
        totalDays = midleMonth + initilDays + endDays;
        return totalDays;
    }
        int checkYear(int intYear)
    {
        if ((intYear % 4 == 0) && (intYear % 100 != 0) || (intYear % 400 == 0))
            return 366;//Високосный год
        else
            return 365;//Невисокосный год
    }
        int calculateDaysInYears(int intYear, int endYear)
    {
        //Начальное кол-во дней. Необходимо для запуска счетчика
        int amountDays(0);
    
        //Инкремент начального года для компенсации кол-ва дней промежуточных годов
        intYear++;
    
        for (int i = intYear; i < endYear; i++)
            amountDays += checkYear(i);
    
        return amountDays;
    }
        int main()
    {
        int initialDay;
        int initialMonth;
        int initialYear;
        int endDay;
        int endMonth;
        int endYear;
    
        std::cout << "Hello! I'm your calendar calculator."            << std::endl <<
                     "Here some rules: "                               << std::endl << 
                     "you should enter a data like(d.m.y): 23.8.2020." << std::endl <<
                     "Also you can ask me to calculate for couple years or in border of one year. Good luck! " << std::endl;
    
        std::cout << "" << std::endl;
    
        //Начальная дата
        std::cout << "Enter an initial day: ";
        initialDay = getUserData();
    
        std::cout << "Enter an initial month: ";
        initialMonth = getUserData();
    
        std::cout << "Enter an initial year: ";
        initialYear = getUserData();
    
        std::cout << "" << std::endl;//Пропуск строки
    
        //Конечная дата
        std::cout << "Enter an end day: ";
        endDay = getUserData();
    
        std::cout << "Enter an end month: ";
        endMonth = getUserData();
    
        std::cout << "Enter an end year: ";
        endYear = getUserData();
    
        //Проверка кол-ва годов
        if ((endYear - initialYear) >= 1)
        {
            //Подсчет дней до конца начального года
            int daysToTheEndOfStartYear = calculateMonthInYears(initialMonth, 12, initialYear) + calculateAmountOfDays(initialDay, initialMonth, initialYear);
    
            //Подсчет дней до конца конечного месяца
            int daysToTheEndOfEndYear = calculateMonthForEndYear(endMonth, endYear) + endDay;
    
            //Подсчет дней между годами
            int whalDays = calculateDaysInYears(initialYear, endYear);
    
            //Подсчет конечной цыфры
            int allDay = whalDays + daysToTheEndOfEndYear + daysToTheEndOfStartYear;
    
            //Вывод в консоль
            std::cout << allDay;
        }
        else
        {
            //Дни месяцев между начальным и конечным месяцами
            int daysInMonths = calculateMonth(initialMonth, endMonth, initialYear);
    
            //Подсчет дней до конца начального месяца
            int daysInFirstMonth = calculateAmountOfDays(initialDay, initialMonth, initialYear);
    
            //Подсчет конечной цыфры
            int allDay = daysInMonths + daysInFirstMonth + endDay;
    
            //Вывод в консоль
            std::cout << allDay;
        }
        return 0;
    }
    

    【讨论】:

      【解决方案2】:

      这是计算 y/m/d 日期差的完整代码。

      假设 tofromdate 类型,并且月和日从 1 开始(类似到 Qt):

      static int increment[12] = { 1, -2, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1 };
      
      int daysInc = 0;
      if (to.day() - from.day() < 0)
      {
          int month = to.month() - 2; // -1 from zero, -1 previous month.
          if (month < 0)
              month = 11; // Previous month is December.
          daysInc = increment[month];
          if ( (month == 1) && (to.year()%4 == 0) )
              daysInc++; // Increment days for leap year.
      }
      
      int total1 = from.year()*360 + from.month()*30 + from.day();
      int total2 = to.year()*360 + to.month()*30 + to.day();
      int diff = total2 - total1;
      int years = diff/360;
      int months = (diff - years*360)/30;
      int days = diff - years*360 - months*30 + daysInc;
      
      // Extra calculation when we can pass one month instead of 30 days.
      if (from.day() == 1 && to.day() == 31) {
          months--;
          days = 30;
      }
      

      我试过这个算法,它工作正常。如果您在使用/理解时遇到问题,请告诉我。

      【讨论】:

        【解决方案3】:

        旧问题的新答案:

        chrono-Compatible Low-Level Date Algorithms

        具有将 {year,month,day} 三元组转换为连续天数并返回的公式。您可以使用它来计算两个日期之间的天数,如下所示:

        std::cout << days_from_civil(2012, 4, 2) - days_from_civil(2003, 2, 2) << '\n';
        

        哪个输出:

        3347
        

        本文是操作手册,而不是图书馆。它使用 C++14 来演示公式。每个公式都带有详细的描述和推导,只有在您关心了解公式的工作原理时才需要阅读。

        这些公式非常有效,并且在非常大的范围内有效。例如使用 32 位算术,+/- 500 万年(绰绰有余)。

        连续天数是自 1970 年新年以来(或之前)的天数,使公式与 Unix Time 和所有已知的 std::chrono::system_clock 实现兼容。

        days_from_civil 算法并不新颖,它应该看起来与其他算法非常相似,可以做同样的事情。但反过来说,从天数回到 {year,month,day} 三元组就比较棘手了。这是civil_from_days 记录的公式,我还没有见过像这个一样紧凑的其他公式。

        该论文包括显示 typical computationsstd::chrono interoperability 和广泛的 unit tests 的示例使用,证明了 +/- 100 万年的正确性(使用 proleptic Gregorian calendar)。

        所有的公式和软件都在公共领域。

        【讨论】:

          【解决方案4】:

          还有另一种方式...

          • 给定两个日期,取较早日期的年份作为参考年份
          • 然后计算否。两个给定日期与 1/1/
          • 之间的天数
          • 保留一个单独的函数,用于告知特定月份已过去的天数。
          • 这两个的绝对差异没有。 of days 将给出两个给定日期之间的差异。
          • 另外,不要忘记考虑闰年

          代码:

          #‎include‬<stdio.h>
          #include<math.h>
          typedef struct
          {
              int d, m, y;
          } Date;
          int isLeap (int y)
          {
              return (y % 4 == 0) && ( y % 100 != 0) || (y % 400 == 0);
          }
          int diff (Date d1, Date d2)                         //logic here!
          {
              int dd1 = 0, dd2 = 0, y, yref;                  //dd1 and dd2 store the <i>no. of days</i> between d1, d2 and the reference year
              yref = (d1.y < d2.y)? d1.y: d2.y;               //that <b>reference year</b>
              for (y = yref; y < d1.y; y++)
                  if (isLeap(y))                              //check if there is any leap year between the reference year and d1's year (exclusive)
                      dd1++;
              if (isLeap(d1.y) && d1.m > 2) dd1++;                //add another day if the date is past a leap year's February
              dd1 += daysTill(d1.m) + d1.d + (d1.y - yref) * 365;     //sum up all the tiny bits (days)
              for (y = yref; y < d2.y; y++)                       //repeat for d2
                  if(isLeap(y))
                      dd2++;
              if (isLeap(y) && d2.m > 2) dd2++;
              dd2 += daysTill(d2.m) + d2.d + (d2.y - yref) * 365;
              return abs(dd2 - dd1);                          //return the absolute difference between the two <i>no. of days elapsed past the reference year</i>
          }
          int daysTill (int month)                            //some logic here too!!
          {
              int days = 0;
              switch (month)
              {
                  case 1: days = 0;
                  break;
                  case 2: days = 31;
                  break;
                  case 3: days = 59;
                  break;
                  case 4: days = 90;      //number of days elapsed before April in a non-leap year
                  break;
                  case 5: days = 120;
                  break;
                  case 6: days = 151;
                  break;
                  case 7: days = 181;
                  break;
                  case 8: days = 212;
                  break;
                  case 9: days = 243;
                  break;
                  case 10:days = 273;
                  break;
                  case 11:days = 304;
                  break;
                  case 12:days = 334;
                  break;
              }
              return days;
          }
          main()
          {
              int t;          //no. of test cases
              Date d1, d2;    //d1 is the first date, d2 is the second one! obvious, duh!?
              scanf ("%d", &t);
              while (t--)
              {
                  scanf ("%d %d %d", &d1.d, &d1.m, &d1.y);
                  scanf ("%d %d %d", &d2.d, &d2.m, &d2.y);
                  printf ("%d\n", diff(d1, d2));
              }
          }
          

          标准输入:

          1
          23 9 1960
          11 3 2015
          

          标准输出:

          19892
          

          实际代码:https://ideone.com/RrADFR

          始终欢迎更好的算法、优化和编辑!

          【讨论】:

            【解决方案5】:

            由于您正在寻找数学公式,它将帮助您找到解决问题的方法。设 Y 为年,M 为月,D 为日。对两个日期都进行此计算。

            Total = Y* 365 + M*30 + D ,然后求对应日期的2个总和之间的差。

            在将 30 乘以 M 值时,您必须给出该月的天数。您可以使用 #define 值或 if 循环来完成。同样,您也可以通过将 366 与 Y 相乘来为闰年做。

            希望对你有所帮助....

            【讨论】:

            • 很好的答案,但不完整,所以我在下面添加完整的代码。
            【解决方案6】:

            仅使用标准库,您可以将一个适度疯狂的日期结构转换为从任意零点开始的秒数;然后减去并转换为天数:

            #include <ctime>
            
            // Make a tm structure representing this date
            std::tm make_tm(int year, int month, int day)
            {
                std::tm tm = {0};
                tm.tm_year = year - 1900; // years count from 1900
                tm.tm_mon = month - 1;    // months count from January=0
                tm.tm_mday = day;         // days count from 1
                return tm;
            }
            
            // Structures representing the two dates
            std::tm tm1 = make_tm(2012,4,2);    // April 2nd, 2012
            std::tm tm2 = make_tm(2003,2,2);    // February 2nd, 2003
            
            // Arithmetic time values.
            // On a posix system, these are seconds since 1970-01-01 00:00:00 UTC
            std::time_t time1 = std::mktime(&tm1);
            std::time_t time2 = std::mktime(&tm2);
            
            // Divide by the number of seconds in a day
            const int seconds_per_day = 60*60*24;
            std::time_t difference = (time1 - time2) / seconds_per_day;    
            
            // To be fully portable, we shouldn't assume that these are Unix time;
            // instead, we should use "difftime" to give the difference in seconds:
            double portable_difference = std::difftime(time1, time2) / seconds_per_day;
            

            使用 Boost.Date_Time 就不那么奇怪了:

            #include "boost/date_time/gregorian/gregorian_types.hpp"
            
            using namespace boost::gregorian;
            date date1(2012, Apr, 2);
            date date2(2003, Feb, 2);
            long difference = (date1 - date2).days();
            

            这对我来说似乎很麻烦,但也许我没有考虑一个简单的数学公式?

            确实比较麻烦,不过有formula,要自己算的话。

            【讨论】:

            • 只是一点点(因为我不知道任何平台会失败),但标准没有说明time_t 中的时间表示,或者减去@ 987654325@会给你。你应该使用difftime(它返回一个double,它引入了自己的一系列问题)。
            • @JamesKanze:好点; POSIX 指定它是秒计数,但 C 将其保留为实现定义。
            • 值得一提的是,这个解决方案即使跨 DST 边界也能正常工作,因为 make_tm() 没有设置 tm_isdst 所以 mktime() 将表现得好像 DST 不存在并且一天将永远存在成为60*60*24 秒。
            【解决方案7】:

            我不确定你在哪个平台上?窗户,Linux?但是让我们假设您想要一个独立于平台的解决方案,并且语言是标准 C++。

            如果您可以使用库,则可以使用 Boost::Date_Time 库 (http://www.boost.org/doc/libs/1_49_0/doc/html/date_time.html)

            如果你不能使用库来解决你的任务,你需要找到一个共同的简单基础。也许您可以将所有日期转换为秒,或者将日期减去它们,然后再次将其转换回数据。将天数或月数减去整数将无济于事,因为它会导致不正确的结果,除非您不考虑其余部分。 希望对您有所帮助。

            就像 dbrank0 指出的那样。 :)

            【讨论】:

              【解决方案8】:

              如果您需要自己做,那么一种非常简单的方法是将日期转换为Julian Day。您可以在该链接获得公式,从转换开始,您只能使用浮点数,其中每天为 1 个单位。

              【讨论】:

                【解决方案9】:

                您应该查看DateTime 类。

                还有用于 C++ 语法的 msdn reference

                【讨论】:

                  猜你喜欢
                  • 2020-11-19
                  • 1970-01-01
                  • 2011-02-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-02-04
                  • 2014-04-21
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多