第二章 公历与儒略日 概述 选自本人的《天文算法》部分译文 公历中规定平年有365日,闰年366日。每年含有12个月。 在1582年10月4日以前,公历规定每4年设置一个闰年,平均年长度为365.25天,这期间的公历称为儒略历。在1582年10月15日之后则规定每400年97闰,平均年长度为365.2425天,这期间的公历称之为格里高利历。 格里高利历并非在所有国家迅速得到一致采用,这一点在历史研究中要引起注意。例如在大不列颠,晚至公元1752年才变更历法,而土耳其则要等到1927年。 由于儒略历存在严重的“多闰”问题,到了1582年,公历跑快了10天左右,当时就人为调整了10天,并从此改用格里历。因此务必注意1582年10月4日(儒略历)的下一日为1582年10月15日(格里高利历)。也就是说1582年10月份少了10天。 闰年的具体设置 在儒略历中,能被4整除的年份为闰年,这一年有366天,其它年份为平年(365天)。 如900年和1236年为闰年,而750年和1429年为平年。 格里高利历法也采用这一规则,但下列年份除外:不能被400整除的百年为平年,如1700年,1800年,1900年和2100年。其余能被400整除的年份则为闰年,如1600年,2000年和2400年。 儒略历的扩展 儒略历由尤里乌斯·恺撒于公元前45年在罗马帝国创立,而其最终形式确立于公元8年前后,尽管如此,我们仍可以借助天文学家的演算无止境地向前推算儒略历。比如在这一系统中,我们可以说某次日食发生在公元前1203年8月28日,虽然在那个遥远的年代,罗马帝国根本还未被创建,而8月这个月份更有待设立。 对于公元1年之前年份的纪年方法,天文学家同历史学家并不一致。天文纪年中,+1年的前一年为0年,再之往前1年是-1年。所以历史学家所说的公元前585年实际上是-584年。 天文上以负数纪年只是为了计算方便。比如,在历史学纪年中的,可被4整除的年份为儒略历闰年这个规则不再有效了,如公元前1,5,9,13,…在天文纪年中它们却被记为0,-4,-8,-12 …,都能被4整除。 我们以INT(x)来表示数x的整数部分,即小数点前的整数。例如: INT(7/4) = 1 INT(5.02) = 5 INT(8/4) = 2 INT(5.9999) = 5 对于负数,这里的INT(x)指小于等于x的最大整数。那样的话就有INT(-7.83) = -8。如果你的程序是javascript,取整函数是 Math.floor(x),它返回小于等于x的最大整数。如果你用的是C++,那么用 (int)x 强制转换,得到是的整数部分,而不是小于等于x的最大整数。 儒略日数(简称儒略日) 儒略日数是指从公元 -4712 年开始连续计算日数得出的天数及不满一日的小数,通常记为 JD (**)。传统上儒略日的计数是从格林尼治平午,即世界时12点开始的。若以力学时(或历书时)为标尺,这种计数通常表达为“儒略历书日”,即JDE (**),其中E只是一种表征,即按每天86400个标准秒长严格地计日。例如: 1977年4月26.4日 UT = JD 2443 259.9 1977年4月26.4日 TD = JDE 2443 259.9 儒略日的计算 设Y为给定年份,M为月份,D为该月日期(可以带小数)。 若M > 2,Y和M不变,若 M =1或2,以Y–1代Y,以M+12代M,换句话说,如果日期在1月或2月,则被看作是在前一年的13月或14月。 对格里高利历有 :A = INT(Y/100) B = 2 - A + INT(A/4) 对儒略历,取 B = 0 要求的儒略日即为:JD = INT(365.25(Y+4716))+INT(30.6001(M+1))+D+B-1524.5 使用数值30.6取代30.6001才是正确的,但我们仍使用30.6001,以确保总能取得恰当的整数。事实上可用30.601甚至30.61来取代30.6001。例如,5乘30.6精确等于153,然而大多数计算机不能精确表示出30.6,这导致得出一个152.999 9998的结果,它的整数部分为152,如此算出的JD就不正确了。
下表列出了一些历日所对应的儒略日,可作测试程序之用。 由儒略日推算历日 将JD加上0.5,令 Z 为其整数部分,F 为尾数(小数)部分。 若 Z < 2299161,取A = Z 若 Z 大于等于2299 161,计算 α=INT((Z-1867216.25)/36524.25) ,A=Z+1+α-INT(α/4) 然后计算 B = A+1524 C = INT((B-122.1)/365.25) D = INT(365.25C) E = INT((B-D)/30.6001) 该月日期(带小数部分)则为:d = B - D - INT(30.6001E) + F 月份m为: 年份为y: 这个公式里求E时用的数30.6001不能代之以30.6,哪怕计算机没有先前所说的问题。否则,你得到的结果会是2月0日而不是1月31日,或者4月0日而不是3月31日。 算法实现范例(JavaScript) function int2(v){ return Math.floor(v); } //取整数部分 var JD={ //日期元件 JD:function(y,m,d){ //公历转儒略日 var n=0, G=0; if(y*372+m*31+int2(d)>=588829) G=1; //判断是否为格里高利历日1582*372+10*31+15 if(m<=2) m+=12, y--; if(G) n=int2(y/100), n=2-n+int2(n/4); //加百年闰 return int2(365.25*(y+4716)) + int2(30.6001*(m+1))+d+n - 1524.5; }, DD:function(jd,r){ //儒略日数转公历 var D=int2(jd+0.5), F=jd+0.5-D, c; //取得日数的整数部份A及小数部分F if(D>=2299161) c=int2((D-1867216.25)/36524.25),D+=1+c-int2(c/4); D += 1524; r.Y = int2((D-122.1)/365.25);//年数 D -= int2(365.25*r.Y); r.M = int2(D/30.601); //月数 D -= int2(30.601*r.M); r.D = D;; //日数 if(r.M>13) r.M -= 13, r.Y -= 4715; else r.M -= 1, r.Y -= 4716; //日的小数转为时分秒 F*=24; r.h=int2(F); F-=r.h; F*=60; r.m=int2(F); F-=r.m; F*=60; r.s=F; } } 星期几的问题 在公历中,星期是按7天一个循环计日,周而复始。中国的干支记法与星期记法的算法的实现几乎完全相同。 给定日期是星期几可由以下方法获得 — 计算该日0时的儒略日,加上1.5,再除以7 ,所得余数将指示出星期几:若余数为0,则为星期日,1为星期一,2为星期二,3为星期三,4为星期四,5为星期五,6为星期六。 儒略历到格里高利历的换算并不影响星期。因而,在1582年,10月4日星期四接下来的一天便是10月15日星期五。 |