Convert a Julian Date to an Instant

前端 未结 4 1515
再見小時候
再見小時候 2021-01-05 14:58

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 under

4条回答
  •  礼貌的吻别
    2021-01-05 15:21

    Epoch of 14 September 1752

    My reading of the Wikipedia page on Calendar (New Style) Act 1750 indicates an epoch reference date of 1752-09-14.

    If we add the integer portion of your input number of 95906.27600694445, 95_906L, we do indeed get your target date of April 15, 2015 (in modern calendar system).

    long input = 95_906L;
    LocalDate epochCalendarNewStyleActOf1750 = LocalDate.of ( 1752 , Month.SEPTEMBER , 14 );
    LocalDate localDate = epochCalendarNewStyleActOf1750.plusDays ( input );
    System.out.println ( input + " days from epoch of: " + epochCalendarNewStyleActOf1750 + " is " + localDate );
    

    95906 days from epoch of: 1752-09-14 is 2015-04-15

    Regarding the fractional number, which I presume is the fraction of the number of seconds in a generic 24-hour day.

    While LocalDate is for date-only without time-of-day, we now need time-of-day which is represented by our fractional number. So in place of LocalDate, we switch to OffsetDateTime.

    OffsetDateTime epochCalendarNewStyleActOf1750 = LocalDate.of ( 1752 , Month.SEPTEMBER , 14 ).atStartOfDay ().atOffset ( ZoneOffset.UTC );
    

    We use BigDecimal as double and Double are floating-point technology that trades away accuracy for speed of execution.

    String input = "95906.27600694445";
    BigDecimal bd = new BigDecimal ( input );
    

    Pull from that the number of whole days.

    long days = bd.toBigInteger ().longValue ();
    

    Work on the fraction of a day. Extract the fractional number by subtracting the integer portion.

    BigDecimal fractionOfADay = bd.subtract ( new BigDecimal ( days ) ); // Extract the fractional number, separate from the integer number.
    

    We assume this decimal fraction is a fraction of the number of seconds in a day. So we can multiply by the number of seconds is a day.

    BigDecimal secondsFractional = new BigDecimal ( TimeUnit.DAYS.toSeconds ( 1 ) ).multiply ( fractionOfADay );
    

    From that, extract the number of whole seconds. From the remainder, produce a whole number nanoseconds, the resolution of the java.time classes including OffsetDateTime and Duration.

    long secondsWhole = secondsFractional.longValue ();
    long nanos = secondsFractional.subtract ( new BigDecimal ( secondsWhole ) ).multiply ( new BigDecimal ( 1_000_000_000L ) ).longValue ();
    

    Create a Duration to represent the amount of time we want to add to our epoch.

    Duration duration = Duration.ofDays ( days ).plusSeconds ( secondsWhole ).plusNanos ( nanos );
    

    Add the duration to the epoch to get our final result.

    OffsetDateTime odt = epochCalendarNewStyleActOf1750.plus ( duration );
    

    You can extract a Instant object from the OffsetDateTime.

    Instant instant = odt.toInstant();
    

    Dump to console.

    System.out.println ( "bd: " + bd );
    System.out.println ( "days: " + days );
    System.out.println ( "fractionOfADay.toString(): " + fractionOfADay );
    System.out.println ( "secondsFractional: " + secondsFractional );
    System.out.println ( "secondsWhole: " + secondsWhole );
    System.out.println ( "nanos: " + nanos );
    System.out.println ( "duration.toString(): " + duration );
    System.out.println ( "duration.toDays(): " + duration.toDays () );
    System.out.println ( "odt.toString(): " + odt );
    

    This code seems to be working properly. The result here matches the expectation stated in the Question to the second, though we disagree on the fraction of a second.

    No guarantees here; this code is fresh off the top of my head, and is quite untested and unproven.

    See this code run live at IdeOne.com.

    bd: 95906.27600694445

    days: 95906

    fractionOfADay.toString(): 0.27600694445

    secondsFractional: 23847.00000048000

    secondsWhole: 23847

    nanos: 480

    duration.toString(): PT2301750H37M27.00000048S

    duration.toDays(): 95906

    odt.toString(): 2015-04-15T06:37:27.000000480Z

    Of course this math could be simpler. But I thought it might be interesting to show the pieces. One simpler ways is to multiply the 95906.27600694445 BigDecimal by the number of seconds in a generic 24 hour day. Then separate the resulting integer from its decimal fraction, and feed each to Duration.ofSeconds and Duration::plusNanos as that fits the internal data model of Duration, a total number of seconds and a total number of nanos in a fraction of a second. We would be skipping the part where we called Duration.ofDays.


    About java.time

    The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

    The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

    To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

    Where to obtain the java.time classes?

    • Java SE 8 and SE 9 and later
      • Built-in.
      • Part of the standard Java API with a bundled implementation.
      • Java 9 adds some minor features and fixes.
    • Java SE 6 and SE 7
      • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
    • Android
      • The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
      • See How to use ThreeTenABP….

    The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

提交回复
热议问题