【笔记】计算日期差
前言
今天李老师给我出了一道算法题:快速求日期差。不会吧不会吧,这么简单的题也能考的住我?我花了十几分钟敲了个代码,不一会儿就调出来了。就这就这?然后李老师告诉我他三行就能实现。我不信,你敲一个?然后我信了,实现这个算法的核心代码真就三行。
正文
先上我写的代码:
#include<iostream>
#include<cstdio>
using namespace std;
int y1,y2,m1,m2,d1,d2;
bool judge(int y){//判断是否为闰年
if((y%4==0&&y%100!=0)||(y%400==0))return true;//如果是返回true
else return false;//如果不是返回false
}
int day(int y,int m){//接受年和月,返回此月有多少天
bool flag=judge(y)?true:false;//flag用来标记是否为闰年
if(m==1||m==3||m==5||m==7||m==8||m==10||m==12)return 31;
else if(m==2)return flag?29:28;//根据flag标记返回2月的天数
else return 30;
}
int Intervals(int Y1,int M1,int D1,int Y2,int M2,int D2){//计算日期差
int sub=0;//用来存计算日期差的结果
if(Y1==Y2){//如果是同一年
if(M1!=M2){//如果月不相同
if(M1+1<M2)for(int i=M1+1;i<M2;i++)sub+=day(Y1,i);//计算两个月间完整的月份的天数和
sub+=D2+day(Y1,M1)-D1;//处理非完整月天数
}
else sub+=D2-D1;//如果月相同,直接加上两个日期差
}else{//如果不是同一年
if(Y1+1<Y2)for(int i=Y1+1;i<Y2;i++)sub+=judge(i)?366:365;//计算完整年的天数和
sub+=Intervals(Y1,M1,D1,Y1,12,31)+Intervals(Y2,1,1,Y2,M2,D2)+1;//处理非完整年的天数,‘+1’是因为12月31日到次年1月1日也算一天
}
return sub;
}
int main(){
cin>>y1>>m1>>d1>>y2>>m2>>d2;//输入保证较小日期在先
cout<<Intervals(y1,m1,d1,y2,m2,d2)<<endl;
return 0;
}
李老师的代码:
int IntervalsPlus(int y, int m, int d){//核心代码就下面三行
int M = (m + 9) % 12;
int Y = y - M / 10;
return Y * 365 + Y / 4 - Y / 100 + Y / 400 + (M * 306 + 5) / 10 + d - 1;
}
int main(){
cout<<IntervalsPlus(y2, m2, d2) - IntervalsPlus(y1, m1, d1)<<endl;
return 0;
}
他告诉我这是解决这个问题的经典方法,他觉得很有意思就拿来考我了。
这个算法总体思想是计算给定日期到 0年3月1日的天数,然后相减,获取天数的间隔。
M = (m + 9) % 12;
用于判断日期是否大于3月(2月是判断闰年的标识),还用于纪录到3月的间隔月数。
Y = y - M / 10;
如果是1月和2月,则不包括当前年(因为是计算到0年3月1日的天数)。
return Y * 365 + Y / 4 - Y / 100 + Y / 400 + (M * 306 + 5) / 10 + d - 1;
其中
Y * 365
是不算闰年多出那一天的天数。
Y / 4 - Y / 100 + Y / 400
是加所有闰年多出的那一天。
(M * 306 + 5) / 10
用于计算到当前月到3月1日间的天数,306=365-31-28(1月和2月),5是全年中不是31天月份的个数。
d - 1
用于计算当前日到1日的间隔天数。 ——此段修改自C语言计算日期间隔天数的经典算法解析
后记
算法真是奇妙!