Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Java8DateTime API转换修改过的Julian日数_Java_Date_Datetime_Julian Date - Fatal编程技术网

如何使用Java8DateTime API转换修改过的Julian日数

如何使用Java8DateTime API转换修改过的Julian日数,java,date,datetime,julian-date,Java,Date,Datetime,Julian Date,我有一个数据库,将日期和日期时间(分别作为整数和双精度)存储为修改的朱利安日数(MJD)。修改后的朱利安日数是从UTC午夜(1858年11月17日)开始的连续天数。根据定义,它们总是以UTC计算,与GMT的偏移量为+0:00,并且不调整夏令时。这些属性使用日期时间简化某些操作,例如优先级和日期算术 不利的一面是,MJD必须在使用前后从UTC重新本地化,并从非本地化回到UTC,特别是对于日期边界至关重要的应用程序(例如,医疗保险将计费日期边界识别为当地时间午夜) 考虑以下静态工厂方法,其目的是将“

我有一个数据库,将日期和日期时间(分别作为整数和双精度)存储为修改的朱利安日数(MJD)。修改后的朱利安日数是从UTC午夜(1858年11月17日)开始的连续天数。根据定义,它们总是以UTC计算,与GMT的偏移量为+0:00,并且不调整夏令时。这些属性使用日期时间简化某些操作,例如优先级和日期算术

不利的一面是,MJD必须在使用前后从UTC重新本地化,并从非本地化回到UTC,特别是对于日期边界至关重要的应用程序(例如,医疗保险将计费日期边界识别为当地时间午夜)

考虑以下静态工厂方法,其目的是将“区域日数”(基本上是已添加适当偏移量的MJD,以表示本地日期时间)非定域为MJD(UTC):

直观地看,如果您有一个本地日期和时间,并且您知道本地时区,那么您应该拥有将
regDN
偏移回UTC所需的所有信息(根据MJD的要求)

事实上,使用以前的Java日历API编写此函数相当简单。
regDN
很容易转换为
Date
,用于设置GregoriaCalendar实例。了解“本地时区”后,日历会报告区域偏移量和DST偏移量值,这些值可用于将日数调整为MJD

这是我在Java 8 DateTime API中编写类似算法的尝试:

public static MJD ofDayNumberInZone(double zonedMJD, ZoneId zone) {
        double epochSec = ((zonedMJD - MJD.POSIX_EPOCH_AS_MJD) * 86400.0);
        LocalDateTime dt = LocalDateTime
            .ofEpochSecond(
                    (long) epochSec, 
                    (int) (epochSec - Math.floor(epochSec) * 1000000000.0),
--->                zone.getRules().getOffset( <Instant> )
            );   
}

根据你的评论,你的核心问题似乎是关于将一个没有时区(a)的日期时间转换成一个分区时刻(a)的模糊性。您解释了夏时制(DST)等异常可能导致无效值

ZonedDateTime zdt = myLocalDateTime.atZone( myZoneId );
这是真的。在DST“向前跳”或“向后退”切换中着陆时,没有完美的解决方案。但是,java.time类确实通过采用某种策略来解决这种模糊性。您可能同意也可能不同意该政策。但如果您同意,那么您可以依靠java.time来确定结果

要引用以下文档:

在重叠的情况下,时钟被向后设置,有两个有效偏移。如果首选偏移是有效偏移之一,则使用它。否则,使用较早的有效偏移量,通常对应于“summer”

在间隙的情况下,时钟向前跳,没有有效的偏移。相反,本地日期时间会根据间隔的长度调整为更晚。对于典型的一小时夏令时更改,本地日期时间将在一小时后移动到通常对应于“夏季”的偏移量中

今天:2017-03-19 天数:57831

我不太理解你的问题。但在我看来,MJD(修改后的朱利安日)的意义在于有一种方法来跟踪“一个真实时间”,以避免所有时区的混淆。在标准ISO 8601日历系统中,UTC扮演着“一个真实时间”的角色。所以我建议坚持UTC

当你需要考虑一个地区的挂钟时间,比如你的医疗保险的例子,该地区的一天结束,确定区域墙壁时钟时间,然后转换为UTC。java.time中的
Instant
类的定义始终是UTC

ZoneId z = ZoneId.of( "America/Los_Angeles" );
LocalDate localDate = LocalDate.now( z );
ZonedDateTime firstMomentNextDay = localDate.plusDays( 1 ).atStartOfDay( z );
Instant medicareExpiration = firstMomentNextDay.toInstant(); // UTC
BigDecimal modJulDays = this.convertInstantToModifiedJulianDays( medicareExpiration ) ;
使用小数时,如果精度很重要,请使用
BigDecimal
。使用
double
double
float
float
意味着使用浮点技术,以牺牲精度换取更快的性能

下面是一些代码的粗略裁剪,用于将BigDecimal(修改过的Julian Days)转换为Instant。我想一些聪明的人可能会发现这段代码的更精简或更吝啬的版本,但我这里的代码似乎正在工作。使用风险自负。我几乎没有测试过这段代码

public Instant convertModifiedJulianDaysToInstant ( BigDecimal modJulDays ) {
    Instant epoch = OffsetDateTime.of ( 1858, 11, 17, 0, 0, 0, 0, ZoneOffset.UTC ).toInstant ( ); // TODO: Make into a constant to optimize.
    long days = modJulDays.toBigInteger ( ).longValue ( );
    BigDecimal fractionOfADay = modJulDays.subtract ( new BigDecimal ( days ) ); // Extract the fractional number, separate from the integer number.
    BigDecimal secondsFractional = new BigDecimal ( TimeUnit.DAYS.toSeconds ( 1 ) ).multiply ( fractionOfADay );
    long secondsWhole = secondsFractional.longValue ( );
    long nanos = secondsFractional.subtract ( new BigDecimal ( secondsWhole ) ).multiply ( new BigDecimal ( 1_000_000_000L ) ).longValue ( );
    Duration duration = Duration.ofDays ( days ).plusSeconds ( secondsWhole ).plusNanos ( nanos );
    Instant instant = epoch.plus ( duration );
    return instant;
}
然后去另一个方向

public BigDecimal convertInstantToModifiedJulianDays ( Instant instant ) {
    Instant epoch = OffsetDateTime.of ( 1858, 11, 17, 0, 0, 0, 0, ZoneOffset.UTC ).toInstant ( ); // TODO: Make into a constant to optimize.
    Duration duration = Duration.between ( epoch, instant );
    long wholeDays = duration.toDays ( );
    Duration durationRemainder = duration.minusDays ( wholeDays );

    BigDecimal wholeDaysBd = new BigDecimal ( wholeDays );
    BigDecimal partialDayInNanosBd = new BigDecimal ( durationRemainder.toNanos ( ) ); // Convert entire duration to a total number of nanoseconds.
    BigDecimal nanosInADayBd = new BigDecimal ( TimeUnit.DAYS.toNanos ( 1 ) );  // How long is a standard day in nanoseconds?
    int scale = 9; // Maximum number of digits to the right of the decimal point.
    BigDecimal partialDayBd = partialDayInNanosBd.divide ( nanosInADayBd ); // Get a fraction by dividing a total number of nanos in a day by our partial day of nanos.
    BigDecimal result = wholeDaysBd.add ( partialDayBd );
    return result;
}
调用那些转换方法

    BigDecimal input = new BigDecimal ( "57831.5" );
    Instant instant = this.convertModifiedJulianDaysToInstant ( input );
    BigDecimal output = this.convertInstantToModifiedJulianDays ( instant );
转储到控制台

    System.out.println ( "input.toString(): " + input );
    System.out.println ( "instant.toString(): " + instant );
    System.out.println ( "output.toString(): " + output );
input.toString():57831.5

instant.toString():2017-03-19T12:00:00Z

output.toString():57831.5

看看这些


同样,对于一个类似的问题也可能有帮助。

分区MJD
转换为
UTC MJD
的方法的目的也是如此?我不使用Java,但让我们想象一下你成功了。我希望您能够在程序运行时获得有效的偏移量,或者考虑到日期并更改当前年份夏令时的偏移量。当DST的开始/结束日期不同时,我不希望Java能够提供历史补偿,当然,预测国会未来的行动是不可能的。那么,您是否适当考虑了历史或未来的日期/时间?@GerardAshton:这是一个与我的问题无关的单独问题,但是Java DateTime API完全支持IANA时区数据库,并为特定于区域的时间偏移计算提供历史上准确的偏移量。我注意到getOffset方法需要一个瞬间,它是从纪元开始的秒和纳秒创建的。但是如果你不知道偏移量,也不知道格林尼治/UTC时间,那么你就无法计算出从纪元开始的秒数,所以你无法创建瞬间。@GerardAshton:这是我遇到的悖论。。。如果-你-知道当地时间和当地时区,那么-你-有足够的信息正确到达UTC。然而,Java 8 DateTime API似乎无法构造任何瞬间,除非它知道如何在UTC内部表示它(显然,事先知道UTC的偏移量是一个先决条件)。我被困在如何利用当地时间和时区并从中获得瞬间。这在旧的API中很简单,但我正在寻找新的API
public BigDecimal convertInstantToModifiedJulianDays ( Instant instant ) {
    Instant epoch = OffsetDateTime.of ( 1858, 11, 17, 0, 0, 0, 0, ZoneOffset.UTC ).toInstant ( ); // TODO: Make into a constant to optimize.
    Duration duration = Duration.between ( epoch, instant );
    long wholeDays = duration.toDays ( );
    Duration durationRemainder = duration.minusDays ( wholeDays );

    BigDecimal wholeDaysBd = new BigDecimal ( wholeDays );
    BigDecimal partialDayInNanosBd = new BigDecimal ( durationRemainder.toNanos ( ) ); // Convert entire duration to a total number of nanoseconds.
    BigDecimal nanosInADayBd = new BigDecimal ( TimeUnit.DAYS.toNanos ( 1 ) );  // How long is a standard day in nanoseconds?
    int scale = 9; // Maximum number of digits to the right of the decimal point.
    BigDecimal partialDayBd = partialDayInNanosBd.divide ( nanosInADayBd ); // Get a fraction by dividing a total number of nanos in a day by our partial day of nanos.
    BigDecimal result = wholeDaysBd.add ( partialDayBd );
    return result;
}
    BigDecimal input = new BigDecimal ( "57831.5" );
    Instant instant = this.convertModifiedJulianDaysToInstant ( input );
    BigDecimal output = this.convertInstantToModifiedJulianDays ( instant );
    System.out.println ( "input.toString(): " + input );
    System.out.println ( "instant.toString(): " + instant );
    System.out.println ( "output.toString(): " + output );