C语言——蔡勒(Zeller)公式:快速将任意日期转换为星期数

情景引入

  在日常生活中,我们有时候会遇到这样的问题:看到一个日期想知道这一天是星期几。对于这个问题,如果用编程的方式,应该怎么实现呢?你可能已经有思路了,比如你知道某个日期是星期几,把这个日期作为原点,然后计算目标日期和这个原点之间相差多少天,再除以 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;
}
  • 10
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值