第八週練習寫一個萬年曆程式, 注意西元曆法曾經調整過 !
  羅馬曆法在1582年10月調整, 但是英美等國是在1752年9月才調整,
  這題原則上照美國的西元曆法,
  這次的習題是要寫一個方便查詢的萬年曆, 
  可依使用者要求輸出一年年曆或一個月的月曆, 甚至只輸出星期幾。
    輸入 38 代表要印出西元 38 年整年年曆,
    輸入 12 38 代表要列印西元 38 年 12 月的月曆,
    輸入 25 12 38 代表要問西元38年的12月25日是星期幾;
進階(可第九週再做):
 ** 若輸入字串中含有 "CH" 或是"CN, 不管大寫小寫,
   表示要照中國用的西元曆法!(1911/12/18隔日是1912/01/01)!
   關於美國與中國的西元曆法有何不同可看Unix系統的ncal命令 !

  這題的重點除了練習排版印出外, 還要知道閏年的算法, 以及參考點
  的日期是星期幾, 還有要知道美國1752年九月之前閏年算法不同:
bsd% 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 
  以及各國調整曆法的日期並不相同(參看Unix的 ncal命令)
 **現在你可以自己用gogle.com查資料看
 **後面有更多的提示

 Hint: 這個問題一開始會覺得很難, 因為不知道從何下手。
    但是其實很簡單, 它只是很煩!
  (1)首先, 要從輸入字串中找出要做甚麼, 這交給一個小弟function找;
    先查看輸入字串中有沒有 "CN" 或 "CH", 記下來,
        然後把字串中所有 isalpha(x) 成立的都換成空白,
        接著可以利用 sscanf( ) 從該字串中試著讀去三個整數:
        k = sscanf(buf, "%d %d %d", &ds, &mm, &yyyy);
        這時察看 k 就知道讀到幾個整數!
  (2)然後, 當然須知道 1/01/01 這天是星期幾? 星期六啦!
       不過請注意, 這不是唯一的參考點!
       可能的參考點請看(4)說明。 
  (3)接著, 要能知道每年是閏年還是平年? 
    這個也可交給一個小弟(function)去做! 
    例如 isleap(n) 若是 n 為閏年, 就回傳 1, 否則回傳 0。
    這樣看起來就可以算出任何一天是星期幾的吧!? 
   阿不過, 鳩多媽爹! 還有一件很重要的事情你必須知道!
       不然閏年也會判斷錯誤, 要考慮下一點(4)中說明!
  (4)阿就是: 若考慮英國美國曆法, 1752年9月要特別處理,
    1752/09/02 星期三, 隔天是 1752/09/14 星期四!
    若考慮中國則在1911年12月18日星期日, 
    隔天就是 1912年1月1日星期一 ! 所以1911年12月只有18天!
    (5)關於(3)的閏年判斷若照英美曆法, 1752年(含)之前都是
    除以 4 除得盡就是閏年; 考慮中國曆法則是 1911年之前
    都是除以 4 除得盡就是閏年!所以要寫到 isleap(n)內!
  (6)至於在調整日之後的閏年算法如下:
    (a) 除以 400 除得盡則是閏年, 否則
    (b) 除以 100 除得盡則不是閏年! 否則
    (c) 除以 4 除得盡則是閏年, 否則是平年 ! 
  (7)為了方便, 可以用一個 Global 變數紀錄是要英美曆法,
    還是要中國曆法? 這變數在各函數中都可以用到!
       有了 isleap(year) 幫忙算 year 是否閏年,
       再來就可給定任何一個日期, 算出它相對於參考點(包括
       1/1/1 或 1752/09/14 或 1912/01/01)差了幾天, 然後
       從隔了幾天就可推算出星期幾 (好好想想用手做如何做?)
  (8)最後是要排列印出來, 因印年曆最好一列印三個月,
    這需要好好安排, 還不太會的, 就印成一個月接著一個月:-)
    不然簡單做法是用三個字串陣列:
     char a[6][33], b[6][33], c[6][33];  // 33 夠用
    因為一個月最多可能誇六週, 每週最多七天要印成最多26字,
    這樣一列共 26*3 = 78 字剛好擺得下:-)
  (9)若要印月曆, 把算好日期擺入 a[][ ]就可用Loop印出!
       為了方便, 可把排一個月各日的工作寫成 function,
       如此一來, 此 function 也可在印年曆時叫用!
   (10)若要印年曆, 用Loop 每次印三個月:
         char a[6][33], b[6][33], c[6][33];  
         int i, k; // year 是你要的年
         for(i=1; i<=10; i+=3) { // 1,2,3; 4,5,6; ...
            putMonth(year, i, a);
            putMonth(year, i+1, b);
            putMonth(year, i+2, c);
            for(k=0; k<=5; ++k) 
                printf("%s%s%s\n", a[k], b[k], c[k];);
         }//for i  
     
========================
補充說明:(關於曆法的調整)
  大家都知道中華民國開國元年一月一日是西元1912/01/01,
那請問前一天是西元何年何月何日? 
錯錯錯! 大部分人都答錯! 
正確答案是1911/12/18ㄝ! 1911年12月只有18天,
請用 Unix 下這命令 ncal -p 以及 ncal -sCN 12 1911 看看便知道!
  原因是世界各國調整西元曆法的日期並不一致!
為何要調整曆法? 當然是因為弄錯了! 
誰弄錯了? 
羅馬帝國的凱薩大帝的天文學家弄錯了! 
怎會弄錯? 
因為地球繞太陽一圈到底多久? 以前弄錯!
  西元曆法是根據地球繞太陽一圈作一年! 可是一年究竟是幾天?
或者說為何會有閏年? 
顯然地, 地球繞太陽一圈不是剛好365天, 也不是剛好366天! 
 在公元1582年之前, 大家一直以為地球繞太陽一圈是 365.25天, 
所以才會每四年多一天(閏年)!
  當然, 那是錯的, 因為地球繞太陽一圈是365.2422天, 不是365.25天!
我們現行的曆法稱為格里曆(Gregorian calendar),就是俗稱的公曆或公元,
這是十六世紀的羅馬教皇Gregorian XIII (格里十三世)針對當時使用的儒略曆
(Julian calendar)進行修訂後,於1582年10月開始實行的。

  在1582年10月4日(含)之前所實行的曆法稱為儒略曆(Julian calendar),
從公元前46年(BC 45)羅馬統治者儒略•凱薩大帝(Julius Caesar)開始實施。
 (Note that 公元前一年是 BC 0, 沒有公元 0 年 )
  在公元4年3月1日以前的閏年是不規則的,
自公元4年後則規定所有4除得盡的年都是潤年,
也就是等於規定一年是365.25天,與真正的回歸年365.2422天相差0.0078天,
  從公元前46年(BC 45)羅馬統治者儒略•凱薩大帝開始實施後,
到格里十三世的一千多年裡,儒略曆累積的誤差已達10天(24節氣都亂掉了),
為了消除這個差額,
格里十三世於是將儒略曆1582年10月4日的隔天訂為格里曆的1582年10月15日>,
把日期去掉十天,就可以讓春分日期又回復到3月21日左右,冬至回到12月22日左右。
所以應該是AD 1 到 AD 1582 年間多算了 12 天,BC 45 到 AD 1 之間少算了2天。
 
    這麼說來應該是1582年的10月只有21天,
那為什麼在 UNIX上用 cal 9 1752 會是1752年的九月憑空消失了11天呢?
 (但是 1582/10 仍是31天 !)
 
這當然又牽涉到統獨問題了.. 
   啥? 
阿不是我們的統獨問題,是美國的 .. (其實應該是新舊教的問題)。
更精確的說是因當時的英皇亨利八世與教宗Gregorian關係惡劣拒絕調整! 
   阿眾所週知,美國大都是英國人跑去新大陸阿後來獨立建國的,歷史太短,
只好懷念"祖國"囉,既然 UNIX 是美國人寫的阿所以 cal 就採用英國的 Gregorian
calendar! 大不列顛(英國)是在 1752 年9月才改用 Gregorian calendar,當時誤差已
達11天,所以該月就憑空消失了11天! (see "man cal")
所以 1752/9/2 是星期三,隔天就是 1752/9/14 星期四。 
   據說當時英國大遊行的盛況比2002/9/28台灣大遊行還熱鬧,
因為租房子的人抗議多繳了11天的房租! 
要求政府應該用免稅來補償! 嘿.嘿..嘿... 

  聰明的同學可能發現問題:
   就是英國美國加拿大等是在 1752年九月才調整, 那就是
這些年: 公元100, 200, 300, 500, 600, 700, 900, 1000, 1100,
以及 1300, 1400, 1500, 1700 這些被都誤認為閏年!
總共十三個年各多算了一天, 共多算了 13天 !
那樣不是該扣回 13 天? 
阿娜怎會1752年9月只有少了 11 天 ? 難道又弄錯?
(大多數天主教國家1582年10月則是扣掉10天, 但錯算12個閏年!)
其實這沒有錯 !
因為在公元前46年到公元開始之間也搞錯但少算了兩個閏年 !
所以兩相抵銷之下, 1752 年9月只扣回 11天!(比1582年時多錯算了1700這年 )

了了吧!

註: 
   節氣是依據國曆, 不是農曆, 別弄錯了!!
 很多人都誤會是農曆,  因為都印在農民曆上 :-)
 其時嚴格說來節氣是要算到時分秒(至少算到時),
   因為是以地球繞太陽繞到某定點為某節氣,
 例如清明節可能是國曆4月4日或4月5日或4月6日;
 今年(2010年)是4月5日卯時(上午5點到7點),
 更正確的說是 2010/04/05 早上 05:31 是清明!
 明年(2011年)清明則是2011/04/05 早上 11:11:14; 
 之前有一年曾經弄錯, 害得一堆印日曆月曆的因重印賠了一屁股!
 主要原因是雖然節氣是依據國曆算出的, 可是中國的時間
 是以子時(晚上11點開始的兩小時)就要算作隔日! 
 也就是說, 4月5日的晚上23:00:00就要算作4月6日!
 當然, 記在農民曆上都會寫到對應的農曆月日時啦。



bsd2% ncal -s CN 12 1911      (CN 代表中國; 可用 ncal -p 看各國代碼)
    December 1911
Mo     5 12
Tu     6 13
We     7 14
Th  1  8 15
Fr  2  9 16
Sa  3 10 17
Su  4 11 18    (中國與台灣 1911年12月只有 18天;因為清朝沒有調整曆法)
bsd2% 

bsd2% ncal -p
 AL Albania        1912-11-30      IT Italy          1582-10-04
 AT Austria        1583-10-05      JP Japan          1918-12-18
 AU Australia      1752-09-02      LI Lithuania      1918-02-01
 BE Belgium        1582-12-14      LN Latin          9999-05-31
 BG Bulgaria       1916-03-18      LU Luxembourg     1582-12-14
 CA Canada         1752-09-02      LV Latvia         1918-02-01
 CH Switzerland    1655-02-28      NL Netherlands    1582-12-14
 CN China          1911-12-18      NO Norway         1700-02-18
 CZ Czech Republic 1584-01-06      PL Poland         1582-10-04
 DE Germany        1700-02-18      PT Portugal       1582-10-04
 DK Denmark        1700-02-18      RO Romania        1919-03-31
 ES Spain          1582-10-04      RU Russia         1918-01-31
 FI Finland        1753-02-17      SI Slovenia       1919-03-04
 FR France         1582-12-09      SW Sweden         1753-02-17
 GB United Kingdom 1752-09-02      TR Turkey         1926-12-18
 GR Greece         1924-03-09     *US United States  1752-09-02
 HU Hungary        1587-10-21      YU Yugoslavia     1919-03-04
 IS Iceland        1700-11-16
You are the -th visitors to this page.


CopyLeft tsaiwn@csie.nctu.edu.tw

--
--------------------
你要我別愛上你 卻又要我想你
難道童心未泯的你 又在玩四月一日的遊戲
愛情竟被你當兒戲 上帝也會生氣
我真的敗給了你