【接上篇】
上述計(jì)算星期的方法雖然步驟簡(jiǎn)單,但是每次都要計(jì)算兩個(gè)日期的時(shí)間差,不是非常方便。如果能夠有一個(gè)公式可以直接根據(jù)日期計(jì)算出對(duì)應(yīng)的星期豈不是更好?幸運(yùn)的是,這樣的公式是存在的。此類公式的推導(dǎo)原理仍然是通過兩個(gè)日期的時(shí)間差來計(jì)算星期,只是通過選擇一個(gè)特殊的日期來簡(jiǎn)化公式的推導(dǎo)。這個(gè)所謂的特殊日期指的是某一年的12月31日這天剛好是星期日這種情況。選擇這樣的日子有兩個(gè)好處,一個(gè)是計(jì)算上可以省去計(jì)算標(biāo)準(zhǔn)日期這一年的剩余天數(shù),另一個(gè)是計(jì)算出來的日期差余數(shù)是幾就是星期幾,不需要再計(jì)算星期的差值。人們知道公元元年的1月1日是星期一,那么公元前1年的12月31日就是星期日,用這一天作為標(biāo)準(zhǔn)日期,就可以只計(jì)算整數(shù)年的時(shí)間和日期所在的年積累的天數(shù),這個(gè)星期公式就是:
w = (L * 366 + N * 365 + D) % 7 (公式 2)
公式中的L是從公元元年到y年m月d日所在的年之間的閏年次數(shù),N是平常年次數(shù),D是y年內(nèi)的積累天數(shù)。將整年數(shù)y - 1 = L + N帶入上式,可得:
w = ( (y - 1) * 365 + L + D) % 7 (公式 3)
根據(jù)閏年規(guī)律,從公元元年到y年之間的閏年次數(shù)是可以計(jì)算出來的,即: 將L帶入公式2,得到星期w的最終計(jì)算公式: 還以2005年5月31日為例,利用公式5計(jì)算w的值為: 得到2005年5月31日是星期二,和前面的計(jì)算方法得到的結(jié)果一致。根據(jù)上述分析,可得寫出使用公式5計(jì)算星期的算法實(shí)現(xiàn):
公式5的問題在于計(jì)算量大,不利于口算星期結(jié)果。于是人們就在公式5的基礎(chǔ)上繼續(xù)推導(dǎo)更簡(jiǎn)單的公式。德國(guó)數(shù)學(xué)家克里斯蒂安·蔡勒(Christian Zeller, 1822- 1899)在1886年推導(dǎo)出了著名的為蔡勒(Zeller)公式: 對(duì)計(jì)算出的w值除以7,得到的余數(shù)就是星期幾,如果余數(shù)是0,則為星期日。蔡勒公式中各符號(hào)的含義如下: w :星期; c :世紀(jì)數(shù) – 1的值,如21世紀(jì),則 = 20; m :月數(shù),的取值是大于等于3,小于等于14。在蔡勒公式中,某年的1月和2月看作上一年的13月和14月,比如2001年2月1日要當(dāng)成2000年的14月1日計(jì)算; y :年份,取公元紀(jì)念的后兩位,如1998年, = 98,2001年, = 1; d :某月內(nèi)的日數(shù)
為了方便口算,人們通常將公式6中的 。目前人們普遍認(rèn)為蔡勒公式是計(jì)算某一天是星期幾的最好的公式。但是蔡勒公式有時(shí)候可能計(jì)算出的結(jié)果是負(fù)數(shù),需要對(duì)結(jié)果+7進(jìn)行修正。比如2006年7月1日,用蔡勒公式計(jì)算出的結(jié)果是 -1,實(shí)際上這天是星期六。根據(jù)前面分析的結(jié)果整理出的蔡勒公式算法實(shí)現(xiàn)如下:
蔡勒公式(公式6)和前面提到的公式5都只適用于格里歷法。羅馬教皇在1582年修改歷法,將10月5日指定為10月15日,從而正式廢止儒略歷法,開始啟用格里歷法。因此,上述求星期幾的公式只適用于1582年10月15日之后的日期,對(duì)于1582年將10月4日之前的日期,蔡勒也推導(dǎo)出了適用與儒略歷法的星期計(jì)算公式: 公式7適用于對(duì)1582年10月4日之前的日期計(jì)算星期,1582年10月5日與1582年10月15日之間的日期是不存在的,因?yàn)樗鼈兌际峭惶臁?/p>
格里歷歷法簡(jiǎn)單,除二月外每月天數(shù)固定,二月則根據(jù)是否是閏年確定是28天還是29天,每天的星期數(shù)可以通過蔡勒公式(公式6)計(jì)算,有了這些信息,就可以按照一定的排版格式將某一年的日歷打印出來。排版打印的算法非常簡(jiǎn)單,就是按照順序打印12個(gè)月的月歷,因此,打印月歷的函數(shù)就是輸出算法的重點(diǎn)。代碼沒什么特別之處,就是用一些小技巧確定每個(gè)月的第一天的開始位置,打印月歷的核心代碼如下:
GetDaysOfMonth()函數(shù)其實(shí)就是從daysOfMonth表中查一下每月的天數(shù),如果是閏年,則對(duì)二月的天數(shù)修正(+1),daysOfMonth表定義如下:
int daysOfMonth[MONTHES_FOR_YEAR] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
計(jì)算星期不必對(duì)每一天都計(jì)算一次,只要對(duì)每個(gè)月的第一天計(jì)算一次就可以了,以后的日期可以用 week = (week + 1) % 7 直接推算出星期幾。下面就是我們的算法打印輸出的效果:
********************************************************************************
Calendar of 2012
********************************************************************************
----------January----------
Sunday Monday Tuesday Wednesday Thursday Friday Saturday 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
----------February----------
Sunday Monday Tuesday Wednesday Thursday Friday Saturday 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
----------March----------
Sunday Monday Tuesday Wednesday Thursday Friday Saturday 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
……
小知識(shí)2:儒略歷和格里歷 在公元1582年10月15日之前,人們使用的歷法是源自古羅馬的儒略歷,儒略歷的置閏規(guī)則就是四年一閏,但是沒有計(jì)算每年多出來的0.0078天,這樣從公元前46年到公元1582年一共累積多出了10天,為此,當(dāng)時(shí)的教皇格里十三世將1582年10月5日人為指定為10月15日,并開始啟用新的置閏規(guī)則,這就是后來沿用至今的格里歷。
小知識(shí)3:約化儒略日 由于儒略日數(shù)字位數(shù)太多,國(guó)際天文聯(lián)合會(huì)于1973年8月決定對(duì)其修正,采用約化儒略日(MJD)進(jìn)行天文計(jì)算,定義MJD = JD – 2400000.5,MJD相應(yīng)的起始點(diǎn)是1858年11月17日 0:00。
小知識(shí)4:1752年9月到底是怎么回事兒 如果你用的操作系統(tǒng)是unix或linux,在控制臺(tái)輸入以下命令:
#cal 9 1752
你會(huì)看到這樣一個(gè)奇怪的月歷輸出:
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
1752年的9月缺了11天,到底怎么回事兒?這其實(shí)還是因?yàn)閺娜迓詺v到格里歷的轉(zhuǎn)換造成的。1582年10月5日,羅馬教皇格里十三世宣布啟用更為精確的格里歷,但是整個(gè)歐洲大陸并不是所有國(guó)家都立即采用格里歷,比如大英帝國(guó)就是直到1752年9月議會(huì)才批準(zhǔn)采用格里歷,所以大英帝國(guó)及其所有殖民地的歷法一直到1752年9月才發(fā)生跳變,“跟上”了格里歷。德國(guó)和荷蘭到了1698年才采用格里歷,而俄羅斯則直到1918年革命才采用格里歷。Linux的cal指令起源與最初AT&T的UNIX,當(dāng)然采用的是美國(guó)歷法,但是美國(guó)歷史太短,再往前就只能采用英國(guó)歷法,所以cal指令的結(jié)果就成了這樣。對(duì)于采用格里歷的國(guó)家來說,只要知道1582年10月發(fā)生了日期跳變就行了,可以不用關(guān)心1752年9月到底是怎么回事兒。但是對(duì)于研究歷史和考古的人來說,就必需要了解這個(gè)歷史,搞清楚每個(gè)歐洲國(guó)家改用格里歷的年份,否則就可能在一些問題上出錯(cuò)。在歐洲研究歷史,你會(huì)發(fā)現(xiàn)很多事件都是有多個(gè)時(shí)間版本的,比如大科學(xué)家牛頓的生日就有兩個(gè)時(shí)間版本,一個(gè)是按照儒略歷歷法的1642年12月25日,另一個(gè)是格里歷歷法的1643年1月4日,對(duì)于英國(guó)人來說,1752年之前都是按照儒略歷計(jì)算的,所以英國(guó)的史書可能會(huì)記載牛頓出生在圣誕節(jié),這也沒什么可奇怪的。
|
|