zoukankan      html  css  js  c++  java
  • 儒略日的计算

    儒略日的计算

    现在的公历起源于埃及历,由古罗马的恺撒在公元前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
    }

  • 相关阅读:
    UWA 技术分享连载 转载
    移动游戏加载性能和内存管理全解析 学习
    英语书籍阅读
    2017年6月
    Unity 官方文档学习
    YAML Class ID Reference
    Unity Blog 学习
    希腊字母
    2017年5月
    转载:书籍
  • 原文地址:https://www.cnblogs.com/shaoguangleo/p/2805809.html
Copyright © 2011-2022 走看看