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).
I know that this is not a Java Calendar API, but maybe you should try Jodd tool.
JulianDateStamp julianStamp = new JulianDateStamp(julianDays);
JDateTime jdate = new JDateTime(julianStamp);
Date date = new Date(jdate.getTimeInMillis());
This works perfect for:
- 2113488,2746855323 -> 1074.06.01 18:35
- 2453479,5866961805 -> 2005.04.19 02:04
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.
If you are willing to move outside the core JDK classes, then Joda can be a solution. Joda supports the Julian calendar system. From their doc page:
Chronology julianChrono = JulianChronology.getInstance();
DateTime dt = new DateTime(1066, 10, 14, 0, 0, 0, julianChrono);
That would be the Battle of Hastings 1066 in the Julian Calendar system.
来源:https://stackoverflow.com/questions/14988459/how-do-i-use-julian-day-numbers-with-the-java-calendar-api