Werden wir Helden für einen Tag

Home | About | Archive

無聊筆記: 公農曆轉換法 #2

Posted on May 20, 2013 by Chung-hong Chan

從上文可見,公農曆轉換計算簡單,但所需的數據甚多,當中包括每年有否閏年,以及每個農曆月的天數。以上兩組數據也可以用計算方法算出,但非常複雜,故此多以查表方式得出數據。
最直接方法就是如此儲在數據。如 2012 年可存為:

[30,29,30,30,29,30,29,30,29,30,29,30,29,4]

Vector (或 array/tuple )頭十三位是每個農曆月日數,最後一位是閏月。如沒有閏月可存為 0 。但市面上見到的數據表,大多是在 liblunar 抽出來,而那數據表如此。

[
    0xF0EA4, 0xF1D4A, 0x52C94, 0xF0C96, 0xF1536, 0x42AAC, 0xF0AD4, 0xF16B2, 0x22EA4, 0xF0EA4,  # 1901-1910
    0x6364A, 0xF164A, 0xF1496, 0x52956, 0xF055A, 0xF0AD6, 0x216D2, 0xF1B52, 0x73B24, 0xF1D24,  # 1911-1920
    0xF1A4A, 0x5349A, 0xF14AC, 0xF056C, 0x42B6A, 0xF0DA8, 0xF1D52, 0x23D24, 0xF1D24, 0x61A4C,  # 1921-1930
    0xF0A56, 0xF14AE, 0x5256C, 0xF16B4, 0xF0DA8, 0x31D92, 0xF0E92, 0x72D26, 0xF1526, 0xF0A56,  # 1931-1940
    0x614B6, 0xF155A, 0xF0AD4, 0x436AA, 0xF1748, 0xF1692, 0x23526, 0xF152A, 0x72A5A, 0xF0A6C,  # 1941-1950
    0xF155A, 0x52B54, 0xF0B64, 0xF1B4A, 0x33A94, 0xF1A94, 0x8152A, 0xF152E, 0xF0AAC, 0x6156A,  # 1951-1960
    0xF15AA, 0xF0DA4, 0x41D4A, 0xF1D4A, 0xF0C94, 0x3192E, 0xF1536, 0x72AB4, 0xF0AD4, 0xF16D2,  # 1961-1970
    0x52EA4, 0xF16A4, 0xF164A, 0x42C96, 0xF1496, 0x82956, 0xF055A, 0xF0ADA, 0x616D2, 0xF1B52,  # 1971-1980
    0xF1B24, 0x43A4A, 0xF1A4A, 0xA349A, 0xF14AC, 0xF056C, 0x60B6A, 0xF0DAA, 0xF1D92, 0x53D24,  # 1981-1990
    0xF1D24, 0xF1A4C, 0x314AC, 0xF14AE, 0x829AC, 0xF06B4, 0xF0DAA, 0x52D92, 0xF0E92, 0xF0D26,  # 1991-2000
    0x42A56, 0xF0A56, 0xF14B6, 0x22AB4, 0xF0AD4, 0x736AA, 0xF1748, 0xF1692, 0x53526, 0xF152A,  # 2001-2010
    0xF0A5A, 0x4155A, 0xF156A, 0x92B54, 0xF0BA4, 0xF1B4A, 0x63A94, 0xF1A94, 0xF192A, 0x42A5C,  # 2011-2020
    0xF0AAC, 0xF156A, 0x22B64, 0xF0DA4, 0x61D52, 0xF0E4A, 0xF0C96, 0x5192E, 0xF1956, 0xF0AB4,  # 2021-2030
    0x315AC, 0xF16D2, 0xB2EA4, 0xF16A4, 0xF164A, 0x63496, 0xF1496, 0xF0956, 0x50AB6, 0xF0B5A,  # 2031-2040
    0xF16D4, 0x236A4, 0xF1B24, 0x73A4A, 0xF1A4A, 0xF14AA, 0x5295A, 0xF096C, 0xF0B6A, 0x31B54,  # 2041-2050
    0xF1D92, 0x83D24, 0xF1D24, 0xF1A4C, 0x614AC, 0xF14AE, 0xF09AC, 0x40DAA, 0xF0EAA, 0xF0E92,  # 2051-2060
    0x31D26, 0xF0D26, 0x72A56, 0xF0A56, 0xF14B6, 0x52AB4, 0xF0AD4, 0xF16CA, 0x42E94, 0xF1694,  # 2061-2070
    0x8352A, 0xF152A, 0xF0A5A, 0x6155A, 0xF156A, 0xF0B54, 0x4174A, 0xF1B4A, 0xF1A94, 0x3392A,  # 2071-2080
    0xF192C, 0x7329C, 0xF0AAC, 0xF156A, 0x52B64, 0xF0DA4, 0xF1D4A, 0x41C94, 0xF0C96, 0x8192E,  # 2081-2090
    0xF0956, 0xF0AB6, 0x615AC, 0xF16D4, 0xF0EA4, 0x42E4A, 0xF164A, 0xF1516, 0x22936,           # 2090-2099
]

以上的數據已包含 1901 至 2099 年的全部數據。經過研究之後,數據結構如此。舉 2012 年的 0x4155A 為例。
將十六進制的 4155A 轉為二進制,就是 1000001010101011010 。二進位是由右讀到左,第 1 至 13 位元就是每個農曆月的天數, 0 為 29 , 1 為 30 。16 位元開始的 100 ,就是閏月月份。 1000 轉成十進制就是 4 。我們可用 Bitwise operator 將以上數據計算出來。以 R 為例,可以用以下方法算出閨月和某月的天數。

bitwShiftR(0x4155A, 16) #4
29 + bitwAnd(bitwShiftR(0x4155A, 1), 1) # Jan = 30 day
29 + bitwAnd(bitwShiftR(0x4155A, 2), 1) # Feb = 29 day

好了,我們已有足夠數據轉換 1901 年 2 月 19 日至 2100 年 2 月 18 日的所有農曆了。戲肉就是寫一個 R function 去將公曆年份轉成農曆。
這個東西已放在我的 github 。順手一提,我正在開發一個叫 hongkong 的 R Package 。而這個公農曆轉換法,實在是用作計算香港的假期。現在已確定 2007 年至 2014 年的公眾假期計算正確。


Powered by Jekyll and profdr theme