根據日期推算星期和曆法由來

太陽曆和公曆(儒略曆與格里曆)
如今世界上通用的歷法——公曆,有人曾似是而非地稱之爲「西曆」。其實,究其根
源,這種曆法並不是產生於西方,而是產生於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日開始到如今,每一天都是連續的。」
                                         ——於鵬ui

「西方曆法的第一次改革是羅馬朱利烏斯·凱撒大帝引進的。他採用的四年一閏的閏年方式。因爲一個太陽年不恰好是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日。」spa

日期的限制是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語句實現)不妨做以下演算:(爲了一致起見,採用1、二月做爲上年的十3、十四月。這是一個很是聰明的方法。)用於鵬同窗的方法建表,並對7取模(表一)。再創建Kim S. Larsen函數 的函數值表(表二)。很顯然兩者是相同的。.net


三月    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 設計

表一                      表二 orm

其次,在處理閏年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)){/*一月、二月看成前一年的十3、十四月*/
    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]);
}htm

出處:http://bbs.csdn.net/topics/10163840blog

==================================================

根據日期推算星期做者: 宋維業

      記得幾年前,有個新聞報道說,有我的記憶力很強,能夠記住任意日期是星期幾。

      我感受不太靠譜,其實,這個星期幾是能夠經過公式計算出來的。

其中一種叫作基姆拉爾森計算公式:

      公式是W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7

  在公式中d表示日期中的日數+1,m表示月份數,y表示年數。

  注意:在公式中有個與其餘公式不一樣的地方:

  把一月和二月當作是上一年的十三月和十四月,例:若是是2004-1-10則換算成:2003-13-10來代入公式計算。

 

還有蔡勒公式:

 

        W = [C/4] - 2C + y + [y/4] + [13 * (M+1) / 5] + d - 1

 

或者是:w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1

 

公式中的符號含義以下:
w:星期; w對7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
c:世紀-1(前兩位數)
y:年(後兩位數)
m:月(m大於等於3,小於等於14,即在蔡勒公式中,某年的一、2月要看做上一年的1三、14月來計算,好比2003年1月1日要看做2002年的13月1日來計算)
d:日
[ ]表明取整,即只要整數部分。

 

 

      另外,還有個事情,這個公式只能計算1582年10月15日(含)以後的情形。

      緣由是什麼呢?

    在如今通行的歷法記載上,全世界竟然有十天沒有任何人出生過,也沒有任何人死亡過,也沒有發生過大大小小值得記念的人或事。這就是1582年10月5日至10月14日,持續時間爲0。

  事實上,目前世界通行的公曆中,就有持續時間爲0的10天,即公元1582年10月5日至14日。事情是這樣的:

  西方曆法的第一次改革是羅馬朱利烏斯·凱撒大帝於公元前45年親自引進的。當時採用的數字是一年365.25天,因而朱利安曆法成爲最簡單的歷法:第1、2、三年都是365天,三年餘下的0.25天給第四年,第四年就有366天,這就是閏年。因而重複365,365,365,366的週期,每一年都是整數。

  可是,一個太陽年不恰好是362.25天,而是 362.242199…天,每一年相差11分14秒,也就是朱利安曆法中每一年多算了11分鐘14秒。因爲偏差不太大,頭幾年沒什麼關係,凱撒活着時影響還不大。可是,一年又一年,偏差累積起來,朱利安曆法就與實際的太陽年不合拍了。例如每一年春分在3月21日先後,但幾個世紀後,春分在朱利安曆法上的日期愈來愈提早了,這對農民種地不方便,對教會肯定復活節在哪一天也帶來麻煩。因爲朱利安曆法是凱撒親自制定的,上述狀況對他的威信是一個沉重打擊。

  16世紀時,教皇格利戈裏八世進行了一次校訂。由於到16世紀,每一年11分14秒已經累積成10天,也就是曆法上多了10天,這對於肯定復活節形成嚴重困難,不得不採起措施補救。爲此,格利戈裏採起了解決此類難題的最古老最有效的策略----他召集一個委員會,任命一位聰明的主席,即傑出的耶穌會數學家克利斯多弗·克拉維斯(Christopher Clavius),要求委員會提出解決方案。委員會於1587年開始工做。

  克拉維斯委員會面臨兩個不一樣的問題,它用不一樣的方法進行解決。第一,朱利安曆法如今走快了10天,必須拉回到與太陽年一致。克拉維斯建議用官方聲明把這10天抹掉!教皇格利戈八世於1582年2月24日以教皇訓令頒佈,將1582年10月5日至14抹掉,因而這10天就消失了,一去不復返。1582年10月4日過完了,次日已是10月15日了,因而曆法又回到與太陽年同步。

  當時以及後來有許多人對此感到驚愕,目瞪口呆,有人認爲是荒唐、武斷。「教皇一紙訓令就能抹掉日曆上的10天?」

  可是,這10天的確不存在了,這10天什麼也沒有發生,這10天根本就沒過日子。若是你能找到當時的日記,10月4日記完後,下一頁就是10月15日的事。用科學語言表達,這10天的持續時間爲0。

  其實徹底沒必要驚訝。太陽年、太陽日與天然現象有聯繫,至於某一天是什麼日子,則是人爲的,與給小孩起名字同樣。咱們能夠不用公曆,一年不分月,只叫第1天,第2天,……第125天,……到第365天,這是容許的。喜歡偶數的人能夠發明一個「偶很多天曆」:2月2日,2月4日……4月2日……12月30日,12月32日……,14月2日,這也是容許的,只要一年365天或者366天就行。這再一次證實,在一個科學理論或體系中區分出由天然現象決定(於是必須符合實驗)的部分和人爲規定的部分是重要的。

  固然,這個決定對當時的社會生活也會有必定影響,例如出生在10月5日至10月14日的人在1582年找不到本身的生日,但與出生在2月29日的人相比,少過一年生日算不了什麼。還有,那年10月份的工資、利息也會有問題,但不知那時的銀行、工資制度什麼樣。不過這些問題的影響微乎其微。

  第二個問題是須要提出曆法的補充規則,不讓每一年多出的11分14秒累積得太多。因而克拉維斯委員會提出一年有365.2422天的方案,這比朱利安曆法的365.25天大大接近天體運動實際。據此對朱利安曆法只有「四年一閏」的簡單規定進行校訂:四年一閏,可是世紀之交的’00年,如100年,200年,不閏,即每一百年少閏一次。這樣一算,閏年又太少了,因而進一步規定:每四個世紀的世紀之交,即400年,800年等還是閏年。最終關於閏年的規定爲,用4除盡的年份還是閏年。教皇訓令也批准了這個校訂。通過這兩個校訂的朱利安曆法叫格利戈裏曆法,也就是咱們如今用的公曆。因爲格利戈裏曆法中的年與太陽年仍有偏差,還須要進一步校訂,不過兩者只相差25.96秒,每過2800年才相關一天,在實際生活中沒什麼影響。這樣,1900年不是閏年,但2000年是閏年,每400年才遇到一次!又一個特殊性!

  格利戈裏曆法很快在羅馬天主教勢力範圍被廣泛接受,可是在英國卻引發了一片喧囂的反對聲,英國人仍然堅持朱利安曆法,拒絕「抹掉10天」。直到1752年,英國人才想通,理性終於佔了上風,不過從1582年到那時,曆法又多出了1天,因此英國議會在1752年做出決定,抹掉11天----1752年9月3日至13日,至此才接受了格利戈裏的改革。請注意,英國曆史中,這11天什麼也沒有發生。由此能夠看到,一次曆法改革是多麼不容易,對於一個聰明、合理的決定,僅僅由於看上去有點怪就有人反對,居然花了快二百年才接受!

       附錄一個基姆拉爾森計算公式C語言程序

#include "stdio.h"

void CaculateWeekDay(int y,int m, int d)
{
    if(m==1||m==2) {
        m+=12;
        y--;
    }
    int iWeek=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;
    switch(iWeek)
    {
    case 0: printf("星期一\n"); break;
    case 1: printf("星期二\n"); break;
    case 2: printf("星期三\n"); break;
    case 3: printf("星期四\n"); break;
    case 4: printf("星期五\n"); break;
    case 5: printf("星期六\n"); break;
    case 6: printf("星期日\n"); break;
    }
} 
void main()
{
    int year=0,month=0,day=0;
    printf("請輸入日期:\n格式爲:1900,1,1\n");
    char temp = '1';
    while (temp != '0')
    {
        scanf("%d,%d,%d",&year,&month,&day);
        scanf("%c",&temp);
        CaculateWeekDay(year,month,day);
        printf("輸入0退出,其餘繼續:");
        scanf("%c",&temp);
    }
}

運行效果:
請輸入日期:
格式爲:1900,1,1
2008,4,29
星期二
輸入0退出,其餘繼續:d
2008,1,1
星期二
輸入0退出,其餘繼續:l
2008,8,8
星期五
輸入0退出,其餘繼續:0
請按任意鍵繼續. . .

(根據網絡資料整理)

出處:http://blog.renren.com/share/112875057/8739219718

相關文章
相關標籤/搜索