一般来说,关于日期计算的算法题,无外乎就是计算两个日期差多少天,给定一个日期算出今天是星期几,那么该如何计算呢?
常规方法
- 计算0001-01-01到(xxxx-1)-12-31的公式是
这里(xxxx-1)指的是去年,比如我们要算2024-02-29那么xxxx-1就代表2023年
公式1 其中,y:year,
闰年分为普通闰年(能被4整除但不能被100整除)跟世纪闰年(能被400整除),365*year好理解,就是先算平年的所有天,
y/4-y/100是计算0001-xxxx年间有多少个普通闰年,
y/400是计算有多少个世纪闰年(多少个闰年就多多少天)
-
接着计算xxxx-01-01到xxxx-xx-xx的天数,执行1.+2.
-
如果计算两个日期差的话,就是两个天数相减
上面的计算是否麻烦的一些?还得判断xxxx是闰年还是平年,然后挨个月计算,那么是否有一种公式只需要年月日就可以计算出差多少天?——蔡勒公式
蔡勒公式
首先先给出蔡勒公式的表达式:
公式2 |
这是你要计算的日期 |
闰年跟平年的区别只是在2月份有区别,其他月份不管是平年还是闰年都是一样的。要想无需判断平年闰年就能计算出差多少天,首先一定得迈过2.28/2.29这个坎,于是该公式的起始月份是每一年的3.01到明年的2.01,此时完美避开了2.28/2.29,从而可以无需考虑该年是平年还是闰年。公式的前半部分(公式2中包含公式1的那部分)好理解,就是计算0001-01-01到(xxxx-1)-12-31或者0001-01-01到xxxx-12-31的时间,当我
让我们观察一下每个月的1号到3月1号的天数规律
月份 | 该月天数 | 该月1号到3月1号的天数差 | 规律 |
---|---|---|---|
3 | 31 | 0 | 0 |
4 | 30 | 31 | 30+1 |
5 | 31 | 61 | 60+1 |
6 | 30 | 92 | 90+2 |
7 | 31 | 122 | 120+2 |
8 | 31 | 153 | 150+3 |
9 | 30 | 184 | 180+4 |
10 | 31 | 214 | 210+4 |
11 | 30 | 245 | 240+5 |
12 | 31 | 275 | 270+5 |
13 | 31 | 306 | 300+6 |
14 | 未知 | 337 | 330+7 |
其中1-12表示的是去年一整年的月份,13表示今年的1月份,14表示今年的2月份。
你会发现除了个位数,另一个是一个首项是0,公差是30的等差数列
现在的问题就变成找到一个函数拟合个位数的变化1,1,2,2,3,4,4,5,5,6,7
该函数就是
公式3 |
m是月份,num值是其个位数 |
于是就有
公式4 |
所以这个公式就是计算我们要求的month所在月的1号到3.01的天数 |
加上该月所在的天数day,就是总的TotalDay
那么306是哪来的呢, 看上面表格你会发现,306是指3.01-2.01(去年3月1号到今年2月1号)这个时间的总和
那么为何要-306呢?我们来举两个例子
例子说明
计算2024-02-27和计算2024-05-23(ps:下面说的公式前半部分指的是公式1,后半部分指的是公式4)
首先计算2024-02-27,由于是2月份(小于3月份)于是变成2023-14-27,带入公式得,由于公式的前半部分是计算了2023年一整年,所以这部分就是计算0001-01-01~2023-12-31的总天数,公式后半部分计算的是2023-03-01到2023-14-01(也就是2024-02-01)的总天数,这里也就有了重叠计算了两次2023-03-01到2023-12-31的天数,也就是306,于是公式就有减去306天了,最后在加上2月已过去27天,也就是2024-02-27已过去的天数了。
计算2024-05-23,由于是5月份(大于3月份)于是直接带入公式得,公式前半部分计算0001-01-01到2024-12-31的总天数,减去306天也就是变成0001-01-01到2024-03-01的总天数,公式后半部分计算的是3-01到5-01的总天数,两者相加就是2024-05-23已过去的天数了。
这里给出c++的代码
int sum_date(int y, int m, int d) {
if (m < 3) {
m += 12;
y--;
}
return 365 * y + y / 4 - y / 100 + y / 400 + (153 * m - 457) / 5 + d - 306;
}
最后
算出了这个日期已过去多少天就可以秒杀很多题目了,包括但不限于,两个日期差多少天,给定一个日期算出今天是星期几?(totalday%7=0就是星期天,1就是星期一以此类推)