最近我偶然发现提示使用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缺陷?
更新:
JODA按设计工作。如果您确实想使用Years.between()
,请使用LocalDateTime
或确保使用DateTimeZone.UTC
。
答案 0 :(得分:0)
从我的评论(现已转入此答案):
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
)。否则,如果你关心"确切"实际时间差异(通过不同的夏季/冬季时间或偏移的历史估计)然后预期年份差异不是真正正确,即应考虑时区偏移。