2012-10-12 123 views
8

计算两个日期之间的天数的最有效方法是什么?基本上我问我们的优惠日期时间库是如何实现的。执行计算两个日期之间的天数

当我每4年运行一次迭代时,我很快实现了一个解决方案〜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; 
} 
+0

的check_leap公式是错误的,是来自Kiron的LeapYear评论是正确的:https://www.mathsisfun.com/leap-years。html –

回答

20

您可以在O(1)中将日期转换为Julian day number

减去两个朱利安天数。

+0

我很惊讶复杂的50行C++代码变成了3行.Thx – Satbir

7

所有除法都是整数除法,运算符%是模数。

鉴于整数Y,M,d,计算天数克为:

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) 
+0

你能解释一下这个公式吗? – Pwnna

+0

解释,它如何工作或如何编码?我认为g()根据公历来计算日数。那么两个日期之间的天数就是天数之间的差值。 –

+1

某处有证据吗? – Pwnna

4

的解决方案是在Python和它不应该是难以转换为其他任何语言。

def isLeapYear(year): 
    if year%4 == 0: 
     if year%100 == 0: 
      if year%400 == 0: 
       return True 
      else: 
       return False 
     else: 
      return True 
    else: 
     return False 

def daysBetweenDates(year1, month1, day1, year2, month2, day2): 
    cumDays = [0,31,59,90,120,151,181,212,243,273,304,334] #cumulative Days by month 
    leapcumDays = [0,31,60,91,121,152,182,213,244,274,305,335] # Cumulative Days by month for leap year 
    totdays = 0 
    if year1 == year2: 
     if isLeapYear(year1): 
      return (leapcumDays[month2-1] + day2) - (leapcumDays[month1-1] + day1) 
     else: 
      return (cumDays[month2-1] + day2) - (cumDays[month1-1] + day1) 

    if isLeapYear(year1): 
     totdays = totdays + 366 - (leapcumDays[month1-1] + day1) 
    else: 
     totdays = totdays + 365 - (cumDays[month1-1] + day1) 

    year = year1 + 1 
    while year < year2: 
     if isLeapYear(year): 
      totdays = totdays + 366 
     else: 
      totdays = totdays + 365 
     year = year + 1 

    if isLeapYear(year2): 
     totdays = totdays + (leapcumDays[month2-1] + day2) 
    else: 
     totdays = totdays + (cumDays[month2-1] + day2) 
    return totdays 
+0

这工作正常。结果与WolframAlpha中的结果相同。 – maro

2

我根据Doug Currie的建议写了这个公式。我测试了它直到从今天起2147483647天。

static int daysElapsed(int yearOne,int monthOne,int daysOne,int yearTwo,int monthTwo,int daysTwo) 
{ 
    return (daysTwo-32075+1461*(yearTwo+4800+(monthTwo-14)/12)/4+367*(monthTwo-2-(monthTwo-14)/12*12)/12-3*((yearTwo+4900+(monthTwo-14)/12)/100)/4)- 
        (daysOne-32075+1461*(yearOne+4800+(monthOne-14)/12)/4+367*(monthOne-2-(monthOne-14)/12*12)/12-3*((yearOne+4900+(monthOne-14)/12)/100)/4);    
    } 
+0

它工作正常。虽然有一些舍入误差。在某些情况下,应轮到某个人,并且有时轮到他们。 – maro

8

泰勒杜登的解决方案是最优雅的,但可能需要一些解释。

算法的优点是语句:

(m*306 + 5)/10 

它返回3月1日之间的天数,和“第m个月的3月以后开始。 (如果你想证明它,只要记住使用'整数除法',它会截断小数部分)

要将喇叭标准约会惯例应用到此函数中,月份和年份的输入值会被移动,以便日历“开始” 3月份而不是1月份。

m = (m + 9) % 12 
y = y - m/10 

实施此操作可以处理计算“每月天数”的问题,并且仅计算“每年的天数”。维基百科为该部分提供了充分的解释。

http://en.wikipedia.org/wiki/Leap_year#Algorithm

-1

也许这可以帮助:(这个程序用C语言编写)使用Python

#include<stdio.h> 


int gauss(int y) 
{ 
int r; 
r=(1+(5*((y-1)%4))+(4*((y-1)%100))+(6*((y-1)%400)))%7; 
return r; 
/* 
using gauss's algorithm to figure out the first day of the given year 
* visit:   https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week#Gauss.27s_algorithm 

*/ 
} 
int julian(int d,int m,int y){ 
int j; 
j=(d + (((153*m)+2)/5) + (365*y) + (y/4) - (y/100) + (y/400)); 
return j; 
/* 
    * calculating julian number for a date so that we can calculate number of days passed between the 
* first day of that year and the given date 
* visit: http://www.had2know.com/society/number-days-between-two-dates.html 
*/ 
} 

int main(){ 
int d1,m1,y1,j1,j2,n,r,n1,abs; 

int d,m,y; 

/* 
* d1= day date 
* d=d1 
* m1= month given by the user 
* m= month required for calculation 
* y1= year given by the user 
* y=year required for calculation 
*/ 
printf("Enter the day number of date: "); 
scanf("%d",&d1); 
printf("\nEnter the month number of date: "); 
scanf("%d",&m1); 
printf("\nEnter the year of date: "); 
scanf("%d",&y1); 
if(m1<13&&m1>2){ 
    m=m1-3; 
    d=d1; 
    y=y1; 
    j1=julian(1,10,y-1);//did y-1 as for jan and feb we did the same 

    j2=julian(d,m,y); 

} 
else if(m1==1 || m1==2) 
{ 
    m=m1+9; 
    d=d1; 
    y=y1-1; 
    j1=julian(1,10,y); 

    j2=julian(d,m,y); 

    } 
printf("\ndate: %d/%d/%d",d1,m1,y1); 

r=gauss(y1); 

abs=(j1-j2); 

if(abs<0){ 
    abs=0-abs; 
} 

n=(abs)%7; 


n1=(n+r)%7; 


if(n1==0) 
{ 
    printf("\nThe day is: Sunday"); 
} 
else if(n1==1) 
{ 
    printf("\nThe day is: Monday"); 
} 
else if(n1==2) 
{ 
    printf("\nThe day is: Tuesday"); 
} 
else if(n1==3) 
{ 
    printf("\nThe day is: Wednesday"); 
} 
else if(n1==4) 
{ 
    printf("\nThe day is: Thursday"); 
} 
else if(n1==5) 
{ 
    printf("\nThe day is: Friday"); 
} 
else if(n1==6) 
{ 
    printf("\nThe day is: Saturday"); 
} 
return 0; 

}

-1

简单的算法:

#Calculate the Days between Two Date 

    daysOfMonths = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 

    def isLeapYear(year): 

     # Pseudo code for this algorithm is found at 
     # http://en.wikipedia.org/wiki/Leap_year#Algorithm 
     ## if (year is not divisible by 4) then (it is a common Year) 
     #else if (year is not divisable by 100) then (ut us a leap year) 
     #else if (year is not disible by 400) then (it is a common year) 
     #else(it is aleap year) 
     return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0 

    def Count_Days(year1, month1, day1): 
     if month1 ==2: 
      if isLeapYear(year1): 
       if day1 < daysOfMonths[month1-1]+1: 
        return year1, month1, day1+1 
       else: 
        if month1 ==12: 
         return year1+1,1,1 
        else: 
         return year1, month1 +1 , 1 
      else: 
       if day1 < daysOfMonths[month1-1]: 
        return year1, month1, day1+1 
       else: 
        if month1 ==12: 
         return year1+1,1,1 
        else: 
         return year1, month1 +1 , 1 
     else: 
      if day1 < daysOfMonths[month1-1]: 
       return year1, month1, day1+1 
      else: 
       if month1 ==12: 
        return year1+1,1,1 
       else: 
         return year1, month1 +1 , 1 


    def daysBetweenDates(y1, m1, d1, y2, m2, d2,end_day): 

     if y1 > y2: 
      m1,m2 = m2,m1 
      y1,y2 = y2,y1 
      d1,d2 = d2,d1 
     days=0 
     while(not(m1==m2 and y1==y2 and d1==d2)): 
      y1,m1,d1 = Count_Days(y1,m1,d1) 
      days+=1 
     if end_day: 
      days+=1 
     return days 


    # Test Case 

    def test(): 
     test_cases = [((2012,1,1,2012,2,28,False), 58), 
         ((2012,1,1,2012,3,1,False), 60), 
         ((2011,6,30,2012,6,30,False), 366), 
         ((2011,1,1,2012,8,8,False), 585), 
         ((1994,5,15,2019,8,31,False), 9239), 
         ((1999,3,24,2018,2,4,False), 6892), 
         ((1999,6,24,2018,8,4,False),6981), 
         ((1995,5,24,2018,12,15,False),8606), 
         ((1994,8,24,2019,12,15,True),9245), 
         ((2019,12,15,1994,8,24,True),9245), 
         ((2019,5,15,1994,10,24,True),8970), 
         ((1994,11,24,2019,8,15,True),9031)] 

     for (args, answer) in test_cases: 
      result = daysBetweenDates(*args) 
      if result != answer: 
       print "Test with data:", args, "failed" 
      else: 
       print "Test case passed!" 
    test() 
相关问题