【笔记】计算日期差

前言

今天李老师给我出了一道算法题:快速求日期差。不会吧不会吧,这么简单的题也能考的住我?我花了十几分钟敲了个代码,不一会儿就调出来了。就这就这?然后李老师告诉我他三行就能实现。我不信,你敲一个?然后我信了,实现这个算法的核心代码真就三行。

正文

先上我写的代码:

#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语言计算日期间隔天数的经典算法解析

后记

算法真是奇妙!

posted @ 2020-10-24 21:24  pjhui  阅读(384)  评论(0编辑  收藏  举报