kowala's home

kowala's home
這裡是我的學習筆記,陸續增加中。
http://kowala21.blogspot.com

2012-09-02

農曆程式概念探討(3)

kowala's home
http://kowala21.blogspot.com

開始演算法部分,從哪裡開始呢?先從能夠獨立的模塊開始好了。

二十四節氣

原作者基本上是使用查表法,依照陽曆的節氣順序來定義表格,從陽曆1/1開始,首先遇到的節氣不是"立春",而是"小寒",是在1/6日,幾乎每年都固定在這一天,作者分別計算各節氣距離這基準點的分鐘數而製成下表。

var sTermInfo=new Array(
0,21208,42467,63836,85337,107014,128867,150921,173149,195551,218072,240693,263343,285989,308563,331033,353350,375494,397447,419210,440795,462224,483532,504758);

前面的說明可知,地球繞日的軌道是橢圓,所以並非等速前進,可以參考橢圓軌道的計算方法,或是直接查表,這程式開始是西元1900年,我們把它的數據套進Excel中試算,可以得到上表相同的結果,如圖二所示。

圖一、 二十四節氣時刻


圖二、 二十四節氣時刻試算[3]

先計算出從1/1到1/6日"小寒"經過的秒數525837,令它為基準 0,爾後各節氣累計秒數皆須減525837,再來把它轉成分鐘,就完成了上表了。

使用上則是計算某日到陽曆1/6日"小寒"所經過的分鐘數,然後查表就可以判定哪個節氣,或是某個節氣落在哪一日了。

原程式可以求得 y 年的第 n 個節氣的日期

function sTerm(y,n) {
   var offDate = new Date(
       ( 31556925974*(y-1900)*1000 + sTermInfo[n]*60*1000  ) + Date.UTC(1900,0,6,2,5)
   );
   return(offDate.getUTCDate());
}

說明
31556925974 = 365.2421990741*24*60*60 = 一個回歸年秒數
31556925974*(y-1900)*1000 = y 年距離基準年(1900)的毫秒數
sTermInfo[n]*60*1000 = 第 n 個節氣距離"小寒"的毫秒數
Date.UTC(1900,0,6,2,5)  = 基準年
所以
offDate = (y年毫秒數+第n個節氣毫秒數+ 基準年小寒毫秒數)
轉回日期格式
offDate.getUTCDate()

生肖定位

原作者是取陽曆年來對應生肖,其實應該要取陰曆年才對,不過沒關係,我們就假裝不知道,繼續討論下去。
十二生肖就是12年一循環,如下陣列 Animals[12],所以只要除以12取餘數就能定位了,但是 1900 年是鼠年,應該對應餘數 0,但 1900 不是剛好整除 12,所以要調整為整除,就是1900-4=1896,這樣就恰好整除,對應"鼠"年了。

西元 1900-1-31 光緒26 年 - 農曆歲次-庚子年元月初一【鼠】

先宣告一個十二生肖陣列

var Animals=new Array("鼠","牛","虎","兔","龍","蛇","馬","羊","猴","雞","狗","豬");



var sy=1900;
Animals[(sy-4)%12];

這樣就會取到"鼠"了。


干支定位

中國早在商朝時代,就已經開始使用干支記日了[1],那什麼是干支的規則呢,干支就是天干地支,天干有十地支十二,分別列出如下。

天干 = 甲,乙,丙,丁,戊,己,庚,辛,壬,癸
地支 = 子,丑,寅,卯,辰,巳,午,未,申,酉,戌,亥

配對規則就是天干配地支,依序循環。

第一個天干配第一個地支,就是甲子。
第二個天干配第二個地支,就是乙丑。
第三個天干配第三個地支,就是丙寅。
...
到了第十個就是
第十個天干配第十個地支,就是癸酉。

第十一個呢,就變成天干又重頭開始了
第十一個天干配第十一個地支,就是甲戌。
第十二個天干配第十二個地支,就是乙亥。

所以第十三個換地支重頭開始。
第十三個天干配第十三個地支,就是丙子。
如此循環不已,到了下次甲子,剛好60年一循環。

干支60年各年份名稱
甲子     乙丑     丙寅     丁卯     戊辰     己巳     庚午     辛未     壬申     癸酉
甲戌     乙亥     丙子     丁丑     戊寅     己卯     庚辰     辛巳     壬午     癸未
甲申     乙酉     丙戌     丁亥     戊子     己丑     庚寅     辛卯     壬辰     癸巳
甲午     乙未     丙申     丁酉     戊戌     己亥     庚子     辛丑     壬寅     癸卯
甲辰     乙巳     丙午     丁未     戊申     己酉     庚戌     辛亥     壬子     癸丑
甲寅     乙卯     丙辰     丁巳     戊午     己未     庚申     辛酉     壬戌     癸亥

知道60年一甲子後,該是把今年定位到干支表上,概念是這樣的,必須先找個基準點,然後求出距離幾年,再查表取出干支。
以甲子年為基準年來算,我們很容易可以查到  甲子年有 公元1864年,1924年,1984年。
 
方法1.取1864年為基準,那今年2012年,距離就是

 2012-1864=148年 +1(種樹問題要加1,別跟我說沒種過樹 = =)
 149=60+60+29 => 第 29 個序列  => 壬辰

方法2.干支個別取法,因為陣列索引由 0 起算,所以不用+1
           
天干取 148 % 10 =  8 => 壬
地支取 148 % 12 =  4 => 辰

原作程式寫法就是這樣子(程式寫的真好 ^^)

var Gan=new Array("甲","乙","丙","丁","戊","己","庚","辛","壬","癸");
var Zhi=new Array("子","丑","寅","卯","辰","巳","午","未","申","酉","戍","亥");

function cyclical(num) {
   return(Gan[num%10]+Zhi[num%12]);
}


var year=2012;
cyclical(year-1864);

方法3.或是取公倍數定位法
已知 1924 年為甲子年,該年餘數必須調整為 0,
即 (1924-x)%60 = 0,可得 x 最小為 4

var year=2012;
cyclical(year-4);

這樣也可以取得正確的干支。
上述三種方法都可以正確定位,任選一種使用即可。


民國定位

今年西元 2012 等於民國 101年,兩者差為 2012-101=1911年,所以互換的常數就是 1911。

西元 - 1911 = 民國
民國 + 1911= 西元

我們可以寫個轉換式如下

function getMG(year) {
   return('民國 '+(year-1911)+' 年');
}

getMG(2012);  //取得民國年


共和國定位

共和國是大陸地區使用的記年,全名是中華人民共和國,這裡不上歷史課,簡單說明就好,要深入了解的,自己去查,民國全名是中華民國的簡稱,是國父孫中山先生所創立,後經過了國共之戰,民國38年後,分裂為兩個地區,大陸地區由毛澤東領導,以共和國紀年,台灣地區由蔣中正領導沿用中華民國記年。

民國38年大陸地區為共和國元年

民國38年 + 1911 = 1949 = 共和國元年

所以

西元 - 1949 = 共和國
共和國 + 1949= 西元

//西元 to 共和國
function getGB(year) {
   return('共和國 '+(year-1949)+' 年');
}

若要互換

民國 - 38 = 共和國
共和國 + 38 = 民國

//民國 to 共和國
function getB2G(year) {
   return('共和國 '+(year-38)+' 年');
}

//共和國 to 民國
function getG2B(year) {
   return('民國 '+(year+38)+' 年');
}


佛曆年定位

西元1950年,首屆「世界佛教徒友誼會」在錫蘭首都可倫坡舉辦。會中議決:佛陀誕生於西元前623年,成道於西元前588年,去世於西元前543年。1954年,該年會於緬甸仰光舉行,會中再決議佛教國家以「佛曆」紀元,並以釋迦牟尼涅槃年推算,西元1954年為佛曆2497年。[2]

所以佛曆與西元互換的常數就是 2497-1954 = 543

西元 + 543 = 佛曆
佛曆  - 543 = 西元

轉換式如下

function getBD(year) {
   return('佛曆 '+(year+543)+' 年'); 
}

getBD(2012); //取得佛曆年


待續...

參考資料
1.  维基百科干支  http://zh.wikipedia.org/wiki/干支
2.  维基百科佛曆年 http://zh.wikipedia.org/zh-tw/佛曆
3.  1900年二十四節氣表.xls https://docs.google.com/open?id=0B9_qAWWvUIuUSFh1V3lqcnhLdVU

沒有留言:

張貼留言

請提供您的寶貴意見 ;-)