如何在Java Calendar API中使用Julian Day Numbers?

时间:2013-02-20 19:37:20

标签: java date calendar timestamp julian

Julian Day Numbers是一种将时间戳表示为自公元前4713年1月1日中午UTC以来连续天数(和分数天数)的方法。 Java 7 SE API不包含对此格式的支持。使用过SQLite数据库的开发人员可能已经使用了strftime()函数提供的本机Julian Day支持。

将时间戳表示为Julian Day Numbers的优点包括:

  • 日期和时间可以表示为基本数据类型(双精度)的毫秒精度
  • 一年中的日子比一天中的几天要复杂得多
  • 如果这种精确度不重要,可以解决“闰秒”的问题
  • 日期之间的算术算术是微不足道的;排序优先顺序很容易确定
  • 非常轻量级

缺点

  • Java Date / Time API没有对JDN的内置支持
  • 不适合进行非常精确的时间测量
  • 仅为UTC定义,必须从UTC映射到本地时间
  • 不适合向最终用户展示;必须在显示之前转换/格式化

朱利安日数字通常用于天文计算,其定义高度标准化并被接受。同样,修改后的朱利安日数(从1858年11月17日午夜开始计算)是标准定义并用于航空航天应用(见http://tycho.usno.navy.mil/mjd.html)。

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

以下代码定义了有助于将Julian Day Numbers或Modified Julian Day Numbers与Java Date / Time / Calendar API一起使用的函数。该代码基于Jean Meeus的“Astronomical Algorithms”,第1版,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;
    }
}

这里也提供了这个答案:How can I convert between a Java Date and Julian day number?。在当前的帖子中,提供了该算法的参考文献以及一些更多的讨论。上面的算法实现也不包含Java API依赖(除了Math函数)。

3 个答案:

答案 0 :(得分:2)

我知道这不是Java Calendar API,但您可以尝试使用Jodd工具。

$content

这非常适合:

  • 2113488,2746855323 - &gt; 1074.06.01 18:35
  • 2453479,5866961805 - &gt; 2005.04.19 02:04

Read more

答案 1 :(得分:1)

java.time

Java 8及更高版本中内置的java.time框架取代了与最早版本的Java捆绑在一起的旧日期时间类。见Oracle Tutorial。许多功能已经被后端移植到Java 6&amp; ThreeTen-Backport中的7,并在ThreeTenABP中进一步适应Android。

java.time类包含java.time.temporal.JulianFields。此类提供了TemporalField的三个实现,以仅为Julian日期值(无时间)提供有限支持。因此,您可以获得整天,而不是问题中请求的double。仔细阅读该课程文档,以确保它符合您的期望。请注意,与大多数其他java.time类不同,这些Julian类会忽略任何来自UTC或时区的偏移信息(始终视为本地日期)。

  • JULIAN_DAY→自第0天起的整天数,即公元前4713年1月1日,朱利安历法(-4713-11-24 Gregorian)。
  • MODIFIED_JULIAN_DAY→与JULIAN_DAY类似,但减去2_400_000.5(基本上删除了Julian日期编号的前两位数字)。请注意,此处的结果比上面项目的Julian日期数少一(-1)
  • RATA_DIE→与上述两项相似,它是一个时代的天数。但这里的纪元是0001-01-01的{​​{3}}日期。

在此示例中,我们从{8}的ISO 8601日期开始。

1970-01-01
  

localDate:1970-01-01 |朱利安日期:2440588 | modifiedJulianDate:40587 | rataDie:719163

ThreeTen-EXTRA

ISO 8601项目是未来可能添加到java.time的实验性验证基础。该名称来自定义java.time的ThreeTen-Extra

此库在其JSR 310Julian calendar system)中包含对Julian日期的额外支持。与Java 8中的支持一样,此库仅限于仅限日期的值(不包括部分日期或时间)。

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

您可以在那里查看许多方法和功能。

答案 2 :(得分:0)

如果您愿意移出核心JDK类,那么Joda可以是一个解决方案。 Joda支持Julian日历系统。从他们的文档页面:

Chronology julianChrono = JulianChronology.getInstance();
DateTime dt = new DateTime(1066, 10, 14, 0, 0, 0, julianChrono);

这将是朱利安历法系统中的黑斯廷斯战役1066。