根据日期推算星期和历法由来
太阳历和公历(儒略历与格里历)
现在世界上通用的历法——公历,有人曾似是而非地称之为“西历”。其实,究其根
源,这种历法并非产生于西方,而是产生于6000多年前的古埃及。
古埃及气候炎热,雨水稀少,但是农业生产却很发达。这是为什么呢?原来这与尼罗河
的定期泛滥有着密切的关系。埃及的大部分国土都是沙漠,只有尼罗河流域像一条绿色的缎
带从南到北贯穿其间。直到现代,埃及的的95%以上的人口也都集中在这条绿色的生命带
中。因此,在希腊时代,西方人便把埃及称为“尼罗河送来的礼物”。古代埃及人更是将尼
罗河视为“母亲河”。
尼罗河全长6648公里,同亚洲的长江、南美洲的亚马逊河和北美洲的密西西比河并
称为世界最长的河流。
尼罗河发源于赤道一带,主流叫白尼罗河,从乌干达流入苏丹,在喀土穆和发源于埃塞
俄比亚的青尼罗河汇合,流入埃及。
在埃及境内,尼罗河每年6月开始涨水,7至10月是泛滥期,这时洪水夹带着大量腐
殖质,灌满了两岸龟裂的农田。几个星期后,当洪水退去时,农田就留下了一层肥沃的淤
泥,等于上了一次肥。11月进行播种,第二年的3至4月收获。尼罗河还有一个特性,那
就是每年的涨水基本是定时定量,虽有一定的出入,但差别不是太大,从没有洪水滔天淹没
一切的大灾。这就为古埃及人最早创建大规模的水利灌溉系统和制定历法提供了方便。
古埃及人为了不违农时,发展农业生产,逐渐认识到必须掌握尼罗河泛滥的规律,准确
地计算时间,这就需要有一种历法。他们在长期的生产实践中,积累了许多经验。
古埃及人发现尼罗河每次泛滥之间大约相隔365天。同时,他们还发现,每年6月的
某一天早晨,当尼罗河的潮头来到今天开罗附近时,天狼星与太阳同时从地平线升起。以此
为根据,古埃及人便把一年定为365天,把天狼星与太阳同时从地平线升起的那一天,定
为一年的起点。一年分为12个月,每月30天,年终加5天作为节日,这就是埃及的太阳
历。
埃及的太阳历将一年定为365天,与地球围绕太阳公转一圈的时间(回归年)相比
较,只相差四分之一天,这在当时已经是相当准确了。但是,一年相差四分之一天不觉得,
经过4年就相差一天。经过730年,历法上的时间就比实际时间推进了半年,冬天和夏天
正好颠倒过来。再过730年,才能回到原来的起点。公元前46年,罗马统帅儒略·凯撒
(又译朱利乌斯·凯撒)决定以埃及的太阳历为蓝本,重新编制历法。凯撒主持编制的历
法,被后人称为“儒略历”。
儒略历法对埃及太阳历中每年约四分之一天的误差,作了这样的调整:设平年和闰年,
平年365天,闰年366天。每4年置1个闰年。单月每月31天,双月中的2月平年2
9天,闰年30天,其它双月每月30天。
恺撒死后,他的继承人奥古斯都因为自己生在8月,便从2月中抽出一天加在8月上,
使8月也成为大月,即31天,同时相应把9、11两个月定为小月,10、12两个月定
为大月。经过这样的改动,各月的天数与今天使用的公历基本相同了。公元325年,罗马
皇帝君士坦丁在一次宗教会议上,规定儒略历为基督教的历法,但没有规定哪一年是它的起
点。到了公元6世纪时,基督教徒把500多年前基督教传说的创始人耶稣·基督诞生的那
一天,说成是公元元年。“公元”的拉丁文的意思就是“主的生年”,用拉丁文A.D.表
示。在这一年以前,称为“公元前”,英文的意思是“基督以前”,用英文B.C.表示。
儒略历虽然比埃及的太阳历进了一步,但回归年仍有11分14秒的误差,积128年
又要相差一天。儒略历在欧洲通行了1600多年,至16世纪下半叶,历法上的日期比回
归年迟了10天。比如,1583年的春分应在3月21日,历法上却是3月11日。此
外,教会规定耶稣复活节,应在过春分月圆后的第一个星期日,由于春分已相差10天之
多,耶稣究竟在哪一天“复活”的,也成了问题。因此,对儒略历作进一步的改革,已经势
在必行。
罗马教皇格里高利十三世,在1582年组织了一批天文学家,根据哥白尼日心说计算
出来的数据,对儒略历作了修改。将1582年10月5日到14日之间的10天宣布撤
销,继10月4日之后为10月15日,所以1533年的春分又复归于3月21日;过去
将4年置1个闰年,400年共计100个闰年,现在改为400年中有97个闰年,从而
大体上弥补了11分14秒的误差。置闰的方法是:凡是逢百年那一年可以用400除尽的
就是闰年,除不尽的就不是(如:1600年是年,1700年、1800年、1900年
皆不是年,2000年是闰年)。后来人们将这一新的历法称为“格里高利历”,也就是今
天世界上所通用的历法,简称“格里历”或公历。
中华人民共和国成立后,中央人民政府通令,中国以格里历为国家历法,并采用公元纪
年,但不废除农历。
当然,格里历也不是尽善尽美的,每月的天数仍然参差不齐,规则性不强,特别是每经
过三千几百年还会有一天的误差。随着生产的发展和天文学的进步,这些缺陷将不断得到改
进。
出处:http://www.nongli.com/sj5000/008.htm
====================================================
再谈星期的计算
“让我们看看1752年9月14号这个星期四吧,我们的公式最远只能推算到这里了。”
——Kim S. Larsen
“从公元元年1月1日开始到现在,每一天都是连续的。”
——于鹏
“西方历法的第一次改革是罗马朱利乌斯·凯撒大帝引进的。他采用的四年一闰的闰年方式。由于一个太阳年不刚好是365.25天,而是 365.242199…天。到16世纪,每年11分14秒的误差已经累积成10天,也就是历法上多了10天。于是教皇格利戈里八世进行了一次校正。他在1582年2月24日以教皇训令颁布,将1582年10月5日至14日抹掉,并且对原来的闰年方法进行了校正。经过校正的历法叫格利戈里历法,也就是我们现在用的公历。1752年,英国人决定采用格利戈里历法,不过从1582年到那时,历法又多出了1天,所以英国议会在1752年作出决定,抹掉11天——1752年9月3日至13日。”
日期的限制是Kim S. Larsen算法的问题吗?不。
公元元年1月一日开始到现在,每一天都是连续的吗?不。
一个简单的方法就可以证明上述事实——用Linux的cal命令。启动你的Linux在#提示符下输入
cal 9 1752
你会看到:
September 1752
Su Mo Tu We Th Fr Sa
1 2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
有趣吧一个只有19天的九月。
让我们来看看这两个算法,Kim S. Larsen博士的算法和于鹏同学的算法在本质上其实是相同的。只不过在实现的细节上略有不同。如果让两个算法去计算同一天(无论在1752年9月14日之前还是之后)是星期几,二者的答案肯定是相同的。让我们来分析一下吧。
首先,他们把日期对星期的决定作用都分为年、月、日三个决定因素。对于年的因素,从两者的计算公式 就能看出是相同的;对于日的因素,两者都是直接计入,故也是相同的;而对于月的因素,Kim S. Larsen博士构造了一个公式,(一个非常巧妙的公式,)通过以月份为自变量算出的函数值作为对星期的影响量。而于鹏同学采用了查表的方法,即先构造好一个以月份为索引的表对于相应的月份,通过查表得出其对星期的影响量。(以switch语句实现)不妨作如下演算:(为了一致起见,采用一、二月作为上年的十三、十四月。这是一个非常聪明的方法。)用于鹏同学的方法建表,并对7取模(表一)。再建立Kim S. Larsen函数 的函数值表(表二)。很显然二者是相同的。
三月 0 0 | 三月 0
四月 31 3 | 四月 3
五月 61 5 | 五月 5
六月 92 1 | 六月 1
七月 122 3 | 七月 3
八月 153 6 | 八月 6
九月 184 2 | 九月 2
十月 214 4 | 十月 4
十一月 245 0 | 十一月 0
十二月 275 2 | 十二月 2
十三月 306 5 | 十三月 5
十四月 337 1 | 十四月 1
表一 表二
其次,在处理闰年2月29日的问题上,两者的做法略有不同,但效果还是相同的。Kim S. Larsen博士采用的方法相当高明,他把二月排在一年的最后,管他闰不闰,反正是最后一天。而于鹏同学加了一个if分支,直观有效。
大师不愧为大师,设计的算法简洁、优美;而于鹏同学的算法,简单易懂,并且效率并不差。
好了,该解决这个“历史遗留问题”了。其实,并没有什么数学公式能算出指定日期是星期几,我们可以试着拼凑一个,不过何必呢?加个if分枝不就解决问题了吗?(Kim S. Larsen算法+于鹏思想)对Kim S. Larsen 博士的程序作一些必要的添加,可得到突破1752年9月14日日期限制的C语言程序。
/*C++Builder5下编译通过*/
/*假设输入的是正确的日期*/
#include <stdio.h>
char *name[] = { “Monday”,
“Tuesday”,
“Wednesday”,
“Thursday”,
“Friday”,
“Saturday”,
“Sunday”
};
void main(){
int D,M,Y,A;
printf(“Day: “); fflush(stdout);
scanf(“%d”,&D);
printf(“Month: “); fflush(stdout);
scanf(“%d”,&M);
printf(“Year: “); fflush(stdout);
scanf(“%d”,&Y);
if ((M == 1) || (M == 2)){/*一月、二月当作前一年的十三、十四月*/
M += 12;
Y–;
}
if ((Y < 1752)||((Y == 1752)&&(M < 9))
||((Y == 1752)&&(M == 9)&&(D < 3)))/*判断是否在1752年9月3日前*/
A = (D + 2*M + 3*(M+1)/5 + Y + Y/4 +5) % 7;/*1752年9月3日前的公式*/
else A = (D + 2*M + 3*(M+1)/5 + Y + Y/4 – Y/100 + Y/400) % 7;/*1752年9月3日后的公式*/
printf(“It\’s a %s.\n”,name[A]);
}
出处:http://bbs.csdn.net/topics/10163840
==================================================