10

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

当我每 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;
} 
4

8 回答 8

23

您可以在 O(1) 中将日期转换为儒略日数。

减去两个儒略日数。

于 2012-10-12T15:31:27.267 回答
11

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

给定整数 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)
于 2012-10-12T16:23:58.543 回答
9

Tyler Durden 的解决方案是最优雅的,但可能需要一些解释。

该算法的美妙之处在于:

(m*306 + 5)/10

它返回从 3 月 1 日到 3 月之后第 'm' 个月的开始之间的天数。(如果你想证明这一点,请记住使用截断小数部分的“整数除法”)

为了将标准约会约定融入此函数,月份和年份的输入值会发生变化,以便日历“开始”在 3 月而不是 1 月。

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

实现这一点处理了计算“每月天数”的问题,只留下“每年天数”要计算。维基百科为这部分提供了充分的解释。

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

于 2014-04-17T15:08:56.710 回答
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
于 2013-05-16T09:41:32.737 回答
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);            
    }
于 2013-10-13T11:30:46.937 回答
0

您还可以使用基于原点的算法。您可以计算开始日期和结束日期之前的所有天数,然后找出这些计数之间的差异:

totalDays = end_date_count - start_date_count

例如(java代码):

public class Origincount {
public static class Dates {
    private final Integer day;
    private final Integer month;
    private final Integer year;

    public Dates(String date) {
        String[] s = date.split("/");
        this.day = Integer.valueOf(s[0]);
        this.month = Integer.valueOf(s[1]);
        this.year = Integer.valueOf(s[2]);
    }
    public Integer getDay() {
        return day;
    }
    public Integer getMonth() {
        return month;
    }
    public Integer getYear() {
        return year;
    }
}

private static final Map<Integer, Integer> daysOfMonth = new HashMap<Integer, Integer>();

static {
    daysOfMonth.put(1, 31);
    daysOfMonth.put(2, 28);
    daysOfMonth.put(3, 31);
    daysOfMonth.put(4, 30);
    daysOfMonth.put(5, 31);
    daysOfMonth.put(6, 30);
    daysOfMonth.put(7, 31);
    daysOfMonth.put(8, 31);
    daysOfMonth.put(9, 30);
    daysOfMonth.put(10, 31);
    daysOfMonth.put(11, 30);
    daysOfMonth.put(12, 31);
}

public static Integer countLeapYears(Dates date) {
    Integer y = date.getYear();
    if(date.getMonth() <= 2) { y--; }
    return (y/4) - (y/100) + (y/400);
}

public static Integer daysMonth(Dates date) {
    Integer days = 0;
    for(int i=1; i<date.getMonth(); i++) {
        days += daysOfMonth.get(i);
    }
    return days;
}

public static void main(String[] args) {
    Dates start = new Dates("1/1/1901");
    Dates end = new Dates("31/12/2999");
    Integer countStart = (start.getYear()*365) + countLeapYears(start) + daysMonth(start) + start.getDay();
    Integer countEnd = (end.getYear()*365) + countLeapYears(end) + daysMonth(end) + end.getDay();

    System.out.println("Total days: "  + (countEnd-countStart));
}
}
于 2018-09-19T00:57:55.870 回答
-1

也许这会有所帮助:(这个程序是用 c 编写的)

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

}

于 2016-06-27T07:51:11.693 回答
-1

使用 Python 的简单算法:

   #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()
于 2018-02-04T15:44:52.090 回答