Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

計算古六曆的代碼 #2

Closed
ytliu0 opened this issue Jul 10, 2019 · 12 comments
Closed

計算古六曆的代碼 #2

ytliu0 opened this issue Jul 10, 2019 · 12 comments

Comments

@ytliu0
Copy link
Owner

ytliu0 commented Jul 10, 2019

回應kanasimi的問題:

**不曉得這邊的古六曆,是否有可能匯出成

1.第一欄是當年的歲首JDN
2.第二欄是所有當年月份的日數

這樣的形式呢?例如 春秋曆:

1457728 29;30;29;30;29;30;30;29;30;29;30;29**

下面的 JavaScript 程式應該可以滿足你的要求。這是按照這裡古六曆網頁的方法寫的,置閏法則採用固定冬至法。

// 古六曆參數
function guliuli_calendar_parameters(li) {
    var jdM0, JDw, jian=0;
    switch(li) {
        case "Zhou":
            // 周曆
            jdM0 = 1683430.5001; 
            JDw = 1721050.5001 + 0.75;
            break;
        case "Huangdi":
            // 黃帝曆
            jdM0 = 1783510.5001; 
            JDw = 1721052.5001 + 0.25;
            break;
        case "Yin":
            // 殷曆
            jian = 1; // 建丑
            jdM0 = 1704250.5001;
            JDw = 1721051.5001 + 0.5;
            break;
        case "Lu":
            // 魯曆
            jdM0 = 1545728.5001 + 419.0/940
            JDw = 1721050.5001;
            break;
        case "Zhuanxu":
            // 顓頊曆
            jian = -1; // 建亥
            jdM0 = 1726575.5001;
            JDw = 1721050.5001 + 19.0/32;
            break;
        case "Xia1":
            // 夏曆(冬至版)
            jian = 2; // 建寅
            jdM0 = 1883590.5001;
            JDw = 1721053.5001 + 0.75;
            break;
        case "Xia2":
            // 夏曆(雨水版)
            jian = 2; // 建寅
            jdM0 = 1883650.5001;
            JDw = 1721052.5001 + 0.875;
            break;
        default:
            console.log("這裡沒有 "+li+" 的曆法數據.");
     }
     return {jian:jian, jdM0:jdM0, JDw:JDw};
}

// 古六曆計算函數
function guliuli(li, y) {
    // 朔策和歲實
    var lunar = 29 + 499.0/940, solar = 365.25;
    // 讀取曆法參數
    var p = guliuli_calendar_parameters(li);
    // 天正冬至的儒略日數
    var Z11 = p.JDw + y*solar;
    // 建子月朔(天正經朔)
    var i = Math.floor((Math.floor(Z11 + 0.5) + 0.5 - p.jdM0)/lunar);
    var Mzi = p.jdM0 + i*lunar;
    // 此歲有閏月?
    var leap = (Mzi + 13*lunar > Math.floor(Z11+solar+0.5)+0.5 ? 0:1);
    // 年首月建的朔 (顓頊曆:十月, 其他曆法:正月)
    var M1 = Mzi + p.jian*lunar;

    // 年首月建為建丑或建寅的曆法
    if (p.jian > 0) {
        // 閏月使正月推遲一個月
        M1 += leap*lunar;
        // 下一歲建子月及冬至
        Mzi += (12+leap)*lunar;
        Z11 += solar;
        // 下一歲歲有閏月?
        leap = (Mzi + 13*lunar > Math.floor(Z11+solar+0.5)+0.5 ? 0:1);
    }

    var Mi = M1 + 0.5;
    var cm = [Math.floor(Mi), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    for (i=1; i<13+leap; i++) {
        cm[i] = Math.floor(Mi + lunar) - Math.floor(Mi);
        Mi += lunar;
    }
    return cm;
}

用法:
執行 guliuli(曆法, 公曆年份) 就會輸出一個Array,含有[歲首JDN, 日數, 日數, ..., 日數],如果Array的長度是13,則該年沒有閏月,如果Array的長度是14,最後一個數字是閏月的日數(閏月總是置於年終)。

例:
console.log(guliuli("Zhou", -386));
輸出:
[ 1580043, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30 ]
就是古六曆網頁例一的結果。

console.log(guliuli("Xia1", -386));
輸出:
[ 1580131, 30, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30 ]
就是古六曆網頁例二的結果。

如果要把數據分成你說的兩欄也不難,例如:
for (var y=-479; y <= -221; y++) {
var cm = guliuli("Zhou", y);
console.log(cm.shift(), cm.join(';'));
}
這就印出了從-479年到-221年的周曆數據。

我檢查了幾個年份和幾部古六曆都沒有錯,但是還是建議您再檢查一下以防有bug,如果發現有 bug 請告知。

最後要說的是春秋曆不是古六曆,不能用古六曆的方法計算,因為其置閏沒有常規,需要另外用Array儲存有閏月的年份。

@kanasimi
Copy link

回應kanasimi的問題
#1

@kanasimi
Copy link

kanasimi commented Jul 10, 2019

這邊之前也研究過古六歷
可惜一直未對上
沒敢放進工具

之前看過許名瑲老師的推步方法
http://www.bsm.org.cn/show_article.php?id=2372

另外這個工具也列出了古六歷的計算方法
https://github.com/suchowan/when_exe/blob/e21141c61740c636ce6fbad65c980572253af6ef/lib/when_exe/region/chinese/twins.rb#L106

看起來推步的時候
這兩個來源採用近元的方法
https://github.com/kanasimi/CeJS/blob/25714b1774fb49b9ba4632fb17c7098840d86115/data/date/calendar.js#L5507

您或可參考看看

另外不知為何
https://ytliu0.github.io/ChineseCalendar/table_chinese.html
這邊的曆譜有的日期似乎會超過十二月
不曉得是不是正常情況呢

@kanasimi
Copy link

請問
https://ytliu0.github.io/ChineseCalendar/guliuli_chinese.html
表 一: 古 六 曆 的 上 元 積 年 數 據
曆元日干支、 氣朔關係

這一段不曉得在哪邊有介紹呢

@ytliu0
Copy link
Owner Author

ytliu0 commented Jul 10, 2019

謝謝您的資料! 那裡好像有其他曆法的計算,我正想撰寫古代曆法的一般計算法,或可比較各家的計算方法。

另外不知為何這邊的曆譜有的日期似乎會超過十二月

可以舉個例子嗎? 如果你是指列出的公曆日期,那是因為我說:
"列出...農曆每月初一的公曆日期 MM-DD。MM代表公曆月份,DD代表公曆日期。MM=13 表示下一個公曆年的1月。"

請問https://ytliu0.github.io/ChineseCalendar/guliuli_chinese.html 表 一: 古 六 曆 的 上 元 積 年 數 據/ 曆元日干支、 氣朔關係/ 這一段不曉得在哪邊有介紹呢

我最初是從張培瑜的《中国先秦史历表》書中前言看到的,後來也見於張培瑜、陳美東、薄樹人和胡鐵珠著的《中国古代历法》,但後者的敘述並不比前者詳細。我算出來的古六曆和張培瑜著的《中国先秦史历表》和《三千五百年历日天象》核對過,結果是一致的。這樣我才有信心把結果列出來,並撰文解釋我的算法。

@ytliu0
Copy link
Owner Author

ytliu0 commented Jul 11, 2019

張培瑜的《中国先秦史历表》可以在以下網址免費閱讀:
https://max.book118.com/html/2019/0113/5002014204002001.shtm

我的古六曆知識有90%就是看書中前言的第3-6頁學會的。

@kanasimi
Copy link

許名瑲老師在計算曆譜的時候
似乎都會加上朔餘跟節氣小餘
http://www.bsm.org.cn/show_article.php?id=2262
image

這邊也照著處理過
供您參考

image

@kanasimi
Copy link

這邊採用另一個推步方法
也實作出了古六曆

和 青川郝家坪秦牘《田律》曆日考釋
http://www.bsm.org.cn/show_article.php?id=2372
比較的結果
除了殷曆差一個月(但這邊做出的和您的歷表相符合 不曉得是不是許名瑲老師另外做過調整)
以及魯曆的朔餘有差別之外
https://github.com/kanasimi/CeJS/blob/23d98a78f50ee4eb2672d3089eb5c206c8c74df3/data/date/calendar.js#L5465
其他部分月序數和朔餘 節氣小餘都能夠重現出來了
謝謝您幫忙提供意見

@ytliu0
Copy link
Owner Author

ytliu0 commented Jul 11, 2019

感謝您提供的資料和建議!

許名瑲老師的計算和《中国古代历法》介紹的算法是一致的,但他採用閏餘法以閏餘不少於12的年份置閏,和《中国先秦史历表》的固定冬至置閏法稍有不同。拙文「古六曆計算法」說明兩者除了在顓頊曆和夏曆的計算中有時閏月會出現差異外,其餘的結果是相同的。他的魯曆朔餘不同,應該是他因為他用了《開元占經》的上元積年數:

魯曆上元庚子至今276 1334年算外,相當前276 0621年,近元在前1821年。

至於殷曆差一個月的問題,我對此也感到困惑。拙文「古六曆計算法」註三提到「張培瑜在《中国先秦史历表》、《三千五百年历日天象》和《中国古代历法》第三章都說殷曆以建子為年首,和一般的說法不同,卻沒有解釋為什麼持這不同說法。」看來許名瑲也是認為殷曆的建正是建子,這是什麼原故,我至今不明。我的殷曆是按建丑來算的。

順便問一下,您認識參與維基百科古六歷的編者嗎? 前兩天我發現拙文「古六曆計算法」竟然被徵引,感到十分意外。

關於朔餘跟節氣小餘的建議,我有些看法和問題,稍後再說。

@kanasimi
Copy link

那個維基百科古六歷的編者就是小弟啦
有優秀的文章自然應該引薦一下😄

@ytliu0
Copy link
Owner Author

ytliu0 commented Jul 11, 2019

原來如此! 我也猜測那個維基百科的編者可能是您或是和您有聯繫的人,所以才有此一問。真感謝你對拙文的謬贊。該文只是我對古六曆學習的一點心得,還是應該請古六曆專家指教,看看有沒有錯。

關於增加氣朔小餘一事。我也認為小餘對於您我編算古曆者來說很有價值,我在春秋魯曆算法一文中說了這裡的春秋曆是根據《中国古代历法》表 3-7列出的朔小餘推出的。

這裡沒有把小餘列出,是有兩個原因。其一是除了曆算者外,其他人對此興趣不大。其二是我想建立一個統一的系統,如果真要提供氣朔小餘,就不應該只限於古六曆,其他曆法的小餘也當列出,這就有困難了。對於唐朝以前的曆法問題不大,因為用平朔平氣法計算很簡單,我的計算基本上完全符合《三千五百年历日天象》的數據。《宣明曆》、《授時曆》和《大統曆》的計算也問題不大,只是在唐宋幾百年間的很多定朔計算我還沒有完全掌握,尤其對進朔法的具體計算了解不深。更麻煩的是有幾部曆法失傳了,我在編制遼金的曆法時就遇到了這個問題。這裡的年曆網頁裡的古代日曆都會列出按當時曆法計算的曆書節氣日期,我在宋遼金元朔閏異同表表末的備註說明遼金時期的《調元曆》和賈俊《大明曆》已失傳,我就只能免強用《宣明曆》和趙知微的《重修大明曆》計算947年到1136年遼金曆書節氣,然後調正6個與朔日不符的節氣日期。

至於清朝,我聽說故宮博物院收藏了清朝每年編的《大清時憲書》,內有月相和節氣時刻,但我不知道到哪裡去找這些數據。我對清朝曆法沒有深入研究,最近下載了《曆象考成》和《曆象考成後編》的電子版。但是文言文對我來說不易看懂,如果不是沒有辦法我不想去看。您知不知道有什麼好的書藉和文章介紹清朝《時憲曆》的計算方法?

@kanasimi
Copy link

kanasimi commented Jul 11, 2019

小弟工具的目的是為了能夠轉換歷史上實際施行、使用過的曆數
沒有深入研究過還原曆法

關於時憲曆的計算
不曉得秦一男教授
https://www.facebook.com/notes/%E7%A7%A6%E4%B8%80%E7%94%B7/%E8%BE%B2%E6%9B%86%E4%B8%8D%E6%98%AF%E6%99%82%E6%86%B2%E6%9B%86%E4%B8%8D%E8%A6%81%E5%86%8D%E4%BB%A5%E8%A8%9B%E5%82%B3%E8%A8%9B%E4%BA%86/2146447082079198/
是不是有些經驗 或許可請教秦一男教授

@ytliu0
Copy link
Owner Author

ytliu0 commented Jul 11, 2019

這裡的資料也是盡量以實曆為依歸,實在找不道資料時才用復原計算。而且所有自己計算必需與其他可靠的資料核對過才會放上來,也會盡量撰文解釋算法。所以如果能找到《大清時憲書》資料就最好。

@ytliu0 ytliu0 closed this as completed Feb 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants