Java 为什么这些奇怪的结果计算两个乔达瞬间之间的年数?

Java 为什么这些奇怪的结果计算两个乔达瞬间之间的年数?,java,jodatime,Java,Jodatime,最近,我无意中发现了使用Years.between()作为JODA计算某人年龄的最佳实践的提示。正如下面的示例所示,它通常不起作用 DateTime y0000 = new DateTime(0000, 1, 1, 0, 0, 0, 0); DateTime y2000 = new DateTime(2000, 1, 1, 0, 0, 0, 0); assertEquals(2000, new Period(y0000, y2000).getYears());

最近,我无意中发现了使用Years.between()作为JODA计算某人年龄的最佳实践的提示。正如下面的示例所示,它通常不起作用

    DateTime y0000 = new DateTime(0000, 1, 1, 0, 0, 0, 0);
    DateTime y2000 = new DateTime(2000, 1, 1, 0, 0, 0, 0);

    assertEquals(2000, new Period(y0000, y2000).getYears());
    assertEquals(1999, Years.yearsBetween(y0000.toInstant(), y2000.toInstant()).getYears());
    assertEquals(1999, new Period(y0000.toInstant(), y2000.toInstant()).getYears());
    assertEquals(2000, new Period(new DateTime(y0000),new DateTime(y2000)).getYears());
JODA是否按照设计在这里工作,或者这是JODA的缺陷

更新: 乔达按设计工作。如果您确实想使用
Years.between()


1999年即时转换的结果可以用一个事实来解释,即时区数据在很久以前没有得到很好的定义。Joda Time使用第二部分的估计区域偏移量(TZDB数据库中称为LMT条目)。这可能会导致0年和2000年的不同偏移,从而减少年增量。了解时区概念是19世纪的概念也是很重要的!所以你的代码毫无意义;-)这里设计的阴暗面也是Joda Time启用代码而不使时区效果可见和明确

我现在使用以下代码调查了本地时区的偏移量:

System.out.println(DateTimeZone.getDefault().getOffset(y0000.toInstant()) / 1000); // 3208 s
System.out.println(DateTimeZone.getDefault().getOffset(y2000.toInstant()) / 1000); // 3600 s
其结果是:必须从y0000中减去第一个较小的偏移量,然后从y2000中减去较大的偏移量,因此两个瞬间之间以秒为单位的差值不能等于以秒为单位的2000年。因此,年增量递减

为了避免这种意外的增量(显然您不会考虑任何时区影响),我强烈建议使用
LocalDateTime
之类的类型。与
DateTime
相比,这种类型没有时区,并且可以按您的期望执行(当然不需要转换为
Instant
)。否则,如果您关心“精确”的物理时差(通过不同的夏季/冬季时间或偏移量的历史估计),则预期的年差实际上并不正确,即应考虑时区偏移量。

根据我的评论(现在转移到本答案中):


1999年即时转换的结果可以用一个事实来解释,即时区数据在很久以前没有得到很好的定义。Joda Time使用第二部分的估计区域偏移量(TZDB数据库中称为LMT条目)。这可能会导致0年和2000年的不同偏移,从而减少年增量。了解时区概念是19世纪的概念也是很重要的!所以你的代码毫无意义;-)这里设计的阴暗面也是Joda Time启用代码而不使时区效果可见和明确

我现在使用以下代码调查了本地时区的偏移量:

System.out.println(DateTimeZone.getDefault().getOffset(y0000.toInstant()) / 1000); // 3208 s
System.out.println(DateTimeZone.getDefault().getOffset(y2000.toInstant()) / 1000); // 3600 s
其结果是:必须从y0000中减去第一个较小的偏移量,然后从y2000中减去较大的偏移量,因此两个瞬间之间以秒为单位的差值不能等于以秒为单位的2000年。因此,年增量递减


为了避免这种意外的增量(显然您不会考虑任何时区影响),我强烈建议使用
LocalDateTime
之类的类型。与
DateTime
相比,这种类型没有时区,并且可以按您的期望执行(当然不需要转换为
Instant
)。否则,如果您关心“精确的”物理时间差(通过不同的夏季/冬季时间或偏移的历史估计)那么,预期的年份差异实际上是不正确的,即应考虑时区偏移。

1999年即时转换的结果可能可以解释为,在遥远的过去,时区数据没有得到很好的定义。Joda Time使用第二部分的估计分区偏移。这可能会导致0年和2000年的不同偏移,从而减少年增量。了解时区概念是19世纪的概念也是很重要的!所以你的代码毫无意义;-)这里设计的阴暗面还在于Joda Time启用代码而不使时区效果可见和明确。它不仅仅适用于“遥远的过去”。我也发现了同样的问题,根据JODA的说法[194020000]是59岁。所有其他间隔(194020000)是正确的。这也可以用1940年和现在的不同时区偏移量来解释。这取决于您的系统时区。1999年即时转换的结果可能可以用一个事实来解释,即时区数据在很久以前没有得到很好的定义。Joda Time使用估计的带第二部分的时区偏移量。这可能会导致不同的结果ent抵消了0年和2000年,因此减少了年增量。了解时区概念是19世纪的概念也是很重要的!因此你的代码是没有意义的;-)这里设计的阴暗面也是Joda Time启用代码,而不使时区效果可见和显式。这不仅适用于“遥远的过去”。我还发现了同样的问题,根据JODA的说法,[194020000]是59年。所有其他时间间隔(19402000)都是正确的。这也可以用1940年和现在的不同时区偏移量来解释。这取决于您的系统时区。使用LocalDateTime确实有效。类名被混淆地命名为“Local”表示我的本地时间(带时区)。如果使用时区
UTC
,也可以使用
DateTime
,即DateTime y0000=新的日期时间(0000,1,1,0,0,0,DateTimeZone.UTC);“local”在Joda中基本上是指“无时区”(和JSR310)类型names@whaefelinger我同意名称
LocalDateTime
令人困惑,但它现在已经一成不变了。许多刚接触这个API的人都会对这个名称感到困惑。当然,我们可以在一段时间后习惯;-)使用LocalDateTime确实有效。类名被混淆为“Local”,表示我的本地时间(带时区).也可以工作