儒略日是一种从历元(公元前4213年1月1日正午12时)开始连续纪日的历法,要换算其他历法的公历,一般以此为中介。所以在历法对比中经常要用到儒略日。[注1]

公历转儒略日

《Astronomical Algorithms》中给出了简便的计算公式。[注2]

儒略日与公历转换

书中并未给出公式的含义,这里做一个分析。

儒略历转儒略日

儒略日的本质是积日,若求Y年M月D日对应的儒略日,即分别对(Y-历元年)年(M-1)月D日进行积日。

:现行公历从公元前4713年开始,由于公元纪年法没有0年,为方便计算,天文学中以0表示公元前1年,则公元前4713年表示为-4712。对儒略历而言,以365.25天为岁长,每年闰余0.25天,4年闰余1天则需置闰。故儒略历每4年一闰,即对于365.25,每4年前3年向下取整,第四年向上取整。计算Y年的积日,即将从-4712年到Y年的积年乘以一回归年的长度。

int((Y+4712)*365.25)

:1.公历设置大小月的基本思路是每月大小相间隔。相邻两月必为61天,如此一年共366天。平均一月为30.5天,对小月向下取整为30(int(30.5)),大月则为相邻2个月日数减小月日数(int(30.5*2)-int(30.5))。这种情况下,M月(积月为M-1)的积日即为int(30.5*(M-1))。而公历以单数月为31天,双数月为30天。即岁首(M=1)时为大月,可令上式M=M+1,再从该式中减去多算的一月30,则积日为int(30.5*M)-30

2. 公历一年实际只有365日,需在某月中减去一天,而公历设在二月。这时,3~12月份仍然是有规律的(大小月相隔),1月有31天,2月有29天。如此,可假设以3月份作为岁首,2月为年尾。则在2月减去的一天可理解为上年岁末(即今年岁首前)少一天。并以13、14月表示上一年的1、2月(即一年只有3~14月)。则每年仍然是单数月31天,双数月为30天,且岁首(M=3)仍为大月,则仅需令上式再减1(2月少一天)。计算M月的积日,则有:int(30.5*M)-31(M>2)

该式只适用于M>2的情况,所以当为1月或2月时,可令M=13、14,整式再减去一年365.25日,表现在年的积日公式中为Y=Y-1。

一年的状况(单数月31天,双数月30天)

3月     4月    5月    6月    7月    8月    9月   10月  11月  12月   1月   2月

31天  30天  31天  30天  31天  30天  31天  30天  31天  30天  31天  30天-1

3. 对于公历,又将8月增加一天成为大月,以后9~12月则改变大小月顺序,而二月再减去一日成为28天。

一年的状况(每5个月循环)

3月     4月    5月    6月    7月    8月    9月   10月  11月  12月   1月   2月

31天  30天  31天  30天  31天  31天  30天  31天  30天  31天  31天  30天-2

如此,7、8成为连大月,12、13也是连大月。其中8月与岁首相差5月,13月与8月也相差5月。此时的大小月顺序仍然存在某种规律,即每连续4月大小月相间(从小月开始),然后是一次连大月。即在一年12个月内,若以4月为岁首,则大小月按小大小大大循环排序。亦即连续5月的积月为153天(3大2小),平均每月为30.6天。则M月的积日为int(30.6*M)-31,由于该式是以3月为岁首,需调整月份,即令M=M+1,再减去多算的一月30,并需减去2月再减少的1天则有:

int(30.6*(M+1))-62 

:由于儒略日的历元是以正午12时开始(记为0.0),而公历一日之始以半夜12时开始(记为1.0),两种相差0.5天,则对日的积日为实际日数-1.5

D - 1.5

将儒略历转换为儒略日,仅需将年月日的积日相加,有:

int(365.25*(Y+4712))+int(30.6*(M+1))+D-63.5 (M>2)

当M<=2时:令Y = Y - 1,M = M + 12,可适用该公式

 

格里高利历转儒略日

:儒略历合400年百闰。而在1582年发现春分点与实际相差10日(岁差22日,而儒略历随常较实际值为大,多计算了12天。)故以是年10月4日的次日实行新历(格里高利历),历元为1582年10月15日,有10日之差。新历在儒略历的基础上调整了岁差和回归年长度,即每400年减少3次置闰,合400年97闰。故计算格里高利历的儒略日,还需在上式中减去不置闰(能被100整除,但不含能被400整除的年份)的日数,即为-int((Y-1582)/100)+int((Y-1582)/400)-10,为简便算法,假设历元为0年,则自0年至1582年少算了不置闰的日数共12天,需加上,则计算格里历的儒略日数需减去不置闰的日数:

-int(Y/100)+int(Y/400)+2

最终有格里高利历转儒略日的公式:

int(365.25*(Y+4712)) + int(30.6*(M+1)) + D - int(Y/100)+int(Y/400)+2 - 63.5  (M>2)

当M<=2时:令Y = Y - 1,M = M + 12,可适用该公式

补充说明:

(1)上式的int()函数表示向下取整,但在计算机中,int()函数一般仅取数字的整数部分,如int(-365.25)值为-365而非366。考虑到当计算-4712年3月1日之前的数据时,Y=Y-1即-4713年,对年的积日运算中出现对负数取整的情况。故将历元推到前一个置闰年为-4716年以避免负数的取整运算,即多加了4年,需要在式尾中减去1460天。部分编程语言提供了向下取整函数,可用于替代上式的Int(),但调整历元的方法更具有普适性。

(2)同样考虑计算机对浮点数计算精度的问题,因为计算机对十进制的表示和计算是以二进制进行的,无法得到精确值。故以30.6001替代30.6以避免出现计算误差。

对此二者做出修正后,则有:

JDN = int(365.25*(Y+4716)) + int(30.6001*(M+1)) + D + B - 1524.5  (M>2)

当M<=2时:令Y = Y - 1,M = M + 12,可适用该公式

对儒略历(公元前1582年10月4日及以前),有B = 0

对格里高利历(公元前1582年10月15日及以后),有B = 2 - int(Y/100)+int(Y/400)

但对计算机而言,该式仍然不适用于计算-4716年3月1日前的儒略日数(但可以计算从儒略日起点开始的任意一天的儒略日数)。若使用向下取整函数替换int(),则该式可使用于任意一天的儒略日计算。

此式即可避免出现计算机取整运算与实际不一致的情况,从而避免因不同编程语言出现的计算误差。

(3)wiki中提供了另一个公式,其实质与上式相同。[注3]

儒略日与公历转换

以3月为岁首,每5个月符合大小大小大的顺序,合计153天,平均每月30.6天。而计算起点为大月,需加上0.4,取整后方得31。故有m月的积日为int((153m+2)/5)。每年以365计,则需加上置闰年int(y/4)(365y+int(y/4)等价于int(365.25y))。式中将历元前推到原历元上一个符合置闰格里历要求的年份-4800(公元前4801年)中午12时,则需在末尾减去(4800-4712)*365.25即32142天,还需再补上1月和2月合计59天,得32083日。对格里历还需补上自-4712年至1582年少置闰的年份,共48天,减去上岁差和回归年过大引起的误差共10天。

儒略日数的计算公式还有很多,但思路类似,不再举例说明。

简化儒略日

为简化儒略日的表示,国际天文联合会决定行用简化儒略日,并定义为

MJD = JD -2400000.5

根据儒略日转公历的计算函数,可得MJD的的起点为儒略日2400000.5,即公元1858年11月17日世界时0时。

儒略日计算的python实例

import datetime
from gyjn import *

def ce2jd(Year,Month,D):
    if Month in [1,2]:
        M = Month + 12
        Y = Year - 1
    else:
        Y = Year
        M = Month
    B = 0
    if Y>1582 or (Y==1582 and M>10) or (Y==1582 and M==10 and D>=15):
        B = 2 - int(Y/100) + int(Y/400)  #公元1582年10月15日以后每400年减少3闰
    #JD = int(365.25*(Y+4712))+int(30.6*(M+1))+D+B-63.5
    JD = int(365.25*(Y+4716))+int(30.6*(M+1))+D+B-1524.5
    print("{}年{}月{}日的儒略日为:{:.1f}".format(gyjn(Year),Month,D,JD))
    if Y>1858 or (Y==1858 and M>11) or (Y==1858 and M==11 and D>=17):
        MJD = int(JD - 2400000.5)
        print("简化儒略日为:{}".format(MJD))

#示例:计算当前时间的儒略日
year = datetime.datetime.now().year
month = datetime.datetime.now().month
day = datetime.datetime.now().day
ce2jd(year,month,day)

程序使用了一个将天文计算年份表达为公元纪年法年份的函数:

def gyjn(year):
    if year > 1:
        ce = "公元" + str(year)
    elif year == 1:
        ce = "公元元"
    elif year <= 0:
        year -= 1
        ce = "公元前" + str(year)[1:]
    return ce

儒略日转公历

儒略日与公历转换

 《Astronomical Algorithms》同一章节给出了求算方法。这里分别说明每一个表达式的含义。

1. 由于儒略日的历元为正午12时,公历历元为半夜12时,为统一计算,将儒略历历元前推至0.5日。即为:JD = JD + 0.5

2.  其中整数部分为日数,小数部分为时刻,只对整数部分进行运算。则令:

Z = int(JD)
F = JD - Z 

 Z即为所求日到-4712年0时的日数。

3.由于儒略历和格里历的岁长不同,需分别处理。即自1582年10月15日0时前适用儒略历(岁长365.25),此后适用格里历(岁长365.2425)。为统一计算,可将格里历转换为儒略历,即假设自-4712年1月1日0时起一直使用的是儒略历。则针对格里历相对儒略历少置闰(400年3闰)的部分给予补上。由于格里历的历元符合新增置闰规则的年份,可将历元推至符合400年置闰周期的近距,即1600年1月1日,根据儒略日计算公式,得该日的儒略日为2305447.5。

a = int((Z - 2305447.5) / 36524.25)

再补上1582年10月4日到10月15日跳过的10天,即为自-4712年1月1日0时到所求日以儒略历计算的总积日。

A = Z + 10 + a - int(a/4) 

(注:书中a和A的表达式与此略有差异,是由于书中将历元推至公元元年1月1日,则至1582年间多置闰了12次,去除跳过的10天,共多了2日,反映在置闰公式中,相当于多计算了200年,由于在置闰公式(int(y/100)-int(y/400))中,对200年间的置闰可能有2次或1次2种情况,宜推算到一次置闰周期即400年,则必然置闰3次,而多算了一次,则在表达式A中补足。即为调整"儒略历和格里历的置闰误差"以及"岁差和回归年过大的误差"再次将历元从公元元年历元推至公元400年。这种情况思虑比较复杂,可不使用书中的表达式。)

同样地,为避免对负数取整的情况,将历元前推至-4716年3月1日0时,需补上相差的日数,合1524日。即有:

B  = A +1524

 对所得的积日(儒略历),除以岁长,即为积年(表达式C),加上历元即为所求公历年份。其中整数部分为年的积日(表达式D),小数部分为月与日的积日(表达式B-D)。

C = int((B-122.1)/365.25)

D = int(365.25*C)

 将B-D除以每月平均日数30.6为积月(表达式E),其中整数部分为月数,小数部分为日数(day)。

最后调整岁首的情况可得month和year。

 

根据儒略日求公历的python实例

from gyjn import *

def jd2ce(JDN):
    JDN  = JDN + 0.5
    Z = int(JDN)
    F  = JDN - Z
    if Z < 2299161: #儒略历
        A = Z
    else: #格里历
        a = int((Z - 2305447.5) / 36524.25)
        A =  Z + 10 + a - int(a/4)
    B  = A + 1524
    C = int((B-122.1)/365.25)
    D = int(365.25 * C)
    E = int((B-D)/30.6001)
    day = B - D - int(30.6001*E) + F
    if E < 14:
        month = E - 1
    elif E < 16:
        month = E - 13
    if month > 2:
        year = C - 4716
    elif month in [1,2]:
        year = C - 4715
    ce = gyjn(year)
    print("儒略日{}对应的公历日期为{}年{}月{}日".format(JDN-0.5,ce,month,day),'\n')

#计算示例
jd2ce(2400000.5)    #print:1858年11月17.0日 
jd2ce(2299160.5)    #print:1582年10月15.0日
jd2ce(2299160.5-1)  #print:1582年10月4.0日

 

测试以上两个程序,可用以下代码:

jd2ce(ce2jd(year,month,day))

对于任意自儒略日历元以后的year,month,day,输出值与输入值相同,可以证明两个程序的正确性,不必分别测试。

 

  • 注1:文中所用的“公历”在公元前1582年10月4日适用儒略历(虽然其历元为公元前45年1月1日半夜12时),在公元前1582年10月15日以后适用格里高利历。

  • 注2:Jean Meeus《Astronomical Algorithms》2nd,p59-66。

  • 注3:https://zh.wikipedia.org/wiki/%E5%84%92%E7%95%A5%E6%97%A5

相关文章: