儒略日的计算
现在的公历起源于埃及历,由古罗马的恺撒在公元前46年制定的,365
日作为一年,单月为大月31天,双月为小月30天,4年一闰,称为"儒略历"或"恺撒历"。
1582年罗马教皇格里高利十三世(Gregorius XⅢ)对"儒略历"又进行修改,规定被4
整除的年为闰年,但逢百之年只有能被400
除尽才能是闰年。这就是使用至今的"格里历"。教皇于1582年10月 4
日还下令将次日(即原10月5日)定为10月15日,把春分日又恢复为3月21日。
儒略日(Julian day,JD)是由法国学者 Joseph Justus Scaliger(1540-1609
)发明的,是天文学上不用一种不用年、月的长期纪日法,用它可以很方便地计算到两时?
涞慵湟蕴焓屏康氖奔浼涓簟H迓匀找怨?713年儒略历1月1
日格林威治平午为起算日期,以7980
年为一个周期,每天顺数而下,流水计日。儒略日的这种计算方法相当方便,获得了天文?
缒诘囊恢虏捎茫翘煳募扑阒凶钗匾募扑慊肌?
例如:JD=245 191 9.34230,它意味着距儒略周期的开始已经逝去了2451919
天。而小数点后的".34230"代表这天的时间("15:12:54 EST")
,在天体位置计算中是最具信息量的数据。再比如世界时公元2009年3月1号的儒略日是
2454891.8333333335天。
注意,"儒略日(julian Day)" 与"儒略历(Julian Calendar)"指的不是同一概念。
由于儒略日的表达数值太长,需要7
位数字表示天数,因此,后来又出现了一种约化儒略日(Modified Julian Day,MJD
)的记法,MJD = JD - 2,400,000.5,即约化儒略日的起算点在1858年11月16
日平午。之所以采用约化儒略日的表达方法,主要有一下2个方面的考虑:
1.日期天数的计算往往习惯以午夜时分起算,而不是正午。
2.在1859至2130年之间,只需要5位数字来表示日期就够了,而不需要全部的7位数字
因此MJD 0就等于JD 2400000.5。对于计算机来说,MJD也意味着更少的存储单元
下面介绍几种儒略日的计算方法:
(一):求出给定年(I),月(J),日(K)的儒略日:
JD=K-32075+1461*(I+4800+ (J-14)/12)/4+367*(J-2-(J-14)/12*12)/12-3*((I+4900+(J-
14)/12)/100)/4
貌似很简单的样子,baidu搜索来之,没用过,不知如何处理1582年那消失的10天。
(二):根据Fundamental Astronomy上介绍的算法,c语言表述:
float jde(int Y,int M,int D,int hour,int min,int sec)
{
long int f,g,mid1,mid2;
float J,JDE,A;
if(M>=3)
{
f=Y;
g=M;
}
if(M==1||M==2)
{
f=Y-1;
g=M=12;
};
mid1=floor(365.25*f);
mid2=floor(30.6001*(g+1));
A=2-floor(f/100)+floor(f/400);
J=mid1+mid2+D+A+1720994.5;
JDE=J+hour/24+min/1440+sec/86400;
return JDE;
};
上述函数返回float类型可能精度不够,最好用double类型。
(三)Jean Meeus的《天文算法》(Astronomical Algorithms,2nd Edition
)第二版中第7章第60页内有详细介绍计算儒略日的方法:
设Y为给定年份,M为月份,D
为该月日期(带小数,把时:分:秒折算成日的形式)。运算符INT
表示为取所给数的整数部分,也即小数点前的部分。
1.若M > 2,Y和M不变。
若 M =1或2,以Y-1代Y,以M+12代M。
换句话说,如果日期在1月或2月,则被看作是在前一年的13月或14月。
2.对格里高利历(即1582年10月15日以后),有
A = INT(Y/100),
B = 2 - A + INT(A/4).
另外,对于儒略历(即1582年10月15日之前),取B=0。
3.所求的儒略日即为:
因为处理器的字长问题,计算机不能精确表示 30.6,比如当5乘30.6刚好是153
,而在处理器内部却表示成152.999 999 8的结果,会使取整操作(INT
)与预期不符,故用30.6001代替30.6,以期得到正确的结果(事实上,30.601甚至30.61
亦可)。
以下列的是一个著名的星图软件stellarium里内对于Jean Meeus
所介绍的方法的实际代码,个人比较推荐:
double get_julian_day (const ln_date * cdate)
{
ln_date date;
int y, m, B;
date = *cdate;
y = date.years;
m = date.months;
if (date.months <= 2)
{
y = date.years - 1;
m = date.months + 12;
}
// Correct for the lost days in Oct 1582 when the Gregorian calendar
// replaced the Julian calendar.
B = -2;
if (date.years > 1582 || (date.years == 1582 && (date.months > 10 || (date
.months == 10 && date.days >= 15))))
{
B = y / 400 - y / 100;
}
return (floor(365.25 * y) +
floor(30.6001 * (m + 1)) + B + 1720996.5 +
date.days + date.hours / 24.0 + date.minutes / 1440.0 + date.
seconds / 86400.0);
}
其中结构体date定义如下:
typedef struct
{
int years; /*!< Years. All values are valid */
int months; /*!< Months. Valid values : 1 (January) - 12 (December
) */
int days; /*!< Days. Valid values 1 - 28,29,30,31 Depends on month
.*/
int hours; /*!< Hours. Valid values 0 - 23. */
int minutes; /*!< Minutes. Valid values 0 - 59. */
double seconds; /*!< Seconds. Valid values 0 - 59.99999.... */
}ln_date;
上述代码是0.8版本的source code,在julian_day.c
文件内。在该文件内,还有一个从儒略日JD反推日期、时间的函数,很强大。stellarium
目前最新的版本是0.10.2,最近刚release,可以在我前面给的链接内找到下载。
(四)下面是一个计算儒略日的JavaScript:
function compute(form) {
MM=eval(form.nmonth.value);
DD=eval(form.nday.value);
YY=eval(form.nyear.value);
HR=eval(form.nhour.value);
MN=eval(form.nminute.value);
SC=eval(form.nsecond.value);
with (Math) {
HR = HR + (MN / 60) + (SC/3600);
GGG = 1;
if (YY <= 1585) GGG = 0;
JD = -1 * floor(7 * (floor((MM + 9) / 12) + YY) / 4);
S = 1;
if ((MM - 9)<0) S=-1;
A = abs(MM - 9);
J1 = floor(YY + S * floor(A / 7));
J1 = -1 * floor((floor(J1 / 100) + 1) * 3 / 4);
JD = JD + floor(275 * MM / 9) + DD + (GGG * J1);
JD = JD + 1721027 + 2 * GGG + 367 * YY - 0.5;
JD = JD + (HR / 24);
}
form.result.value = JD;
}
function gettodayandnow(form) {
var now = new Date();
var hours = now.getUTCHours();
var minutes = now.getUTCMinutes();
var seconds = now.getUTCSeconds()
var month = now.getUTCMonth() + 1;
var day = now.getUTCDate();
var year = now.getUTCFullYear();
form.nmonth.value=month;
form.nday.value=day;
form.nyear.value=year;
form.nhour.value=hours;
form.nminute.value=minutes;
form.nsecond.value=seconds;
}
(五)再来一个脚本程序:
function compute(form)
{
var y = parseFloat(form.year.value)
var m = parseFloat(form.month.value)
var d = parseFloat(form.day.value)
var uh = parseFloat(form.uth.value)
var um = parseFloat(form.utm.value)
var us = parseFloat(form.uts.value)
var extra = 100.0*y + m - 190002.5
var rjd = 367.0*y
rjd -= Math.floor(7.0*(y+Math.floor((m+9.0)/12.0))/4.0)
rjd += Math.floor(275.0*m/9.0)
rjd += d
rjd += (uh + (um + us/60.0)/60.)/24.0
rjd += 1721013.5
rjd -= 0.5*extra/Math.abs(extra)
rjd += 0.5
form.result.value = rjd-0.3333333333
}