基姆拉爾森計算公式 推導
需求:
給定一個xxxx-xx-xx日期,計算為星期幾。
設定
int y; //年
int m; //月
int d; //日
int w; //周幾
從 公元0年1月1日星期日 開始
推導
對於第一個月
w = (d-1) % 7 --------- 公式(1)
對於年
- 不考慮閏年
在不考慮閏年的情況下,一年365天,365%7=1,就是說一年的第一天和最后一天是相同的。
等價於,下一年的第一天星期幾是會比這一年的最后一天+1的。
完善公式(1)
w = (d-1 + y) % 7 --------- 公式(2)
- 考慮閏年
因為閏年會多出來一天,所以相當於,計算當前年份前面有多少個閏年,將日期數w額外+1
計算閏年的公式為:
y/4 - y/100 + y/400
結合之前的公式1,2
w = [d-1+y + (y-1)/4-(y-1)/100+(y-1)/400] % 7 -----公式(3)
對於其它月份
- 假設每個月都是28天
因為28%7=0,也就是說每個月的w是相同的。 - 按正常月份計算
一月是31天,比28多3天,也就是說,2月的w值,是應該比1月按28計算的往后推遲3天。
三月的值,因為二月剛好28天,不影響,相當於還是推后3天。
以此類推。
因為12月已是最后一個月,所以不用考慮12月的誤差天數,同理,1月份的誤差天數是0,因為前面沒有月份影響它。
誤差表
月 | 誤差 | 累計 | 模7 |
---|---|---|---|
1 | 3 | 0 | 0 |
2 | 0 | 3 | 3 |
3 | 3 | 3 | 3 |
4 | 2 | 6 | 6 |
5 | 3 | 8 | 1 |
6 | 2 | 11 | 4 |
7 | 3 | 13 | 6 |
8 | 3 | 16 | 2 |
9 | 2 | 19 | 5 |
10 | 3 | 21 | 0 |
11 | 2 | 24 | 3 |
12 | - | 26 | 5 |
如果用一個數組記錄就是
e[] = {0,3,3,6,1,4,6,2,5,0,3,5}
完善公式
w = [d-1+y + e[m-1] + (y-1)/4-(y-1)/100+(y-1)/400] % 7 --公式(4)
- 將閏年的情況考慮進去
如果是閏年的話,2月之后的都會順移一天
w = (d-1 + y + e[m-1] + (y-1)/4 - (y-1)/100 + (y-1)/400);
if(m>2 && (y%4==0 && y%100!=0 || y%400==0) && y!=0)
++w;
w %= 7;
以上為基本推導過程
- 數學大佬對公式進行了優化
- W= (d+2m+3(m+1)/5+y+y/4-y/100+y/400+1)%7