2012-04-03 73 views
6

我想弄明白我的程序采取一个日期(如2003年2月2日)的方式,并显示两者之间的差异与另一个日期(如2012年4月2日),排除闰年。到目前为止,我只能通过减去“日”来找出日期是否在同一个月。在这个程序中,我使用了2组“月”,“日”和“年”整数。我几乎不知从哪里出发。这是我的任务中完全可选的部分,但我想了解如何使其工作。对我来说这似乎很麻烦,但也许有一个简单的数学公式,我没有想到?确定日期之间的差异

对不起,我没有任何此部分的预先存在的代码,因为作业的其余部分只处理让用户输入日期,然后添加和减去一天。

回答

4

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

假设日期类型,而月和日开始从(类似于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; 
} 

我想这个算法,它是工作好的。让我知道你是否有麻烦使用/理解它。

1

如果您需要自己动手,那么一种简单的方法是将日期转换为Julian Day。你在那个链接上获得公式,并且从转换开始,你只能使用浮动,每天都是1个单位。

+0

很好的参考,谢谢! – Hydlide 2012-04-03 05:43:27

2

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

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

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

像dbrank0指出。 :)

11

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

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

这似乎是一个麻烦给我,但也许有一个简单的数学公式I”米没有考虑?

这确实是一个麻烦,但有一个formula,如果你想自己做计算。

+0

只是一个nit(因为我不知道它会失败的任何平台),但是这个标准没有提及time_t中的时间表示,或者减去'time_t'会给你带来什么。你应该使用'difftime'(它返回一个'double',它引入了它自己的一组问题)。 – 2012-04-03 07:32:02

+0

@JamesKanze:好点; POSIX指定它是一个秒计数,但C保留实现定义。 – 2012-04-03 07:53:58

7

既然您正在寻找数学公式,它将帮助您找到解决问题的办法。让Y是一年,M是一个月,D是一天。为这两个日期做这个计算。

总计= Y * 365 + M * 30 + D,然后找到2个总计的相应日期之间的差异。

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

希望这将帮助ü....

+0

好的答案,但它不完整,所以我添加下面的完整代码。 – Borzh 2015-11-26 17:22:31

2

有圆的另一种方式......

  • 给定两个日期,取较早的日期的年份为参考年
  • 然后计算没有。之间的两个给定的日期和当年的1/1/< >
  • 保留一个单独的函数,告诉直到特定月份的过去的天数。
  • 这两个绝对差异没有。日期将给出两个给定日期之间的差异。
  • 此外,不要忘了考虑闰年

的代码:

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

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

6

对一个老问题的新答案:

chrono-Compatible Low-Level Date Algorithms

具有转换{年,月,日}三重天,回来的串行计数公式。你可以用它来计算这样两个日期之间的天数:

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算法不是新颖的,它看起来应该和其他算法非常相似以做同样的事情。但从另一个方面来看,从天数回到{年,月,日}三倍是棘手的。这是由civil_from_days记录的公式,我还没有看到其他与这个一样紧凑的配方。

本文包括示例使用表示typical computationsstd::chrono interoperability和广泛unit tests展示超过+/- 1亿年正确性(使用proleptic Gregorian calendar)。

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