1 杂谈:
最近在写蓝桥杯嵌入式12届真题,遇见了一个要处理YYMMDDHHmmSS格式的时间之差的问题。起初乍一看感觉很简单啊,不就算个日期差吗?把所有除串口以外的功能写完后,就去写这个日期之差,越写越感觉汗流浃背了,要求了好多细节,导致难度上升很多。其中就属这个算相差多少小时的功能写的最丑陋,一直if else差点给自己写迷了。最后写是写出来了,但是感觉写的太丑陋了,所以静下心研究了一会真就发现了一个比较好算的方法,特意写个博客记录一下,也算帮助一下别人,别人也可以参考一下。
2 内容:
2.1 难点:
我个人感觉日期难点就在与年份分闰年和非润年,闰年是366天非闰年是365天。而且每一年当中不同的月份中的天数也不同比如1,3,5,7,8,10,12都是31天。4,6,9,11都是30天,其中2月最特殊闰年的时候为29天,平年的时候为28天。这一大堆的限制条件很容易让人写出一堆if else,虽然也能运行但是不优雅。
2.2 解决方法:
我们不如换个角度想既然月份的太复杂了,我们不如只看一个整体那就是年份,因为年份只有闰年和平年之分,这样判断条件会减少很多。这个时候我们需要引入一个知识那就是前缀和了。前缀和简单来说就是把一个有序的数组的前n项进行相加,形成一个新的数组,这个数组的每一项都是原数组的起始位到此项之和。比如一个数组是arr[5]={1,2,3,4,5},那它的前缀和数组之和就是sum_arr[5]={1,3,6,10,15}。根据这个原理我们也可以将年份也化为前缀和去使用,它会大大降低我们的计算量。
平年: 原年份数组yaer:
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月
前缀和数组
31, 59, 90, 120, 151,181,212,243,273,304 ,334,365
润年: 原年份数组yaer:
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月
前缀和数组
31, 60, 91, 121, 152,182,213,244,274,305 ,335,366
这张图便是精髓用图像的方式展示出我是如何简便计算的。我们以2020年4月6日到2022年12月11日为例。我们先设一个值dis_day=0.首先我们知道2020年到2022年中间有一个完整的年份就是2021年,我们再判断一下这个2021年是闰年还是平年。2021年是平年所以dis_day+365=365,自可dis_day是365.我们再看起始年份2020年是润年,所以我们需要用到闰年的那个前缀和数组,我们再看月和日是4月6日,可以拆成前三个月的前缀和加上第四月的6天,我们可以查数组3月份的前缀和是91天,再把它加6天就是91+6=97天。但是呢这只是算2020年到起始年份已经经过的天数所以我们要366(闰年)-97=269天,dis_day+269=634天。同理我们再看截止日期2022年是平年所以需要用到平年的前缀和数组,12月11日就是前11个月加上第12个月的11天,11月的前缀和是334,334+11=345天,所以dis_day+345=979天至此我们就算出了相差天数。最终把计算分为了三个部分,起始日期,中间年份,截至日期。
2.3 bug:
其实这里还是有点小bug的,那就是不能算同一年份的相差日期的,因为我们算起始日期的时候要的是全年-月日(366-97)。这个时候只需做一点小修改就是改成我们要这个97天并且变为负数就像这样dis_day-97天就解决了这个bug。通俗易懂的说如果两个年份是同一年,我们要的是它俩的差。例如2022年4月6日到2022年12月11日,首先判断出这个2022是平年,然后就是前11个月的前缀和加11天-前3个月的前缀和加6天,334+11-90+6=249天。
3 代码:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool run_falg(int year)
{
if(year%4==0&&year%100!=0||year%400==0)
{
return true;
}
return false;
}
int run_year[13]={0,31,60,91,121,152,182,213,244,274,305,335,366};
int year[13]={0,31,59,90,120,151,181,212,243,273,304,334,365};
int disday(int h_yy,int h_mm,int h_dd,int l_yy,int l_mm,int l_dd)
{
int dis_day=0;
for(int i=l_yy+1;i<h_yy;i++)
{
if(run_falg(i))
{
dis_day+=366;
}
else
{
dis_day+=365;
}
}
//上半部分
bool l_flag=run_falg(l_yy);
if(h_yy!=l_yy)//当两者年份不相同时
{
if(l_flag)
{
dis_day+=366-(run_year[l_mm-1]+l_dd);
}
else
{
dis_day+=365-(year[l_mm-1]+l_dd);
}
}
//当两者年份相同时
else
{
if(l_flag)
{
dis_day-=(run_year[l_mm-1]+l_dd);
}
else
{
dis_day-=(year[l_mm-1]+l_dd);
}
}
//下半部分
bool h_flag=run_falg(h_yy);
if(h_flag)
{
dis_day+=(run_year[h_mm-1]+h_dd);
}
else
{
dis_day+=(year[h_mm-1]+h_dd);
}
return dis_day;
}
int main(void)
{
int day=disday(22,12,11,20,4,6);
printf("%d",day);
return 0;
}
4 结语:
希望帮到大家。
转载自CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/ne555555/article/details/152167769