如何使用Java日历API使用朱利安日数字? [英] How do I use Julian Day Numbers with the Java Calendar API?

查看:146
本文介绍了如何使用Java日历API使用朱利安日数字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

朱利安日数字是一种将时间戳表示为从UTC,1月1日中午12时(UTC)起的连续日数(以及分数天)的方法。 Java 7 SE API不包含对此格式的支持。使用SQLite数据库的开发人员可能使用了strftime()函数提供的原生Julian Day支持。



将时间戳表示为Julian日数的优点包括: / p>


  • 在原始数据类型中,日期和时间可以表示为毫秒精度(双精度)


  • 如果此精确度不重要,则避免闰秒问题

  • 日期之间的天数算术是微不足道的;



  • 缺点




    • Java日期/时间API没有对JDN的内置支持

    • 不适合进行非常精确的时间测量

    • 仅针对UTC定义,必须从UTC映射到本地时间

    • 不适合向最终用户显示;必须在显示之前进行转换/格式化



    朱利安日数通常用于天文计算,其定义高度标准化和可接受。类似地,修正的朱利安日数(其从UTC UTC午夜算起,1858年11月17日)被标准地定义并用于航空应用(参见 http ://tycho.usno.navy.mil/mjd.html )。



    对于广泛使用日期/时间算法或按时间排序的应用程序或者如果持久的轻量级图元比持久化时间戳更有吸引力),内部表示日期和时间作为JDN或MJD可能对你有意义。



    下面的代码定义了方便使用儒略日数字或修改的儒略日数字与Java日期/时间/日历API。该代码基于Jean Meeus的Astronomical Algorithms,1991年第1版中出版的算法。

      public class JulianDay {

    private static final int YEAR = 0;
    private static final int MONTH = 1;
    私有静态final int DAY = 2;
    private static final int HOURS = 3;
    private static final int MINUTES = 4;
    private static final int SECONDS = 5;
    private static final int MILLIS = 6;




    //在下面的
    //顺序(从索引0到6)中转换作为整数数组显示的时间戳。 :年,月,日,时,分,秒,月
    //月(1-12),日(1-28或29),小时(0-23) )到
    //修改的Julian日数。
    //为了清楚和简单起见,假设输入值形式良好;
    //错误检查未在代码段中实现。

    public static double toMJD(int [] ymd_hms){

    int y = ymd_hms [YEAR];
    int m = ymd_hms [MONTH];
    double d =(double)ymd_hms [DAY];

    d = d +((ymd_hms [HOURS] / 24.0)+
    (ymd_hms [MINUTES] / 1440.0)+
    (ymd_hms [SECONDS] / 86400.0)+
    (ymd_hms [MILLIS] / 86400000.0));

    if(m == 1 || m == 2){
    y--;
    m = m + 12;
    }

    double a = Math.floor(y / 100);
    double b = 2 - a + Math.floor(a / 4);

    return(Math.floor(365.25 *(y + 4716.0))+
    Math.floor(30.6001 *(m + 1))+
    d + b - 1524.5) 2400000.5; // for Julian Day omit the 2400000.5 term
    }

    //将修改的Julian Day Number(double)转换为表示
    的整数数组//时间戳(年,月,天,小时,分钟,秒,毫秒)。适用于所有正JDN

    public static int [] toTimestamp(double mjd){

    int ymd_hms [] = {-1,-1,-1, -1,-1,-1};
    int a,b,c,d,e,z;

    double jd = mjd + 2400000.5 + 0.5; //如果JDN作为参数传递,
    //省略2400000.5项
    double f,x;

    z =(int)Math.floor(jd);
    f = jd - z;

    if(z> = 2299161){
    int alpha =(int)Math.floor((z - 1867216.25)/ 36524.25);
    a = z + 1 + alpha - (int)Math.floor(alpha / 4);
    } else {
    a = z;
    }

    b = a + 1524;
    c =(int)Math.floor((b - 122.1)/ 365.25);
    d =(int)Math.floor(365.25 * c);
    e =(int)Math.floor((b - d)/ 30.6001);

    ymd_hms [DAY] = b - d - (int)Math.floor(30.6001 * e);
    ymd_hms [MONTH] =(e <14)
    ? (e - 1)
    :(e - 13);
    ymd_hms [YEAR] =(ymd_hms [MONTH]> 2)
    ? (c - 4716)
    :(c - 4715);

    for(int i = HOURS; i <= MILLIS; i ++){
    switch(i){
    case HOURS:
    f = f * 24.0;
    break;
    case MINUTES:case SECONDS:
    f = f * 60.0;
    break;
    case MILLIS:
    f = f * 1000.0;
    break;
    }
    x = Math.floor(f);
    ymd_hms [i] =(int)x;
    f = f-x;
    }

    return ymd_hms;
    }
    }

    这里也提供了这个答案:如何在Java日期和Julian之间进行转换天数?。在当前的文章中,提供了该算法的参考以及一些更多的讨论。上述算法的实现也不包含Java API依赖项(除了数学函数)。

    解决方案

    java.time



    Java 8和更高版本中内置的java.time框架取代了与最早版本的Java捆绑在一起的旧日期时间类。请参见 Oracle教程。许多功能已经被移植到Java 6& 7在 ThreeTen-Backport 中进一步修改,并在 ThreeTenABP



    java.time类包括 java.time.temporal.JulianFields 此类提供了 TemporalField ,以有限地支持Julian仅日期值(没有时间)。所以你可以得到整天数,而不是问题中请求的 double 。仔细阅读类doc,以确保它符合您的期望。请注意,与大多数其他java.time类不同,这些Julian类忽略任何偏移UTC或时区信息(始终被视为本地日期)。


    • JULIAN_DAY →自第0天(即儒略历4713年1月1日(4713)起的整天天数)(-4713-11-24 Gregorian )。

    • MODIFIED_JULIAN_DAY →喜欢JULIAN_DAY,但减去 2_400_000.5 (基本上丢弃Julian日期数字的前两位数字)。请注意,这里的结果比上述项目的Julian日期数少少(-1)

    • RATA_DIE →类似于上面的两个项目,时代。但这里的日期是 ISO 8601 日期 0001-01-01 。



    在本例中,我们从ISO 8601开始 01-01

      LocalDate localDate = LocalDate.of(1970,1,1) 
    long julianDate = JulianFields.JULIAN_DAY.getFrom(localDate);
    long modifiedJulianDate = JulianFields.MODIFIED_JULIAN_DAY.getFrom(localDate);
    long rataDie = JulianFields.RATA_DIE.getFrom(localDate);




    localDate:1970-01-01 | julian日期:2440588 |修改日期:40587 | rataDie:719163




    ThreeTen-Extra



    ThreeTen-Extra 项目是将来可能增加java.time的实验性证明。该名称来自定义java.time的 JSR 310



    此库在其 Julian日历系统 Chronology )。与Java 8中的支持一样,此库仅限于日期值(无日期或时间)。



    使用此库,您可以实例化 JulianDate 对象。



    许多方法和功能你来检查一下。


    Julian Day Numbers are a means of representing timestamps as a continuous count of days (and fractional days) since noon UTC, January 1, 4713 B.C. The Java 7 SE API does not contain support for this format. Developers who have used the SQLite database may have used the native Julian Day support provided by the strftime() functions.

    The advantages of representing timestamps as Julian Day Numbers include:

    • A date and time can be represented to millisecond precision in a primitive data type (double)
    • Days in a year are somewhat more concrete than seconds in a day
    • Circumvents the problem of "leap seconds" if this degree of precision is unimportant
    • Days between dates arithmetic is trivial; sorting precedence is easily determined
    • Very lightweight

    Disadvantages

    • The Java Date/Time API does not have built-in support for JDN's
    • Unsuitable for very precise time measurements
    • Only defined for UTC and must be mapped from UTC to local time
    • Unsuitable for display to end-users; must be converted/formatted before display

    Julian Day Numbers are commonly used in astronomical calculations and their definition is highly standardized and accepted. Similarly, Modified Julian Day Numbers (which count from midnight UTC, 17 November 1858) are standardly defined and used in aerospace applications (see http://tycho.usno.navy.mil/mjd.html).

    For applications that make extensive use of date/time arithmetic or chronological sorting (or if persisting lightweight primitives is more appealing than persisting timestamps), internally representing dates and times as JDN's or MJD's may make sense for you.

    The following code defines functions that facilitate using either Julian Day Numbers or Modified Julian Day Numbers with the Java Date/Time/Calendar API. The code is based on algorithms published in Jean Meeus's "Astronomical Algorithms", 1st ed., 1991.

    public class JulianDay {
    
        private static final int YEAR = 0;
        private static final int MONTH = 1;
        private static final int DAY = 2;
        private static final int HOURS = 3;
        private static final int MINUTES = 4;
        private static final int SECONDS = 5;
        private static final int MILLIS = 6;
    
        :
        :
    
        // Converts a timestamp presented as an array of integers in the following
        // order (from index 0 to 6): year,month,day,hours,minutes,seconds,millis
        // month (1-12), day (1-28 or 29), hours (0-23), min/sec (0-59) to a
        // Modified Julian Day Number.
        // For clarity and simplicity, the input values are assumed to be well-formed;
        // error checking is not implemented in the snippet.
    
        public static double toMJD(int[] ymd_hms) {
    
            int y = ymd_hms[YEAR];
            int m = ymd_hms[MONTH];
            double d = (double) ymd_hms[DAY];
    
            d = d + ((ymd_hms[HOURS] / 24.0) +
                     (ymd_hms[MINUTES] / 1440.0) +
                     (ymd_hms[SECONDS] / 86400.0) +
                     (ymd_hms[MILLIS] / 86400000.0));
    
            if (m == 1 || m == 2) {
                y--;
                m = m + 12;
            }
    
            double a = Math.floor(y / 100);
            double b = 2 - a + Math.floor(a / 4);
    
            return (Math.floor(365.25 * (y + 4716.0)) +
                   Math.floor(30.6001 * (m + 1)) +
                   d + b - 1524.5) - 2400000.5;  // for Julian Day omit the 2400000.5 term
        }
    
        // Converts an Modified Julian Day Number (double) to an integer array representing
        // a timestamp (year,month,day,hours,mins,secs,millis). Works for all positive JDN
    
        public static int[] toTimestamp(double mjd) {
    
            int ymd_hms[] = { -1, -1, -1, -1, -1, -1, -1 };
            int a, b, c, d, e, z;
    
            double jd = mjd + 2400000.5 + 0.5;  // if a JDN is passed as argument,
                                                // omit the 2400000.5 term
            double f, x;
    
            z = (int) Math.floor(jd);
            f = jd - z;
    
            if (z >= 2299161) {
                int alpha = (int) Math.floor((z - 1867216.25) / 36524.25);
                a = z + 1 + alpha - (int) Math.floor(alpha / 4);
            } else {
                a = z;
            }
    
            b = a + 1524;
            c = (int) Math.floor((b - 122.1) / 365.25);
            d = (int) Math.floor(365.25 * c);
            e = (int) Math.floor((b - d) / 30.6001);
    
            ymd_hms[DAY] = b - d - (int) Math.floor(30.6001 * e);
            ymd_hms[MONTH] = (e < 14)
                    ? (e - 1)
                    : (e - 13);
            ymd_hms[YEAR] = (ymd_hms[MONTH] > 2)
                    ? (c - 4716)
                    : (c - 4715);
    
            for (int i = HOURS; i <= MILLIS; i++) {
                switch(i) {
                    case HOURS:
                        f = f * 24.0;
                        break;
                    case MINUTES: case SECONDS:
                        f = f * 60.0;
                        break;
                    case MILLIS:
                        f = f * 1000.0;
                        break;  
                }
                x = Math.floor(f);
                ymd_hms[i] = (int) x;
                f = f - x;
            }   
    
            return ymd_hms;
        }
    }
    

    This answer has been provided here as well: How can I convert between a Java Date and Julian day number?. In the current post, references for the algorithm are provided along with some more discussion. The implementation of algorithms above also contains no Java API dependencies (aside from Math functions).

    解决方案

    java.time

    The java.time framework built into Java 8 and later supplants the old date-time classes bundled with the earliest versions of Java. See Oracle Tutorial. Much of the functionality has been back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.

    The java.time classes include the java.time.temporal.JulianFields. This class provides three implementations of TemporalField to give limited support for Julian date-only values (no time-of-day). So you can get whole number of days, not the double requested in the Question. Read that class doc closely to be sure it behaves to your expectations. Note that unlike most other java.time classes, these Julian classes ignore any offset-from-UTC or time zone information (always treated as a local date).

    • JULIAN_DAY → Count of whole days since day 0, which is January 1, 4713 BCE in the Julian calendar ( -4713-11-24 Gregorian ).
    • MODIFIED_JULIAN_DAY → Like JULIAN_DAY but subtracting 2_400_000.5 (basically dropping the first two digits of Julian date number). Note that results here are one fewer (-1) than Julian date number of item above.
    • RATA_DIE → Similar to the two items above in that it is a count of days from an epoch. But here the epoch is the ISO 8601 date of 0001-01-01.

    In this example we start with the ISO 8601 date of 1970-01-01.

    LocalDate localDate = LocalDate.of ( 1970 , 1 , 1 );
    long julianDate = JulianFields.JULIAN_DAY.getFrom ( localDate );
    long modifiedJulianDate = JulianFields.MODIFIED_JULIAN_DAY.getFrom ( localDate );
    long rataDie = JulianFields.RATA_DIE.getFrom ( localDate );
    

    localDate: 1970-01-01 | julianDate: 2440588 | modifiedJulianDate: 40587 | rataDie: 719163

    ThreeTen-Extra

    The ThreeTen-Extra project is the experimental proving grounds for possible future additions to java.time. The name comes from the JSR 310 that defines java.time.

    This library includes additional support for Julian dates in its Julian calendar system (Chronology). Like the support in Java 8, this library is limited to date-only values (no partial days or time-of-day).

    With this library you can instantiate JulianDate objects.

    Many methods and features for you to examine there.

    这篇关于如何使用Java日历API使用朱利安日数字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆