2012-04-03 118 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)。

所有的公式和軟件都在公共領域。