Java 将儒略日期转换为即时日期

Java 将儒略日期转换为即时日期,java,time,java-8,julian-date,Java,Time,Java 8,Julian Date,我遇到了这样一种情况,我想将Julian日期转换为an(如果有意义的话),或者转换为更容易理解的Java时间。我对朱利安约会的理解来自于阅读《圣经》。有很多不同的日期,我试图阅读的日期使用了不同于这些日期的纪元 例如,假设纪元是时间的开始,儒略日期是95906.27600694445,在这种情况下,我认为是CE 2015年4月15日06:37:26.9 UT,我如何从中获得瞬间?稍后我需要调整时区 我注意到有一个叫做的类,但我不知道在哪里/如何使用它。此外,我在包中看到的大多数方法都使用了int

我遇到了这样一种情况,我想将Julian日期转换为an(如果有意义的话),或者转换为更容易理解的Java时间。我对朱利安约会的理解来自于阅读《圣经》。有很多不同的日期,我试图阅读的日期使用了不同于这些日期的纪元

例如,假设纪元是时间的开始,儒略日期是
95906.27600694445
,在这种情况下,我认为是CE 2015年4月15日06:37:26.9 UT,我如何从中获得瞬间?稍后我需要调整时区

我注意到有一个叫做的类,但我不知道在哪里/如何使用它。此外,我在包中看到的大多数方法都使用了
int
long
,而不是真正的
double


那么,有没有一种简单的方法可以将使用不同纪元的儒略日期转换为Java 8
即时日期(或者,如果我的想法是错误的,可以转换为其他时间)。

我假设您有一个数字时间戳,它是一种修改后的儒略日数,即从定义的纪元开始的连续天数

例如,“修改后的朱利安日数”的定义是自1858年11月17日午夜起的连续天数。我相信你的问题是:

我如何换算自2001年以来英国的连续天数 公历被正式采用到了一瞬间

我不确定在新的日历法之后,公历的正式开始是在哪里。我将假设这是1752年1月1日,也就是说,这个数字
95906.276
是从那时起的连续天数

方法1:这里有一个算法,用于将日数处理为整数数组表示形式,以年、月(1-12)、日(1-31)、小时(0-23)、分钟(0-59)、秒(0-59)、毫秒为单位:


下面是一个使用新Java 8类的解决方案:

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
    }
}
关于您询问的
JulianFields
,您可以定义如下自定义格式化程序:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendValue(JulianFields.MODIFIED_JULIAN_DAY)
    .toFormatter().withZone(ZoneOffset.UTC);
不幸的是,它不支持几天的分数:

System.out.println(formatter.format(Instant.now())); // Output: 57249
System.out.println(LocalDate.from(formatter.parse("57249"))); // Output: 2015-08-15
1752年9月14日纪元 我在上读到的维基百科页面表明,纪元参考日期为1752-09-14

如果我们将您的输入编号的整数部分添加到
95906.27600694445
95906l
,我们确实可以得到您的目标日期2015年4月15日(在现代日历系统中)

1752-09-14是2015-04-15

关于分数,我认为是一天24小时内秒数的分数

虽然
LocalDate
只表示日期,而不表示一天中的时间,但我们现在需要一天中的时间,它由分数表示。因此,代替
LocalDate
,我们切换到
OffsetDateTime

OffsetDateTime epochCalendarNewStyleActOf1750 = LocalDate.of ( 1752 , Month.SEPTEMBER , 14 ).atStartOfDay ().atOffset ( ZoneOffset.UTC );
我们使用as
double
double
来权衡执行速度的准确性

String input = "95906.27600694445";
BigDecimal bd = new BigDecimal ( input );
从这一数字中得出整个天数

long days = bd.toBigInteger ().longValue ();
每天工作一小部分时间。通过减去整数部分提取小数

BigDecimal fractionOfADay = bd.subtract ( new BigDecimal ( days ) ); // Extract the fractional number, separate from the integer number.
我们假设这个小数点是一天中秒数的一小部分。我们可以乘以一天的秒数

BigDecimal secondsFractional = new BigDecimal ( TimeUnit.DAYS.toSeconds ( 1 ) ).multiply ( fractionOfADay );
从中提取整秒数。从余数中产生整数纳秒,即java.time类的分辨率,包括
OffsetDateTime
Duration

long secondsWhole = secondsFractional.longValue ();
long nanos = secondsFractional.subtract ( new BigDecimal ( secondsWhole ) ).multiply ( new BigDecimal ( 1_000_000_000L ) ).longValue ();
创建一个
Duration
来表示我们要添加到历元中的时间量

Duration duration = Duration.ofDays ( days ).plusSeconds ( secondsWhole ).plusNanos ( nanos );
将持续时间添加到历元以获得最终结果

OffsetDateTime odt = epochCalendarNewStyleActOf1750.plus ( duration );
您可以从
OffsetDateTime
中提取
即时
对象

Instant instant = odt.toInstant();
转储到控制台

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 );
此代码似乎工作正常。这里的结果与问题中所述的第二个期望值相匹配,尽管我们在一秒的分数上存在分歧

这里没有保证;这段代码是我头脑中最新的,而且还没有经过测试和验证

看这个

屋宇署:95906.27600694445

天数:95906

fractionOfADay.toString():0.27600694445

第二部分:23847.00000048000

第二洞:23847

奈米:480

duration.toString():PT2301750H37M27.00000048S

duration.toDays():95906

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

当然,这个数学可能更简单。但我认为展示这些作品可能会很有趣。一种简单的方法是将
95906.27600694445
BigDecimal乘以一天24小时内的秒数。然后将得到的整数与其小数部分分开,并将它们分别馈送到
Duration.ofSeconds
Duration::plusNanos
,因为这符合
Duration
的内部数据模型,总秒数和总纳秒数在几分之一秒内。我们将跳过调用
Duration.ofDays
的部分


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

从哪里获得java.time类

  • 后来
    • 内置的
    • 标准JavaAPI的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 该项目专门为Android采用了ThreeTen Backport(如上所述)
该项目使用其他类扩展了java.time。这个项目是java.time将来可能添加的一个试验场。你可以
OffsetDateTime odt = epochCalendarNewStyleActOf1750.plus ( duration );
Instant instant = odt.toInstant();
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 );
double customJD = 95906.27600694445; 

// my comment: I have never seen Julian days with that epoch until now    
HistoricCalendar hcal = // date when the new style calendar act took effect
    HistoricCalendar.of(ChronoHistory.of(Locale.UK), HistoricEra.AD, 1752, 9, 14);

// last term 0.5 necessary because julian days start at noon
double value = customJD + hcal.get(EpochDays.JULIAN_DAY_NUMBER) - 0.5;
JulianDay jd = JulianDay.ofSimplifiedTime(value);
Instant instant = jd.toMoment().toTemporalAccessor();

System.out.println(instant); // 2015-04-15T06:37:27Z