簡體   English   中英

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

[英]How do I use Julian Day Numbers with the Java Calendar API?

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;
    }
}

這里也提供了這個答案: 如何在Java Date和Julian day number之間進行轉換? 在當前的帖子中,提供了該算法的參考文獻以及一些更多的討論。 上述算法的實現也不包含Java API依賴(除了Math函數)。

我知道這不是Java Calendar API,但也許您應該嘗試使用Jodd工具。

JulianDateStamp julianStamp = new JulianDateStamp(julianDays);
JDateTime jdate = new JDateTime(julianStamp);
Date date = new Date(jdate.getTimeInMillis());

這適用於:

  • 2113488,2746855323 - > 1074.06.01 18:35
  • 2453479,5866961805 - > 2005.04.19 02:04

閱讀更多

java.time

Java 8及更高版本中內置的java.time框架取代了與最早版本的Java捆綁在一起的舊日期時間類。 請參閱Oracle教程 許多功能已被后移植到Java 6和7在ThreeTen-反向移植並且還適於在到Android ThreeTenABP

java.time類包括java.time.temporal.JulianFields 此類提供了TemporalField三個實現,以便為Julian僅日期值(無時間)提供有限支持。 所以你可以得到整天,而不是問題中要求的double 仔細閱讀該課程文檔,以確保它符合您的期望。 請注意,與大多數其他java.time類不同,這些Julian類會忽略任何來自UTC或時區的偏移信息(始終視為本地日期)。

  • JULIAN_DAY因為0天整天→計數,這是1月1日,4713 BCE儒略歷(-4713-11-24 公歷 )。
  • MODIFIED_JULIAN_DAY →與JULIAN_DAY相似但減去2_400_000.5 (基本上刪除了Julian日期編號的前兩位數字)。 請注意,此處的結果比上面項目的Julian日期數少一(-1)
  • RATA_DIE →與上述兩個項目類似,它是一個時代的天數。 但這里的時代是ISO 86010001-01-01日期。

在本例中,我們從1970-01-01的ISO 8601日期開始。

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 | 朱利安日期:2440588 | modifiedJulianDate:40587 | rataDie:719163

ThreeTen-EXTRA

ThreeTen-Extra項目是未來可能添加到java.time的實驗性驗證基礎。 該名稱來自定義java.time的JSR 310

該庫在其Julian日歷系統年表 )中包含對朱利安日期的額外支持。 與Java 8中的支持一樣,此庫僅限於僅限日期的值(不包括部分日期或時間)。

使用此庫,您可以實例化JulianDate對象。

有許多方法和功能供您查看。

如果您願意轉移到核心JDK類之外,那么Joda可以成為一個解決方案。 Joda支持Julian日歷系統。 從他們的文檔頁面:

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

那將是朱利安歷法系統中的黑斯廷斯戰役1066。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM