目录
一、基础知识
儒略日的计算是从公元前4713年1月1日平午12:00开始的天数积累,这是儒略日计算的起点,儒略历的规则为,分平年和闰年每4年一润各月份对应天数见表1。儒略历一直使用到1582年10月4结束,因为存在误差改为格力高历,从1582年10月15日开始计算,使用格里高历,就是现在使用的公历。即公元纪年法在1582年10月4日及以前使用儒略历,在1582年10月15日及以后使用格里高历,格里高历闰年与平年月份-天数与儒略历一致。不同的国家使用格里高历的时间可能不一样,这个要注意,比如我们国家是新中国成立后开始使用的。
月份 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
天数(平年) | 31 | 28 | 31 | 30 | 31 | 30 | 31 | 31 | 30 | 31 | 30 | 31 |
天数(闰年) | 31 | 29 | 31 | 30 | 31 | 30 | 31 | 31 | 30 | 31 | 30 | 31 |
二、公历(天文纪年)转儒略日
2.1、儒略历转儒略日
计算儒略日就是计算年的积日+月的积日+日的积日,计算的前提为-4712年1月1日以后~1582年10月4日及以前。y年m月d日的儒略日的计算公式为:JD=int(365.25*(y+4712)) + int(30.61*(m+1)) + d - 63.5。下面我来解释一下这个公式:
(1)首先年的积日计算,这个地方因为公元纪年法年没有公元0年,我们把公元前一年当做公元0年,这种做法叫做天文纪年法,公元前4713年就是-4712年,y都是以天文年来计算的。年的积日计算公式为:年的积日 = int(365.25*(y+4712)) 。细心的小伙伴会发现这个计算年的积日是有问题的,假设y为-4711年,积年就是-4712年,这个计算下来的年积日为365天,但由于-4712年是闰年,应该是366天,实际计算结果比真实天数少了一天;当y为-4708年时,积年为-4712、-4711、-4710、-4709这四年,年的积日为1461天,这个计算结果与真实的天数一致。所以正确的年的积日计算公式为:
闰年:年的积日 = int(365.25*(y+4712))
平年:年的积日 = int(365.25*(y+4712)) + 1
(2)月的积日计算,在计算月的积日时我们把2月当做只有28天的时候,将1月、2月当做上一年的13、14月,发现有以下规律(这个规律怎么来的,我也不知道,你也可以总结别的规律):
月份 m | 积日 int(30.61*(m+1)) - 63 | 对应的积月 |
---|---|---|
3 | 59 | 1、2月 |
4 | 90 | 1、2、3月 |
5 | 120 | 1、2、3、4月 |
6 | 151 | 1、2、3、4、5月 |
7 | 181 | 1、2、3、4、5、6月 |
8 | 212 | 1、2、3、4、5、6、7月 |
9 | 243 | 1、2、3、...、7、8月 |
10 | 273 | 1、2、3、...8、9月 |
11 | 304 | 1、2、3、...9、10月 |
12 | 334 | 1、2、3、...10、11月 |
13(1月) | 365 | 1、2、3、...11、12月 |
14(2月) | 396 | 1、2、3、...12、1月 |
那么计算月份的积日时有,月的积日=int(30.61*(m+1)) - 63 (m>2),当m<=2是就将m看做前一年的13、14月,那么m=m+12,这样就保证m>2,为弥补多计算了12个月,年就少计算一年,所以y=y-1。当时细心的同学会发现如果按照这种计算方法,保证m>2后,计算得到的y是闰年的话,会导致月的积日少计算一日,因为闰年2月为29天,这样的话,正确的公式应当如下:
闰年:月的积日=int(30.61*(m+1)) - 63 + 1 (m>2)
平年:月的积日=int(30.61*(m+1)) - 63 (m>2)
(3)日的积日计算,因为儒略日是从-4712年1月1日平午12:00开始的天数积累,-4712年1月2日对应的天数为0.5日,所以得一下公式:
日的积日 = d - 1.5
综上所述我们将上述过程画一个公式推导的流程图如下:
可以发现无论y是平年还是闰年,计算积日的公式均为:
JD = int(365.25*(y+4712)) + int(30.61*(m+1)) - 63 + 1 + d - 1.5 //注意公式中“+1”在平年和闰年时含义的不同
化简后如下:
JD=int(365.25*(y+4712)) + int(30.61*(m+1)) + d - 63.5 //该公式始终成立
2.2、格里高历转儒略日
(1)年的积日计算:因为格里高历每遇百年不能被400整除的话就不闰,按照之前年的积日计算方式就把1582年后百年中不需要闰的年份也闰了,所以要除掉这一部分,计算方式为:年的积日=int(365.25*(y+4712)) - int(y/100) + int(y/400) ,但是按照这种方式计算又存在把0年~1582年(应当为儒略历每四年一闰),其中每四年且为整百年的部分没有闰,没有闰的年数为12年(即12天),所以需要加上12天,所以年的积日计算为:
闰年:年的积日 = int(365.25*(y+4712)) - int(y/100) + int(y/400) + 12
平年:年的积日 = int(365.25*(y+4712)) + 1 - int(y/100) + int(y/400) + 12
(2)月的积日计算与儒略历完全一致。
(3)日的积日计算:格里高历就是目前通用的公历,是从1582年10月15日开始计算的,我们按照上面计算儒略历时的方法,相当于格里高历多计算了10天,所以要减去10天,所以积日的计算公式为:
日的积日 = d - 1.5 - 10
综上所述:同理格里高历转儒略日的计算公式为:
JD=int(365.25*(y+4712)) - int(y/100) + int(y/400) + 12 + int(30.61*(m+1)) - 63 + 1 + d - 1.5 -10 //注意公式中“+1”在平年和闰年的含义的不同
化简后计算公式如下:
JD=int(365.25*(y+4712)) - int(y/100) + int(y/400) + int(30.61*(m+1)) + d - 61.5 //该公式始终成立
不少文章中喜欢将格里高历计算儒略日和儒略历计算儒略日中不同的部分提取出来记作B,B= - int(y/100) + int(y/400) + 12 -10,这一部分是由于格里高历纪年方式改变而带来的,所以仅当时间大于等于1582年10月15日才使用,所以格里高历转儒略日计算公式又可以写为:
B = 2 - int(y/100) + int(y/400)
JD=int(365.25*(y+4712)) + int(30.61*(m+1)) + B + d - 63.5 //该公式始终成立
三、儒略日转公历(天文纪年)
3.1 儒略日转格里高历
儒略日转为格里高历(前提条件JD>2299160.5,即1582年10月15日后),一般有两种思路:
①将1582年10月15日后当做一直使用的儒略历。
②依然将1582年10月15日后按照格里高历计算(这种方式要考虑你采取的计算的历元起点到1582年10月15日前的置闰,和格里高历不一致的地方,你的计算历元起点在1582年后则不用考虑)。
这里我按照第一种思路去计算转换,这是因为下面我们还会讨论计算儒略日转儒略历,这里我们直接将JD转为假设我们一直使用儒略历所对应的儒略日JDr,就可以使用同样的计算规则了。假设JD对应的公历为Y年M月D日,这是格力高历所对应的日期,那么如果一直使用的儒略历要到这个Y年M月D日同样的日期JDr的值应该是多少?如果我们能得到JD与JDr的关系,那么我们可以直接使用JDr去计算对应的Y、M、D。我们先贴出计算公式然后来解释它,计算公式如下:
JD = JD + 0.5 //因为儒略日是从-4712年1月1日12时开始计算的,我们将其往前推0.5日,使其从-4712年1月1日0时开始计算,以适应我们公历日的计算
JD = JD + 10 //补偿1582年10月4日~1582年10月15日缺少的10日
a = int((JD - 2268993) / 36524.25)
//2268993是1500年3月1日的儒略日+0.5,这个地方必须从3月1日开始计算世纪,因为这是为了算出需要补多少天,如果重1600年1月1日起算的话,那么1700年1月1日和1700年3月1日对应的儒略日按照
//公式来看的话,都是需要补偿1日,但实际上1700年1月1日是不需要补偿的,因为1700年1月1日前没有经过平世纪,不需要补一天,为什么是要从1500年3月1日开始而不是1600年3月1日开始计算,
//是因为计算的起点我们需要用一个闰世纪天数作为开始,1500年3月1日~1600年3月1日对应的天数为36525天,是一个闰世纪天数,1600年3月1日~1700年3月1日对应的天数是36524天是一个平世纪天
//数,要想使用“(JD - 2268993) / 36524.25”这个式子,是不能从平世纪天数开始的。
JDr = JD + a - int((a+3) / 4) //补上世纪年缺少的部分
在1582年10月15日前,JD与JDr实际上是一致的,在这个日期之后产生的变化主要来源为,格里高历从1582年10月4日到1582年10月15日跳过了10日,再者是整百年不能被400整除的不闰,两个原因造成的,这两个原因造成的误差就是JD与JDr的关系。在按照儒略历的计算规则计算Y年M月D日时,是没有考虑跳过这10天的,所以JDr比实际的JD多10天,这是公式中10的由来。另外,格里高历整百年不能被400整除的不闰,而儒略历是都要闰的,所有JDr有多了格里高历少闰的的这几天,所以"JDr = JD + a - int((a+3) / 4)"
上述部分就是,当JD>2299160.5时的计算规则,可以写成:
JD = JD + 0.5
JD = JD + 10
a = int((JD - 2268993) / 36524.25)
JD = JD + a - int((a+3) / 4) //得到补偿后的JD
得到补偿后的JD,随后就完全按照儒略日转儒略历的计算规则来。下面直接介绍儒略日转儒略历的计算方法。
3.2 儒略日转儒略历
(1)年的计算:
y = int(JD/365.25) - 4712 //这个应该比较好理解,儒略历平均年长度365.25天,这里提示一下-4712年是366天,也就是计算的首年是366天,不做过多解释。
Y = y //得到Y,小y后面还有别的用处
(2)月的计算:
月的计算相对比较麻烦,记得我吗之前用于计算月的积日的公式“int(30.61*(m+1)) - 63”,这个时候我们要倒着使用这个公式,我们先得到去掉年的积日后剩下的日数muYD(minusYD),这个地方仍然存在平年与闰年的区别:
muYD = JD - int(365.25*(y+4712)) - 1 //平年
muYD = JD - int(365.25*(y+4712)) //闰年
同样的我们要判断muYD是不是属于1、2月,因为若是1、2月需要看做上一年的13、14月,判断这个的时候有个地方要注意,有平年和闰年的区别,如下:
muYD <= 59 //平年
muYD <= 60 //闰年闰年的时候也可以写作:
muYD = muYD - 1
muYD <= 59 //判断是否为1、2月
并且在闰年的时候我们也需要muYD = muYD - 1,2月始终被当做28天才能使用“int(30.61*(m+1)) - 63”这个公式计算出正确的月份,所以综上所述求muYD可以写为:
muYD = JD - int(365.25*(y+4712)) - 1
并且使用muYD <= 59来判断是否为1、2月,就不用管平年还是闰年了
,若muYD<=59,我们就要看做上一年的13、14月,所以:
y = y-1
muYD = JD - int(365.25*(y+4712)) - 1
再判断muYD <= 59,若不是则可以进行下一步了
这个地方有个陷阱,“int(30.61*(m+1)) - 63”这个公式没有理论说他是可逆的,我们需要举列说明一下它是可逆的。下面我列个与表2类似的表来看一下这个。
月份M | 月的积日MD | (MD+63)/30.61 (为了方便我只保留两位小数写在下面) | int((MD+63)/30.61) - 1 |
3 | 59 | 3.98 | 2 |
加1日 | 4.01 | 3 | |
4 | 90 | 4.99 | 3 |
加1日 | 5.03 | 4 | |
5 | 120 | 5.97 | 4 |
加1日 | 6.01 | 5 | |
6 | 151 | 6.99 | 5 |
加1日 | 7.02 | 6 | |
7 | 181 | 7.97 | 6 |
加1日 | 8.00 | 7 | |
8 | 212 | 8.89 | 7 |
加1日 | 9.01 | 8 | |
9 | 243 | 9.99 | 8 |
加1日 | 10.02 | 9 | |
10 | 273 | 10.97 | 9 |
加1日 | 11.00 | 10 | |
11 | 304 | 11.98 | 10 |
加1日 | 12.02 | 11 | |
12 | 334 | 12.96 | 11 |
加1日 | 13.00 | 12 | |
13 | 365 | 13.98 | 12 |
加1日 | 14.01 | 13 | |
14 | 396 | 14.99 | 13 |
从上表可以看出该公式逆向使用成立。另外儒略日计算的是整日,比如说muYD = 90,对应的就是3月31日24:00:00,其实就是4月1日00:00:00,没有24:00:00这个时刻,所以在计算正确的月份是muYD需要加一日,即:muYD + 1,然后再去计算。所以综上所述月份m的计算公式为:
muYD = JD - int(365.25*(y+4712)) - 1 //这个地方前一个“-1”是指,前面说的平年年积日少减1天或者闰年2月需要当成28天也需要减1天
如果muYD>=59,则 //这个地方因为满59天时,应该是3月1日
m = (int((muYD + 1 +63)/30.61) - 1
m = m>12 ? m-12 : m
若muYD<59,则
y = y - 1
muYD = JD - int(365.25*(y+4712)) - 1
m = (int((muYD + 1 +63)/30.61) - 1
M = m>12 ? m-12 : m //得到月,小m后面还有别的用处
(3)日的计算
//月的积日
闰年:月的积日=int(30.61*(m+1)) - 63 + 1 (m>2)
平年:月的积日=int(30.61*(m+1)) - 63 (m>2)
d = jd - int((y + 4712) * 365.25) - int(30.61*(m + 1)) + 63 - 1 + 1 //,小y,小m这个时候用到,这个就好理解了,就是减去年的积日,和月的积日就是日了,最后面这个+1,是因为儒略日满前一天24:00实际上是第二天0:00
上述过程画成流程图如下(左侧为不化简的,右侧为化简后的):
四、python代码如下
#公历转儒略日
# 公历转儒略日
def myDate2JD(y: int, m: int, d: int):
if m in [1, 2]:
m = m + 12
y = y - 1
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)
JD = int(365.25 * (y + 4712)) + int(30.6 * (m + 1)) + d - 63.5 + B
return JD
def myJD2Date(jd: float):
"""
儒略日转天文纪年
:param jd: 儒略日
:return: 年月日 时分秒
"""
re, jd = math.modf(jd + 0.5)
if jd >= 2299161: # 大于1582年10月15日
jd = jd + 10
a = int((jd - 2268993) / 36524.25) # 2268993为1500年3月1日的儒略日+0.5
jd = jd + a - int((a+3) / 4)
y = int(jd / 365.25) - 4712
Y = y
while True:
muYD = jd - int((y + 4712) * 365.25) - 1 # 除去年积日
if muYD >= 59:
m = int((muYD + 1 + 63) / 30.61) - 1
M = m - 12 if m > 12 else m
break
else:
y = y - 1
D = muYD - int(30.61 * (m + 1)) + 63 + 1
return Y, M, D
包含时分秒的转换代码如下:
import math
def myDate2JD(y: int, m: int, d: int, hh:int = 0, mm:int = 0, ss:float = 0.0):
"""
将年月日转换为儒略日
:param y: 年
:param m: 月
:param d: 日
:param hh: 时
:param mm: 分
:param ss: 秒
:return: 儒略日
"""
#日期转换
if m in [1, 2]:
m = m + 12
y = y - 1
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)
JD = int(365.25 * (y + 4712)) + int(30.61 * (m + 1)) + d - 63.5 + B
JD = JD + hh/24 + mm/60/24 + ss/60/60/24
return JD
def myJD2Date(jd: float):
"""
儒略日转天文纪年
:param jd: 儒略日
:return: 年月日 时分秒
"""
re, jd = math.modf(jd + 0.5)
if jd >= 2299161: # 大于1582年10月15日
jd = jd + 10
a = int((jd - 2268993) / 36524.25) # 2268993为1500年3月1日的儒略日+0.5
jd = jd + a - int((a+3) / 4)
y = int(jd / 365.25) - 4712
Y = y
while True:
muYD = jd - int((y + 4712) * 365.25) - 1 # 除去年积日
if muYD >= 59:
m = int((muYD + 1 + 63) / 30.61) - 1
M = m - 12 if m > 12 else m
break
else:
y = y - 1
D = muYD - int(30.61 * (m + 1)) + 63 + 1
re, hh = math.modf(re*24)
re, mm = math.modf(re*60)
ss = re*60
return Y, M, D, hh, mm, ss