蔡勒公式
- 情景引入
- 公式介绍
- 公式细节
- 代码实现
情景引入
在日常生活中,我们有时候会遇到这样的问题:看到一个日期想知道这一天是星期几。对于这个问题,如果用编程的方式,应该怎么实现呢?你可能已经有思路了,比如你知道某个日期是星期几,把这个日期作为原点,然后计算目标日期和这个原点之间相差多少天,再除以 7 求余数,最后通过余数判断目标日期的星期数。
通过这样的过程,你确实可以得到正确的结果,但这样不够快速也不够优雅。对于这个问题,如果你懂得蔡勒(Zeller)公式,那就变得异常简单了,你只需要将年月日等数据代入公式,然后计算出结果,这一结果就是目标日期对应的星期数。
公式介绍
蔡勒(Zeller)公式,是一个计算星期的公式,随便给一个日期,就能用这个公式推算出是星期几。
蔡勒公式的形式如下:
若要计算的日期是在1582年10月4日或之前,公式则为:
以1582年10月4日为例:
1582年10月4日后:w = (d + 1 + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400)%7;
1582年10月4日前:w = (d + 1 + 2*m + 3*(m+1)/5 + y + y/4 + 5) % 7;
或者1752年9月3日为例:
1752年9月3日后:w = (d + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400)%7;
(这个公式应该是跟正常的相差1的,也就是算出来相差了一天)
1752年9月3日前:w = (d + 2*m + 3*(m+1)/5 + y + y/4 + 5) % 7;
备注:罗马教皇决定在1582年10月4日后使用格利戈里历法;而英国则是在1752年9月3日后才接受使用格利戈里历法。
注意:当年的1,2月要当成上一年的13,14月进行计算。
公式细节
w:星期; w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
c:世纪(注:一般情况下,在公式中取值为已经过的世纪数,也就是年份除以一百的结果,而非正在进行的世纪,也就是现在常用的年份除以一百加一;不过如果年份是公元前的年份且非整百数的话,c应该等于所在世纪的编号,如公元前253年,是公元前3世纪,c就等于-3)
y:年(一般情况下是后两位数,如果是公元前的年份且非整百数,y应该等于cMOD100+100)
m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算)
d:日
[ ]代表取整,即只要整数部分。
下面以中华人民共和国成立100周年纪念日那天(2049年10月1日)来计算是星期几,过程如下:
w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1
=49+[49/4]+[20/4]-2×20+[26×(10+1)/10]+1-1
=49+[12.25]+5-40+[28.6]
=49+12+5-40+28
=54 (除以7余5)
即2049年10月1日(100周年国庆)是星期五。
再比如计算2006年4月4日,过程如下:
w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1
=6+[6/4]+[20/4]-220+[26(4+1)/10]+4-1
=-12 (除以7余5,注意对负数的取模运算!实际上应该是星期二而不是星期五)
w=(-12%7+7)%7=2;
代码实现
1582年10月4日之后的计算代码如下:
C代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int year, month, day;
while (scanf("%d %d %d", &year,&month,&day) != EOF)
{
if (month == 1 || month == 2)//判断month是否为1或2
year--, month += 12;
int c = year / 100;
int y = year - c * 100;
int week = y + y / 4 + c / 4 - 2 * c + 26 * (month + 1) / 10 + day - 1;
while (week < 0)
week += 7;
week %= 7;
switch (week)
{
case 1:printf("Monday\n"); break;
case 2:printf("Tuesday\n"); break;
case 3:printf("Wednesday\n"); break;
case 4:printf("Thursday\n"); break;
case 5:printf("Friday\n"); break;
case 6:printf("Saturday\n"); break;
case 0:printf("Sunday\n"); break;
}
}
return 0;
}
C++代码:
#include<iostream>
using namespace std;
int main()
{
int year, month, day;
while (cin >> year >> month >> day)
{
if (month < 3)
{
year -= 1;
month += 12;
}
char b[7][10] = { "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday" };
int c = int(year / 100), y = year - 100 * c;
int w = int(c / 4) - 2 * c + y + int(y / 4) + (26 * (month + 1) / 10) + day - 1;
w = (w % 7 + 7) % 7;
cout << b[w] << endl;
}
return 0;
}