C++ 确定日期之间的差异

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9987562/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:29:19  来源:igfitidea点击:

Determining the difference between dates

c++visual-studiovisual-studio-2010visual-c++

提问by Hydlide

I'm trying to figure out a way for my program to take a date (like February 2nd, 2003) and show the difference between the two with another date (like April 2nd, 2012), excluding leap years. So far I've only been able to figure it out if the dates are in the same month, just by subtracting the "day". In this program I use 2 sets of "month", "day" and "year" integers. I'm pretty much at a loss from where to go from here. This is a completely optional part of my assignment but I'd like to get an idea on how to get it to work. It seems like a hassle to me, but maybe there's a simple math formula I'm not thinking about?

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

Sorry, I don't have any pre-existing code for this part because the rest of the assignment just deals with having the user enter dates and then adding and subtracting a single day.

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

采纳答案by Borzh

Here is a complete code to calculating date difference in y/m/d.

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

Assuming that toand fromare datetypes, and that months and days start from 1(similar to Qt):

假设tofrom日期类型,并且月份和日期从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;
}

I tried this algorithm and it is working okay. Let me know if you have troubles using/understanding it.

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

回答by Mike Seymour

Using just the standard library, you can convert a moderately insane date structure into a count of seconds since an arbitrary zero point; then subtract and convert into days:

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

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

Using Boost.Date_Time is a little less weird:

使用 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();

It seems like a hassle to me, but maybe there's a simple math formula I'm not thinking about?

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

It is indeed a hassle, but there is a formula, if you want to do the calculation yourself.

确实有点麻烦,但是有公式,如果你想自己做计算。

回答by Revathy

Since you are looking for mathematical formula , it will help you to find a solution to your problem. Let Y be the year,M be the month and D be the day. Do this calculation for both the dates.

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

Total = Y* 365 + M*30 + D ,then find the difference between 2 totals of the corresponding dates.

Total = Y* 365 + M*30 + D ,然后找出相应日期的 2 个总数之间的差值。

While multiplying 30 with M value ,you have to give the number of days in that month. You can do it with #define value or if loop. Similarly you can do for leap year too by multiplying 366 with Y .

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

Hope this will help u....

希望这会帮助你......

回答by Howard Hinnant

New answer for an old question:

旧问题的新答案:

chrono-Compatible Low-Level Date Algorithms

chrono- 兼容的低级日期算法

has formulas for converting a {year, month, day} triple to a serial count of days and back. You can use it to calculate the number of days between two dates like this:

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

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

which outputs:

输出:

3347

The paper is a how-to manual, not a library. It uses C++14 to demonstrate the formulas. Each formula comes with a detailed description and derivation, that you only have to read if you care about knowing how the formula works.

该论文是一本操作手册,而不是图书馆。它使用 C++14 来演示公式。每个公式都带有详细的说明和推导,只有在您关心公式的工作原理时才需要阅读这些内容。

The formulas are very efficient, and valid over an extremely large range. For example using 32 bit arithmetic, +/- 5 million years (more than enough).

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

The serial day count is a count of days since (or prior to for negative values) New Years 1970, making the formulas compatible with Unix Timeand all known implementations of std::chrono::system_clock.

连续日计数是自 1970 年新年以来(或之前为负值)的天数计数,使公式与Unix 时间和所有已知的std::chrono::system_clock.

The days_from_civilalgorithm is not novel, and it should look very similar to other algorithms for doing the same thing. But going the other way, from a count of days back to a {year, month, day} triple is trickier. This is the formula documented by civil_from_daysand I have not seen other formulations that are as compact as this one.

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

The paper includes example uses showing typical computations, std::chronointeroperability, and extensive unit testsdemonstrating the correctness over +/- 1 million years (using a proleptic Gregorian calendar).

该论文包括显示典型计算std::chrono互操作性和广泛单元测试的示例使用,证明了 +/- 100 万年的正确性(使用预测公历)。

All of the formulas and software are in the public domain.

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

回答by skrtbhtngr

There is another way round...

还有另一种方式...

  • Given two dates, take the year of the earlier date as the reference year.
  • Then calculate no. of daysbetween each of the two given dates and that 1/1/<that year>
  • Keep a separate function that tells the number of days elapsed till a specific month.
  • The absolute difference of those two no. of dayswill give the difference between the two given dates.
  • Also, do not forget to consider leap years!
  • 给定两个日期,取较早日期的年份作为参考年份
  • 然后计算没有。两个给定日期和 1/1/<那一年> 之间的天数
  • 保留一个单独的函数来告诉特定月份过去的天数。
  • 那两个没有的绝对区别天数将给出两个给定日期之间的差异。
  • 另外,不要忘记考虑闰年

The code:

编码:

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

Standard Input:

标准输入:

1
23 9 1960
11 3 2015

Standard Output:

标准输出:

19892

Code in action: https://ideone.com/RrADFR

行动代码:https: //ideone.com/RrADFR

Better algorithms, optimizations and edits are always welcome!

更好的算法、优化和编辑总是受欢迎的!

回答by ervinbosenbacher

I'm not sure what platform are you on? Windows, Linux? But let us pretend that you would like to have a platform independent solution and the langugage is standard C++.

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

If you can use libraries you can use the Boost::Date_Time library (http://www.boost.org/doc/libs/1_49_0/doc/html/date_time.html)

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

If you cannot use libraries to solve your assignment, you will need to find a common simple ground. Maybe you could convert all the dates to seconds, or days substract them and then convert that back to the data again. Substracting days or months as integers will not help as it will lead to incorrect results unless you do not take into account the rest. Hope that helps.

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

Like dbrank0 pointed it out. :)

就像 dbrank0 指出的那样。:)

回答by dbrank0

If you need to do it yourself, then one way to do this pretty easy is by converting dates into a Julian Day. You get formulas at that link, and from conversion on, you only work with floats, where each day is 1 unit.

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

回答by nikhil

You should look at the DateTimeclass.

您应该查看DateTime类。

Also the msdn referencefor C++ syntax.

还有C++ 语法的msdn 参考