Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert a Julian Date to an Instant

I'm running into a situation where I would like to convert from a Julian date to an java.time.Instant (if that makes sense), or some Java time that can be more easily understood. My understanding of what a Julian date is comes from reading the Wikipedia page. There are bunch of different variants, and the date I am trying to read uses a different epoch than any of these.

For example, let's say the epoch is the beginning of the Calendar (New Style) Act 1750, and the Julian date is 95906.27600694445 which in this case I believe is CE 2015 April 15 06:37:26.9 UT, how do I get an instant from this? I will need to adjust for the timezone later.

I noticed there is a class called JulianFields, but I don't know where/how to use it. Also, most of the methods I see in the package make use of int or long, not really anything for double.

So, is there a simple way to convert from a Julian date using a different epoch to a Java 8 Instant (or some other time if my thinking is wrong).

like image 405
mkobit Avatar asked Aug 14 '15 18:08

mkobit


1 Answers

Here is a solution using the new Java 8 classes:

public class JulianDay {
    private static final double NANOS_PER_DAY = 24.0 * 60.0 * 60.0 * 1000000000.0;

    // Calculate Instants for some epochs as defined in Wikipedia.
    public static final Instant REDUCED_JD =
            ZonedDateTime.of(1858, 11, 16, 12, 0, 0, 0, ZoneOffset.UTC).toInstant();
    public static final Instant MODIFIED_JD =
            ZonedDateTime.of(1858, 11, 17, 0, 0, 0, 0, ZoneOffset.UTC).toInstant();
    public static final Instant JULIAN_DATE =
            REDUCED_JD.minus(2400000, ChronoUnit.DAYS);

    private final Instant epoch;

    public JulianDay(Instant epoch) {
        super();
        this.epoch = epoch;
    }

    public Instant toInstant(double day) {
        long l = (long) day;
        return epoch
                .plus(l, ChronoUnit.DAYS)
                .plusNanos(Math.round((day - l) * NANOS_PER_DAY));
    }

    public static void main(String[] args) {
        // Use the example values from Wikipedia for 2015-09-07 13:21 UTC.
        System.out.println(new JulianDay(REDUCED_JD).toInstant(57273.05625));
        // Output: 2015-09-07T13:21:00.000000126Z
        System.out.println(new JulianDay(MODIFIED_JD).toInstant(57272.55625));
        // Output: 2015-09-07T13:21:00.000000126Z
        System.out.println(new JulianDay(JULIAN_DATE).toInstant(2457273.05625));
        // Output: 2015-09-07T13:20:59.999991953Z
    }
}

Regarding the JulianFields you asked about, you can define a custom formatter like this:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendValue(JulianFields.MODIFIED_JULIAN_DAY)
    .toFormatter().withZone(ZoneOffset.UTC);

Unfortunately it doesn't support fractions of days:

System.out.println(formatter.format(Instant.now())); // Output: 57249
System.out.println(LocalDate.from(formatter.parse("57249"))); // Output: 2015-08-15
like image 89
Sleafar Avatar answered Oct 30 '22 12:10

Sleafar