计算两个日期之间的天数最有效的方法是什么?基本上我是在问我们如何实现我们最喜欢的日期时间库.
当我每4年进行1次迭代时,我很快就实现了一个~O(n)的解决方案.(下面附有代码)
我被一个介绍解决问题的计算机课程的问题要求实现这个,但是他们只是每天迭代而不是每4年一次.所以我不满足于那个解决方案并提出了下面的解决方案.但是,是否有更有效的解决方案?如果是这样,他们如何实现它?
#include <iostream>
using namespace std;
#define check_leap(year) ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)))
#define debug(n) cout << n << endl
int get_days(int month, bool leap){
if (month == 2){
if (leap) return 29;
return 28;
} else if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12){
return 31;
} else {
return 30;
}
}
int days[] = {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
#define days_prior_to_month(n) days[n-2]
int num_days_between(int month1, int day1, int month2, int day2, bool leap){
if (month2 > month1)
return ((days_prior_to_month(month2) - days_prior_to_month(month1+1)) + get_days(month1, leap) - day1 + 1 + day2) + ((leap && month1 <= 2 && 2 <= month2) ? 1 : 0);
else if (month2 == month1)
return day2;
return -1;
}
int main(int argc, char * argv[]){
int year, month, day, year2, month2, day2;
cout << "Year: "; cin >> year;
cout << "Month: "; cin >> month;
cout << "Day: "; cin >> day;
cout << "Year 2: "; cin >> year2;
cout << "Month 2: "; cin >> month2;
cout << "Day 2: "; cin >> day2;
int total = 0;
if (year2 != year){
int leapyears = 0;
total += num_days_between(month, day, 12, 31, check_leap(year));
debug(total);
total += num_days_between(1, 1, month2, day2, check_leap(year2));
debug(total);
int originalyear = year;
year++;
year = year + year % 4;
while (year <= year2-1){
leapyears += check_leap(year) ? 1 : 0;
year += 4;
}
total += leapyears * 366;
debug(total);
total += max(year2 - originalyear - leapyears - 1, 0) * 365;
debug(total);
} else {
total = num_days_between(month, day, month2, day2, check_leap(year));
}
cout << "Total Number of Days In Between: " << total << endl;
system("PAUSE");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
所有除法均为整数除法,运算符%为模数.
给定整数y,m,d,计算天数g为:
function g(y,m,d)
m = (m + 9) % 12
y = y - m/10
return 365*y + y/4 - y/100 + y/400 + (m*306 + 5)/10 + ( d - 1 )
Difference between two dates = g(y2,m2,d2) - g(y1,m1,d1)
Run Code Online (Sandbox Code Playgroud)
Tyler Durden的解决方案最优雅,但可能需要一些解释.
该算法的优点是声明:
(m*306 + 5)/10
Run Code Online (Sandbox Code Playgroud)
返回3月1日和3月之后的"m"月开始之间的天数.(如果你想证明它,只记得使用截断小数部分的'整数除法')
为了将角标准约会惯例转换为此函数,将转换月份和年份的输入值,以便日历在3月而不是1月"开始".
m = (m + 9) % 12
y = y - m/10
Run Code Online (Sandbox Code Playgroud)
实现这一点可以解决计算"每月天数"的问题,并且只计算"每年的天数".维基百科为该部分提供了充分的解释.
http://en.wikipedia.org/wiki/Leap_year#Algorithm