Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
510 views
in Technique[技术] by (71.8m points)

date - How do I use Julian Day Numbers with the Java Calendar API?

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).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...