关于公历年月日与干支的转化问题

 返回列表 回复 发帖

关于公历年月日与干支的转化问题

本来的题目叫“关于公历年月日、农历月相与干支的转化问题”,但后面一半未写成,公式也未选择好,等不及了先写出简单些的。各位都是高人,举一必能反三。我也是边写边修正,大家多提意见。

一、        前提假设:历史上日子干支是连续的
二、        建立时间坐标:
1、        以公元1年1月0日(即公元前1年12月31日)为原点;
2、        坐标单位是日。
3、        历史日子到原点的距离就是该日子的坐标,称为“公元日序数”,原点前的公元日序数为负,原点后的公元日序数为正。例如公元1年1月1日的公元日序数为1,公元前1年1月1日的公元日序数为-1。每个历史日子只有一个公元日。公元日序数是连续的。

说明:建立时间坐标系统,是编制历法、表格的一般性方法。选取公元历作为时间参照系主要是按因应一般使用习惯,它本身只是一种简单易算的工具,其实选用另一种理想历法并无不可。(按一般历史书的记法,1582年10月4日及以前的普遍用儒略历,1582年10月15日的用格列哥里历,今从此)。

三、        公元日序数的算法:

1、公元1582年10月4日前日子的公元日序数求法:
不难按历法知道:
公元日(P)=365*(年号(Y) -1)+闰年数+ 本年的日数
根据儒略历四年一闰的法则(逢被4整除的均置闰)得:

P = 365*(Y-1)+ [ Y/4] + Q

式中“[   ]”是取整符号;Q是从要算的日子到1月1日的天数加1,由于公历的月份有固定的天数,1、3、5、7、8、10、12是大月31天,4、6、9、11日小月30天,2月份置闰月严格按28天算,(为了直观些,稍后我会用坐标来移及一些数学方法,表述成一条用月、日表示的代数式)。
值得注意的是:闰年时,未到3月1日要减1。

例1、        公元227年5月4日的公元日序数是:365*226+[227/ 4]+31+28+31+30+4=82670
例2、        公元1582年10月4日的公元日序数是:365*1581+[1582/4] + 31*5+30*3+28+4 =577737

2、公元1582年10月15日后的日子的公元日序数求法:
     公元1582年10月15日是公元1582年10月4日的后一天,故其公元日577738(见例2),格列哥里历按四年一闰,被4整除的均置闰,但逢百年时需被400整除的方置闰,其它百年不置,故四百年有97闰。公式为:

P=365*(Y-1)+ [Y/4] - [Y/100] +[ Y/400] +Q+15-3-10
=365*(Y-1)+ [Y/4] - [Y/100] +[ Y/400] +Q +2

式中第2、3、4项是格列哥里历的置闰方法。我们可以对照比1582年以前的置闰方法,多了- [Y/100] +[ Y/400]一项,故需减去 - [1582/100]+[1582/400]以校正之;同时从1582年10月4日到1582年10月15日之间跳过了10日,所以同时减去10,使公元日连续。大家可以代入验算一下,它与此1582年10月4日的序数是连续的。

例3、        公元1582年10月15日的公元日序数:
365*1581+[1582/4]  -  [1582/100] + [1582/400] + 31*5+30*3+28+15+2 =577738
例4、        公元2003年4月2日的公元日序数:
365*2002+[2003/4]  -  [2003/100] + [2003/400] + 31+28+31+2+2 =731309

3、公元前日子的公元日序数求法:
尽管儒略历在公元前46年完成,但以前的日期一般的历史书均按儒略历上推,所以也从约定俗成。儒略历按四年一闰,其公式是:

公元日序数=365*年号(负号)+闰年数(负号)+本年的日数(正号)
  P=  -365*Y - [(Y+3)/4]+Q

公元前的求法与公元后的有所不同:后者的计算方向从年、从月、从日是一路远离原点的;前者则是“年”远离了原点,月、日反过来接近原点,这点大家要记住。
(如果选取一个很前的原点,则可以使序数的方向永远为正,但为了便于一般人理解及习惯,我还是放弃了这样叙述------事实上太初历等古代历法一般选取一个很远的天文日作原点的)

例5、        公元前1年1月1日的公元日序数是:-365*1- [(3+1)/4 ]+1=  -365
例6、        公元前202年2月28日的公元日序数:-365*202 – [(202+3)/4] + 31+28= -73722

我们把三个公式并列如下:
(公式1)
P=  -365*Y - [(Y+3)/4]+Q                      (公元前)
P = 365*(Y-1)+ [ Y/4] + Q                      (公元后至1582年10月4日)
P=365*(Y-1)+ [Y/4] - [Y/100] +[ Y/400] +Q +2      (1582年10月15日后)


(以下一段选读)
事实上我们可将坐标“平移”,将原点移到公元1年2月28日。将3月1日“作为”一年的开端,平移的目的是为了使置闰放在一年的最后一天,减小置闰对各月份的影响。(事实上我开始推导时是用这方法的,求得结果后才平移成现在的方式)如此,作月份相应减小2,(3=1,4=2,…………1月等于上年的11月,2月是12月),公元日序数则相应增加59。如此则Q的值也可用相关的月(M)、日(D)代数式表示:
Q=30(M-1)+[0.6(M-1)+0.5] +D
(这纯是个数学问题,我不想在这里证明。反正是十二个月,大家直接代入看看)
如此变换后的公式变为:Y年M月D日  (M为正常月减2,1月时为11月)
(公式二)
   P=  -365*Y - [(Y+3)/4]+30M+[0.6M-0.1]+D+29                 (公元前)
P = 365*(Y-1)+ [ Y/4] + 30M+[0.6M-0.1]+D+29           (公元后至1582年10月4日)
P=365*(Y-1)+ [Y/4] - [Y/100] +[ Y/400] + 30M+[0.6M-0.1]+D+31 (1582年10月15日后)

四、干支的求法
知道了一个日子的公元日序数是,要求该日子的干支序数是一个很容易容易的事了,思路是:
一已知干支的日子———推出原点的干支序数———推出任一历史日子序数
(读者诸公一定想到用类似的方法求有固定周期的朔望了)
不难知:
  历史日子的干支序数= (原点的干支序数+ 公元日序数)除以60取余数
K=(‘K + P)mod 60     
                       
利用例4,公元2003年4月2日的公元日序数是731309,干支乙巳(序数42)则
42=(‘K+731309)mod 60      ‘K=42-731309= -731267=  -47 =13  mod 60
即原点(公元前1年12月31日)的干支序数为13(丙子),我们将结果代入公式一,则
(公式三)
K=(13+P)mod 60


例7、        求公元1582年10月15日的干支。利用例3的结果有
K=(577738 + 13)mod 60=11,即该日甲戌。

我们将公式三代入公式一,则

K= (-365*Y - [(Y+3)/4]+Q+13 )mod 60                      (公元前)
K= (365*(Y-1)+ [ Y/4] +Q+13 )mod 60                 (公元后至1582年10月4日)
K=(365*(Y-1)+ [Y/4] - [Y/100] +[ Y/400] +Q +15)mod 60      (1582年10月15日后)


我们当然可以使用数学方法将公式化简,以下是我使用的化简式:
(公式四) Y年M月D日(M从三月开始,M相应减2)

K= (-5Y-[(Y+3)/4]+30M+ [0.6M-0.1]+ D+42 ) mod 60             (公元前)
K=(5Y+ [ Y/4] + 30M+ [0.6M-0.1] + D+37)mod 60                     (1~1582:10:4)
K=(5Y+ [Y/4] - [Y/100] +[ Y/400]+ 30M+ [0.6M-0.1]+ D+ 39)mod 60    (1582:10:4以后)

我用手上天文台编的三千年公历干支朔望对照表抽样校对了几个日子,准确无误。可见它也是采用同样原理编订的。
反过来,知道干支及大约的月份,求公元日序数(公元历)只是解方程的问题而已。

五、举例及应用

例8、        汉书所说高祖五年(己亥)二月甲午即皇帝位的,该日的公历是多少?
高祖五年己亥是前202年,二月大约在公历3月附近,干支甲午序数31,代入公式四得
-202*5 – [(202+3)/4]+30*1+[0.6M-0. 1]+D+42 =31 mod 60
整理得  -989+D=31 mod 60   D=(31+989 ) mod 60   D=0  mod 60
解出D=0,或60,即该日是3月0日(2月28日),或过60天以后的4月29日。

验算:严格按儒略历四年一闰的算法,公元前202年2月28日的公元日序数为 –73722,
-73722+13= -73709 =  - 29 =31 mod 60 该日甲午。演算没错!!

六、结语:方法是类似解释几何的的方法:
首先建立一个连续时间坐标,
第二是根据公历的规律建立任意日子到原点间的距离公式(公元日序数)
第三是对于有固定周期的属性(干支、月相等),可从任一已知属性的日子利用与原点的距离推出原点的属性。
第四是根据原点的属性利用某点与原的距离推知该点的属性。
第五公式的化简与选择只是一些技术问题。

我向来粗疏,大家如发觉有逻辑上,或计算上的错误,可告我改正。
 
从来都是查书,这会只能做学生
 

其实最重要的是能计算历史日子与原点间的距离。

其实最重要的是能计算历史日子与原点间的距离P,如此一切有固定周期的均可算出:

星期:
S=(‘S+P)mod 7
干支:
K=(‘K+P)mod 60
二十八宿:
H=(‘H+P)mod 28
月相:
Mo=(‘Mo+P)mod 29.53059

‘S、‘K、‘H、‘Mo等都是原点的属性,可用待定系数法求出。



[此贴子已经被作者于2003-4-4 13:04:15编辑过]

 
我晕!

我向来对数字和符号头痛!

看来只好叫兄台换算好后告诉我啦!
 
很高興在國學網的朋友也懂程式設計!
在陳遵媯先生的《中國天文學史》(二)的1373頁
,有個簡單的換算公式,經過初步驗算,是準確
的。打算用簡單的Perl語言把它寫出來讓大家用
,如果有朋友懂程式,會把該公式內容以Images
放上來,很希望有朋友能來共襄盛舉!讓我們把
它寫出來!
 
南山兄,水电工,大家都在等你们俩的精彩表演。
 

英雄所见略同

以下是引用又见南山在2003-4-2 13:31:46的发言:
本来的题目叫“关于公历年月日、农历月相与干支的转化问题”,但后面一半未写成,公式也未选择好,等不及了先写出简单些的。各位都是高人,举一必能反三。我也是边写边修正,大家多提意见。

一、&nbsp前提假设:历史上日子干支是连续的
二、&nbsp建立时间坐标:
1、&nbsp以公元1年1月0日(即公元前1年12月31日)为原点;
2、&nbsp坐标单位是日。
3、&nbsp历史日子到原点的距离就是该日子的坐标,称为“公元日序数”,原点前的公元日序数为负,原点后的公元日序数为正。例如公元1年1月1日的公元日序数为1,公元前1年1月1日的公元日序数为-1。每个历史日子只有一个公元日。公元日序数是连续的。

说明:建立时间坐标系统,是编制历法、表格的一般性方法。选取公元历作为时间参照系主要是按因应一般使用习惯,它本身只是一种简单易算的工具,其实选用另一种理想历法并无不可。(按一般历史书的记法,1582年10月4日及以前的普遍用儒略历,1582年10月15日的用格列哥里历,今从此)。

三、&nbsp公元日序数的算法:

1、公元1582年10月4日前日子的公元日序数求法:
不难按历法知道:
公元日(P)=365*(年号(Y)&nbsp-1)+闰年数+&nbsp本年的日数
根据儒略历四年一闰的法则(逢被4整除的均置闰)得:

P&nbsp=&nbsp365*(Y-1)+&nbsp[&nbspY/4]&nbsp+&nbspQ

式中“[&nbsp&nbsp&nbsp]”是取整符号;Q是从要算的日子到1月1日的天数加1,由于公历的月份有固定的天数,1、3、5、7、8、10、12是大月31天,4、6、9、11日小月30天,2月份置闰月严格按28天算,(为了直观些,稍后我会用坐标来移及一些数学方法,表述成一条用月、日表示的代数式)。
值得注意的是:闰年时,未到3月1日要减1。

例1、&nbsp公元227年5月4日的公元日序数是:365*226+[227/&nbsp4]+31+28+31+30+4=82670
例2、&nbsp公元1582年10月4日的公元日序数是:365*1581+[1582/4]&nbsp+&nbsp31*5+30*3+28+4&nbsp=577737

2、公元1582年10月15日后的日子的公元日序数求法:
&nbsp&nbsp&nbsp&nbsp&nbsp公元1582年10月15日是公元1582年10月4日的后一天,故其公元日577738(见例2),格列哥里历按四年一闰,被4整除的均置闰,但逢百年时需被400整除的方置闰,其它百年不置,故四百年有97闰。公式为:

P=365*(Y-1)+&nbsp[Y/4]&nbsp-&nbsp[Y/100]&nbsp+[&nbspY/400]&nbsp+Q+15-3-10
&nbsp=365*(Y-1)+&nbsp[Y/4]&nbsp-&nbsp[Y/100]&nbsp+[&nbspY/400]&nbsp+Q&nbsp+2

式中第2、3、4项是格列哥里历的置闰方法。我们可以对照比1582年以前的置闰方法,多了-&nbsp[Y/100]&nbsp+[&nbspY/400]一项,故需减去&nbsp-&nbsp[1582/100]+[1582/400]以校正之;同时从1582年10月4日到1582年10月15日之间跳过了10日,所以同时减去10,使公元日连续。大家可以代入验算一下,它与此1582年10月4日的序数是连续的。

例3、&nbsp公元1582年10月15日的公元日序数:
365*1581+[1582/4]&nbsp&nbsp-&nbsp&nbsp[1582/100]&nbsp+&nbsp[1582/400]&nbsp+&nbsp31*5+30*3+28+15+2&nbsp=577738
例4、&nbsp公元2003年4月2日的公元日序数:
365*2002+[2003/4]&nbsp&nbsp-&nbsp&nbsp[2003/100]&nbsp+&nbsp[2003/400]&nbsp+&nbsp31+28+31+2+2&nbsp=731309

3、公元前日子的公元日序数求法:
尽管儒略历在公元前46年完成,但以前的日期一般的历史书均按儒略历上推,所以也从约定俗成。儒略历按四年一闰,其公式是:

公元日序数=365*年号(负号)+闰年数(负号)+本年的日数(正号)
&nbsp&nbspP=&nbsp&nbsp-365*Y&nbsp-&nbsp[(Y+3)/4]+Q

公元前的求法与公元后的有所不同:后者的计算方向从年、从月、从日是一路远离原点的;前者则是“年”远离了原点,月、日反过来接近原点,这点大家要记住。
(如果选取一个很前的原点,则可以使序数的方向永远为正,但为了便于一般人理解及习惯,我还是放弃了这样叙述------事实上太初历等古代历法一般选取一个很远的天文日作原点的)

例5、&nbsp公元前1年1月1日的公元日序数是:-365*1-&nbsp[(3+1)/4&nbsp]+1=&nbsp&nbsp-365
例6、&nbsp公元前202年2月28日的公元日序数:-365*202&nbsp–&nbsp[(202+3)/4]&nbsp+&nbsp31+28=&nbsp-73722

我们把三个公式并列如下:
(公式1)
P=&nbsp&nbsp-365*Y&nbsp-&nbsp[(Y+3)/4]+Q&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp(公元前)
P&nbsp=&nbsp365*(Y-1)+&nbsp[&nbspY/4]&nbsp+&nbspQ&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp(公元后至1582年10月4日)
P=365*(Y-1)+&nbsp[Y/4]&nbsp-&nbsp[Y/100]&nbsp+[&nbspY/400]&nbsp+Q&nbsp+2&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp(1582年10月15日后)


(以下一段选读)
事实上我们可将坐标“平移”,将原点移到公元1年2月28日。将3月1日“作为”一年的开端,平移的目的是为了使置闰放在一年的最后一天,减小置闰对各月份的影响。(事实上我开始推导时是用这方法的,求得结果后才平移成现在的方式)如此,作月份相应减小2,(3=1,4=2,…………1月等于上年的11月,2月是12月),公元日序数则相应增加59。如此则Q的值也可用相关的月(M)、日(D)代数式表示:
Q=30(M-1)+[0.6(M-1)+0.5]&nbsp+D
(这纯是个数学问题,我不想在这里证明。反正是十二个月,大家直接代入看看)
如此变换后的公式变为:Y年M月D日&nbsp&nbsp(M为正常月减2,1月时为11月)
(公式二)
&nbsp&nbsp&nbspP=&nbsp&nbsp-365*Y&nbsp-&nbsp[(Y+3)/4]+30M+[0.6M-0.1]+D+29&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp(公元前)
P&nbsp=&nbsp365*(Y-1)+&nbsp[&nbspY/4]&nbsp+&nbsp30M+[0.6M-0.1]+D+29&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp(公元后至1582年10月4日)
P=365*(Y-1)+&nbsp[Y/4]&nbsp-&nbsp[Y/100]&nbsp+[&nbspY/400]&nbsp+&nbsp30M+[0.6M-0.1]+D+31&nbsp(1582年10月15日后)

四、干支的求法
知道了一个日子的公元日序数是,要求该日子的干支序数是一个很容易容易的事了,思路是:
&nbsp一已知干支的日子———推出原点的干支序数———推出任一历史日子序数
(读者诸公一定想到用类似的方法求有固定周期的朔望了)
&nbsp不难知:
&nbsp&nbsp历史日子的干支序数=&nbsp(原点的干支序数+&nbsp公元日序数)除以60取余数&nbsp
&nbspK=(‘K&nbsp+&nbspP)mod&nbsp60&nbsp&nbsp&nbsp&nbsp&nbsp
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
利用例4,公元2003年4月2日的公元日序数是731309,干支乙巳(序数42)则
42=(‘K+731309)mod&nbsp60&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp‘K=42-731309=&nbsp-731267=&nbsp&nbsp-47&nbsp=13&nbsp&nbspmod&nbsp60
即原点(公元前1年12月31日)的干支序数为13(丙子),我们将结果代入公式一,则
(公式三)
K=(13+P)mod&nbsp60


例7、&nbsp求公元1582年10月15日的干支。利用例3的结果有
K=(577738&nbsp+&nbsp13)mod&nbsp60=11,即该日甲戌。

我们将公式三代入公式一,则

K=&nbsp(-365*Y&nbsp-&nbsp[(Y+3)/4]+Q+13&nbsp)mod&nbsp60&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp(公元前)
K=&nbsp(365*(Y-1)+&nbsp[&nbspY/4]&nbsp+Q+13&nbsp)mod&nbsp60&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp(公元后至1582年10月4日)
K=(365*(Y-1)+&nbsp[Y/4]&nbsp-&nbsp[Y/100]&nbsp+[&nbspY/400]&nbsp+Q&nbsp+15)mod&nbsp60&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp(1582年10月15日后)


我们当然可以使用数学方法将公式化简,以下是我使用的化简式:
(公式四)&nbspY年M月D日(M从三月开始,M相应减2)

K=&nbsp(-5Y-[(Y+3)/4]+30M+&nbsp[0.6M-0.1]+&nbspD+42&nbsp)&nbspmod&nbsp60&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp(公元前)
K=(5Y+&nbsp[&nbspY/4]&nbsp+&nbsp30M+&nbsp[0.6M-0.1]&nbsp+&nbspD+37)mod&nbsp60&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp(1~1582:10:4)
K=(5Y+&nbsp[Y/4]&nbsp-&nbsp[Y/100]&nbsp+[&nbspY/400]+&nbsp30M+&nbsp[0.6M-0.1]+&nbspD+&nbsp39)mod&nbsp60&nbsp&nbsp&nbsp&nbsp(1582:10:4以后)

我用手上天文台编的三千年公历干支朔望对照表抽样校对了几个日子,准确无误。可见它也是采用同样原理编订的。
反过来,知道干支及大约的月份,求公元日序数(公元历)只是解方程的问题而已。

五、举例及应用

例8、&nbsp汉书所说高祖五年(己亥)二月甲午即皇帝位的,该日的公历是多少?
高祖五年己亥是前202年,二月大约在公历3月附近,干支甲午序数31,代入公式四得
-202*5&nbsp–&nbsp[(202+3)/4]+30*1+[0.6M-0.&nbsp1]+D+42&nbsp=31&nbspmod&nbsp60
整理得&nbsp&nbsp-989+D=31&nbspmod&nbsp60&nbsp&nbsp&nbspD=(31+989&nbsp)&nbspmod&nbsp60&nbsp&nbsp&nbspD=0&nbsp&nbspmod&nbsp60
解出D=0,或60,即该日是3月0日(2月28日),或过60天以后的4月29日。

验算:严格按儒略历四年一闰的算法,公元前202年2月28日的公元日序数为&nbsp–73722,
-73722+13=&nbsp-73709&nbsp=&nbsp&nbsp-&nbsp29&nbsp=31&nbspmod&nbsp60&nbsp该日甲午。演算没错!!

六、结语:方法是类似解释几何的的方法:
首先建立一个连续时间坐标,
第二是根据公历的规律建立任意日子到原点间的距离公式(公元日序数)
第三是对于有固定周期的属性(干支、月相等),可从任一已知属性的日子利用与原点的距离推出原点的属性。
第四是根据原点的属性利用某点与原的距离推知该点的属性。
第五公式的化简与选择只是一些技术问题。

我向来粗疏,大家如发觉有逻辑上,或计算上的错误,可告我改正。
求y年m月d日世界时正午的儒略日JD:
儒略历:
JD=365*(y-1)+[y/4] +30*(m-3)+[0.6*(m+1)]-2 +d +1721482.0
格里历:
JD=365*(y-1)+[y/4]-[y/100]+[y/400] +30*(m-3)+[0.6*(m+1)]-2 +d +1721484.0
说明:
1)凡1月、2月视为上一年的13月、14月;
2)公式中[x]=不大于x的最大整数,
如[5]=5,[5.2]=5,[5.8]=5,[0]=0,[-5]=-5,[-5.2]=-6,[-5.8]=-6;
3)计算公元前日期时,年份BC1,BC2,BC3...视为0,-1,-2...,而月份、日序仍然作正数;
4)儒略日是以日为单位的不间断的纪时方法,以儒略历公元前4713年1月1日世界时正午为儒略日起算点;
5)一些特殊日期:
BC4713.1.1=JD0.0(该日是星期一,癸丑日)
AD1.1.1=JD1721424.0
AD1582.10.4=JD2299160.0
AD1582.10.15=JD2299161.0;
6)AD1582.10.4的次日为AD1582.10.15,从此行用格里历。对于此前的日期习惯上一律按照儒略历推算,而不考虑罗马历法的实际施行情况;
7)本法较适用于编为程序应用,稍加补充后即可应用于星期及日干支的计算。

1998年前后我为计算儒略日曾经求出上述公式,其中对日期的处理自认为颇具巧思,现在看了阁下“关于公历年月日与干支的转化问题”一文,真是英雄所见略同啊!
 
我有一本“张氏公元万年甲子纪日速算法”,作者是张致中、张幼明。重庆出版社出版,我这本儿是82年出的。可以找找。
 
又是数字符号,郁闷
 
久违了!很高兴又见“南山”兄大作。
    关于“公历”年月日公元前日期与中国历史纪年的干支转换问题,希望南山兄和各位关心这个问题的网友共同来统一一下思想:
     1大家公认为“公历”的起点日,比如南山兄以之为“原点”的前1年月12月31日这天,其对应的“中历”日期的干支,要公认和统一,有大家的“约法”或“立法”才好。
大作以之为例子该日干支为“丙子”,我也是如此认定的。但权威的资历料不是这样表述的。如1989年版《辞海》附《中国历史年表》,还有台湾中央研究院计算中心网站公布的《中西历转换工具》(ASCC),按它们确指为公(西)元元年1月1日对应日期的干支为“戊寅”。如用此反溯一日,南山兄作为例子的前1年1月31日干支则不是“丙子”而另为“丁丑”日了!?
     2、中历向上与“公历”向上反溯的“公历”日期,也要公认一条“规则”才行。作为“规则”较密近天象,自然以“格里高利”为优。但多以“儒略历”规则,也无不可。只是要求统一。问题出在:公认的权威数据,却是来自对公认的“公历”来源于《儒略历》以前发生的历史的默契和肯定。按《儒略历》规则,四年当置一闰日(于2月为29天)。可从上举两份权威资料的日期安排看,公历1年至7年间,却未应期安排“闰日”。表上连着七年,每年的2月都是28天。
     关于中国历史日期与“公历”反溯对照,与天象密近否,有关系,但更重要的是统一,才有标尺。不知诸兄以为然否?
 
兄好,这是旧年的贴子了。近几个月为口奔波,已很少时间上网,更不要说发贴了。等四月份稍闲,再与君一聚。
 
先把日干支与儒略日对应起来。这个对应简单明了,不会造成混乱。
然后要把儒略日“翻译”成儒略历还是格里历,就按各自的约定而行。
格里历通行之后用格里历自然没有问题;儒略历通行的年代用儒略历也没有问题。
问题是儒略历通行之前的年代,该用什么历?也即中国先秦的日期翻译成公历应该用什么历?
有人主张用格里历,我以为不顺。用儒略历更为合理。
 
以下是引用水電工2在2003-4-3 13:38:13的发言:
在陳遵媯先生的《中國天文學史》(二)的1373頁
,有個簡單的換算公式,經過初步驗算,是準確
的。
这本书好难找呵,网上没有,家里有一本第三册。偶又只有上海图书馆的外借证。外借室里好象没有。
有这本书的朋友能不能把这个公式贴出来呵?
偶也想知道呵!

[此贴子已经被作者于2004-3-1 23:24:24编辑过]

 
地支对应黄道十二星座。
这黄道十二星座由于岁差的作用,每2148-2160逆时针移动一位。
所以,这干支应该也是2148-2160年一变的。

我的想法是,天干方位不变(因为天干代表地球五行),地支每2148年或2160年前移一位。在排列上是这样的:
[第一个2148年或2160年]
甲乙丙丁戊己庚辛壬癸
子丑寅卯辰巳午未申酉戍亥

[第二个2148年或2160年]
乙甲丁丙己戊辛庚癸壬
丑寅卯辰巳午未申酉戍亥子

[第三个2148年或2160年]
甲乙丙丁戊己庚辛壬癸
寅卯辰巳午未申酉戍亥子丑

[第四个2148年或2160年]
乙甲丁丙己戊辛庚癸壬
卯辰巳午未申酉戍亥子丑寅

......依此类推

以上是个人的一些看法,仅供参考。
(我在用易卦预测中使用,效果很不错。)
 

 

<http://bbs.guoxue.com/viewthread.php?tid=123202>

1 概述 首先需要说明的一点,无论是Winform,还是Webform,都有很成熟的日历控件,无论从易用性还是可扩展性上看,日期的选择和校验还是用日历控件来实现比较好。 前几天在优快云多个版块看到需要日期正则的帖子,所以整理了这文章,和大家一起讨论交流,如有遗漏或错误的地方,还请大家指正。 日期正则一般是对格式有要求,且数据不是直接由用户输入时使用。因应用场景的不同,写出的正则也不同,复杂程度也自然不同。正则的书写需要根据具体情况具体分析,一个基本原则就是:只写合适的,不写复杂的。 对于日期提取,只要能非日期区分开,写最简单的正则即可,如 \d{4}-\d{2}-\d{2} 如果可以在源字符串中唯一定位yyyy-MM-dd格式的日期,则可用做提取。 对于验证,如果仅仅是验证字符组成及格式是没有多大意义的,还要加入对规则的校验。由于闰年的存在,使得日期的校验正则变得比较复杂。 先来考察一下日期的有效范围以及什么是闰年。 2 日期的规则 2.1 日期的有效范围 对于日期的有效范围,不同的应用场景会有所不同。 MSDN中定义的DateTime对象的有效范围是:0001-01-01 00:00:00到9999-12-31 23:59:59。 UNIX时间戳的0按照ISO 8601规范为 :1970-01-01T00:00:00Z。 而实际应用中,日期的范围基本上不会超出DateTime所规定的范围,所以正则验证取其中常用的日期范围即可。 2.2 什么是闰年 (以下摘自百度百科) 闰年(leap year)是为了弥补因人为历法规定造成的年度天数地球实际公转周期的时间差而设立的。补上时间差的年份为闰年。 地球绕日运行周期为365天5小时48分46秒(合365.24219天),即一回归年(tropical year)。公历的平年只有365日,比回归年短约0.2422 日,每四年累积约一天,把这一天加于2月末(即2月29日),使当年时间长度变为366日,这一年就为闰年。 需要注意的是,现在的公历是根据罗马人的“儒略历”改编而得。由于当时没有了解到每年要多算出0.0078天的问题,从公元前46年,到16世纪,一共累计多出了10天。为此,当时的教皇格雷果里十三世,将1582年10月5日人为规定为10月15日。并开始了新闰年规定。即规定公历年份是整百数的,必须是400的倍数才是闰年,不是400的倍数的就是平年。比如,1700年、1800年和1900年为平年,2000年为闰年。此后,平均每年长度为365.2425天,约4年出现1天的偏差。按照每四年一个闰年计算,平均每年就要多算出0.0078天,经过四百年就会多出大约3天来,因此,每四百年中要减少三个闰年。闰年的计算,归结起来就是通常说的:四年一闰;百年不闰,四百年再闰。 2.3 日期的格式 根据不同的语言文化,日期的连字符会有所不同,通常有以下几种格式: yyyyMMdd yyyy-MM-dd yyyy/MM/dd yyyy.MM.dd 3 日期正则表达式构建 3.1 规则分析 写复杂正则的一个常用方法,就是先把不相关的需求拆分开,分别写出对应的正则,然后组合,检查一下相互的关联关系以及影响,基本上就可以得出对应的正则。 按闰年的定义可知,日期可以有几种分类方法。 3.1.1 根据天数是否年份有关划分为两类 年份无关的一类中,根据每月天数的不同,又可细分为两类  1、3、5、7、8、10、12月为1-31日  4、6、9、11月为1-30日 年份有关的一类中  平年2月为1-28日  闰年2月为1-29日 3.1.2 根据包含日期不同可划分为四类  所有年份的所有月份都包含1-28日  所有年份除2月外都包含29和30日  所有年份1、3、5、7、8、10、12月都包含31日  闰年2月包含29日 3.1.3 分类方法选择 因为日期分类之后的实现,是要通过(exp1|exp2|exp3)这种分支结构来实现的,而分支结构是从左侧分支依次向右开始尝试匹配,当有一个分支匹配成功时,就不再向右尝试,否则尝试所有分支后并报告失败。 分支的多少,每个分支的复杂程度都会影响匹配效率,考虑到被验证日期概率分布,绝大多数都是落到1-28日内,所以采用第二种分类方法,会有效提高匹配效率。 3.2 正则实现 采用3.1.2节的分类方法,就可以针对每一个规则写出对应的正则,以下暂按MM-dd格式进行实现。 先考虑年份无关的前三条规则,年份可统一写作 (?!0000)[0-9]{4} 下面仅考虑月和日的正则  包括平年在内的所有年份的月份都包含1-28日 (0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])  包括平年在内的所有年份除2月外都包含29和30日 (0[13-9]|1[0-2])-(29|30)  包括平年在内的所有年份1、3、5、7、8、10、12月都包含31日 (0[13578]|1[02])-31) 合起来就是除闰年的2月29日外的其它所有日期 (?!0000)[0-9]{4}-((0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31) 接下来考虑闰年的实现  闰年2月包含29日 这里的月和日是固定的,就是02-29,只有年是变化的。 可通过以下代码输出所有的闰年年份,考察规则 for (int i = 1; i < 10000; i++) { if ((i % 4 == 0 && i % 100 != 0) || i % 400 == 0) { richTextBox2.Text += string.Format("{0:0000}", i) + "\n"; } } 根据闰年的规则,很容易整理出规则,四年一闰; ([0-9]{2}(0[48]|[2468][048]|[13579][26]) 百年不闰,四百年再闰。 (0[48]|[2468][048]|[13579][26])00 合起来就是所有闰年的2月29日 ([0-9]{2}(0[48]|[2468][048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)-02-29) 四条规则都已实现,且互相间没有影响,合起来就是所有符合DateTime范围的日期的正则 ^((?!0000)[0-9]{4}-((0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31)|([0-9]{2}(0[48]|[2468][048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)-02-29)$ 考虑到这个正则表达式仅仅是用作验证,所以捕获组没有意义,只会占用资源,影响匹配效率,所以可以使用非捕获组来进行优化。 ^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$ 以上正则年份0001-9999,格式yyyy-MM-dd。可以通过以下代码验证正则的有效性和性能 DateTime dt = new DateTime(1, 1, 1); DateTime endDay = new DateTime(9999, 12, 31); Stopwatch sw = new Stopwatch(); sw.Start(); Regex dateRegex = new Regex(@"^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$"); //Regex dateRegex = new Regex(@"^((?!0000)[0-9]{4}-((0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31)|([0-9]{2}(0[48]|[2468][048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)-02-29)$"); Console.WriteLine("开始日期: " + dt.ToString("yyyy-MM-dd")); while (dt < endDay) { if (!dateRegex.IsMatch(dt.ToString("yyyy-MM-dd"))) { Console.WriteLine(dt.ToString("yyyy-MM-dd") + " false"); } dt = dt.AddDays(1); } if (!dateRegex.IsMatch(dt.ToString("yyyy-MM-dd"))) { Console.WriteLine(dt.ToString("yyyy-MM-dd") + " false"); } Console.WriteLine("结束日期: " + dt.ToString("yyyy-MM-dd")); sw.Stop(); Console.WriteLine("测试用时: " + sw.ElapsedMilliseconds + "ms"); Console.WriteLine("测试完成!"); Console.ReadLine(); 4 日期正则表达式扩展 4.1 “年月日”形式扩展 以上实现的是yyyy-MM-dd格式的日期验证,考虑到连字符的不同,以及月和日可能为M和d,即yyyy-M-d的格式,可以对以上正则进行扩展 ^(?:(?!0000)[0-9]{4}([-/.]?)(?:(?:0?[1-9]|1[0-2])([-/.]?)(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])([-/.]?)(?:29|30)|(?:0?[13578]|1[02])([-/.]?)31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)([-/.]?)0?2([-/.]?)29)$ 使用反向引用进行简化,年份0001-9999,格式yyyy-MM-dd或yyyy-M-d,连字符可以没有或是“-”、“/”、“.”之一。 ^(?:(?!0000)[0-9]{4}([-/.]?)(?:(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])\1(?:29|30)|(?:0?[13578]|1[02])\1(?:31))|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)([-/.]?)0?2\2(?:29))$ 这就是“年月日”这种形式最全的一个正则了,不同含义部分以不同颜色标识,可以根据自己的需要进行栽剪。 4.2 其它形式扩展 了解了以上正则各部分代表的含义,互相间的关系后,就很容易扩展成其它格式的日期正则,如dd/MM/yyyy这种“日月年”格式的日期。 ^(?:(?:(?:0?[1-9]|1[0-9]|2[0-8])([-/.]?)(?:0?[1-9]|1[0-2])|(?:29|30)([-/.]?)(?:0?[13-9]|1[0-2])|31([-/.]?)(?:0?[13578]|1[02]))([-/.]?)(?!0000)[0-9]{4}|29([-/.]?)0?2([-/.]?)(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00))$ 这种格式需要注意的就是不能用反向引用来进行优了。连字符等可根据自己的需求栽剪。 4.3 添加时间的扩展 时间的规格很明确,也很简单,基本上就HH:mm:ss和H:m:s两种形式。 ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] 合入到日期的正则中,yyyy-MM-dd HH:mm:ss ^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)\s+([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$ 4.4 年份定制 以上所有涉及到平年的年份里,使用的是0001-9999。当然,年份也可以根据闰年规则定制。 如年份1600-9999,格式yyyy-MM-dd或yyyy-M-d,连字符可以没有或是“-”、“/”、“.”之一。 ^(?:(?:1[6-9]|[2-9][0-9])[0-9]{2}([-/.]?)(?:(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])\1(?:29|30)|(?:0?[13578]|1[02])\1(?:31))|(?:(?:1[6-9]|[2-9][0-9])(?:0[48]|[2468][048]|[13579][26])|(?:16|[2468][048]|[3579][26])00)([-/.]?)0?2\2(?:29))$ 5 特别说明 以上正则采用的是最基本的正则语法规则,绝大多数采用传统NFA引擎的语言都可以支持,包括JavaScript、Java、.NET等。 另外需求说明的是,虽然日期的规则相对明确,可以采用这种方式裁剪来得到符合要求的日期正则,但是并不推荐这样使用正则,正则的强大在于它的灵活性,可以根据需求,量身打造最合适的正则,如果只是用来套用模板,那正则也就不称其为正则了。 正则的语法规则并不多,而且很容易入门,掌握语法规则,量体裁衣,才是正则之“道”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值