Java 计算闰年与闰年之间的年数

Java 计算闰年与闰年之间的年数,java,java-8,java-time,leap-year,Java,Java 8,Java Time,Leap Year,在计算两个日期之间的年份时,第二个日期是从第一个日期开始计算的(这是我正在研究的一个简化示例),LocalDate和Period计算年份的方式似乎略有不同 比如说, LocalDate date = LocalDate.of(1996, 2, 29); LocalDate plusYear = date.plusYears(1); System.out.println(Period.between(date, plusYear).getYears()); 当 尽管明确添加了一年,但第一个Per

在计算两个日期之间的年份时,第二个日期是从第一个日期开始计算的(这是我正在研究的一个简化示例),
LocalDate
Period
计算年份的方式似乎略有不同

比如说,

LocalDate date = LocalDate.of(1996, 2, 29);
LocalDate plusYear = date.plusYears(1);
System.out.println(Period.between(date, plusYear).getYears());

尽管明确添加了一年,但第一个
Period
将年份返回为
0
,而第二个案例返回
1


有没有一个简单的方法来解决这个问题?

这个问题具有哲学性质,并且跨越了一些问题,比如时间测量和日期格式约定

LocalDate
是日期交换标准的实现。 Javadoc明确指出,此类不表示时间,但只提供标准的日期表示法

API仅提供符号本身的简单操作,所有计算都是通过增加给定日期的、月、日来完成的

换句话说,当调用
LocalDate.plusYears()
时,您添加的是概念上的年份,每个年份365天,而不是一年中的确切时间

这使得Day成为可以添加到由
LocalDate
表示的日期的最低时间单位

在人类的理解中,日期不是时间上的一个瞬间,而是一个周期

它以00h 00m 00s(…)开始,以23h 59m 59s(…)结束

LocalDate
但是避免了时间测量和人类时间单位模糊的问题(小时、年都可以有不同的长度),并且将日期表示法简单地建模为以下元组:

(年、年内月、月内天)

从时代开始计算

在这种解释中,是影响日期的最小单位,这是有道理的

例如:

LocalDate date = LocalDate.of(1996, 2, 29);
LocalDate plusSecond = date.plus(1, ChronoUnit.SECONDS);
返回

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
1997-02-28
0y 11m 30d
。。。这表明,使用
LocalDate
并添加秒数(或更小的单位来驱动精度),您无法克服问题中列出的限制

查看实现,您会发现在添加年份后,调用
resolvePreviousValid()
。然后,此方法检查闰年,并按以下方式修改字段:

day=Math.min(day,IsoChronology.INSTANCE.isLeapYear((长)年)→29:28)

换句话说,它通过有效地减去1天来纠正它

您可以使用
Year.length()
,它返回给定年份的天数,并将返回闰年的366。所以你可以这样做:

LocalDate plusYear = date.plus(Year.of(date.getYear()).length(), ChronoUnit.DAYS);
您仍然会遇到以下奇怪情况(为了简洁起见,调用
Year.length()
替换为天数):

返回

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
1997-02-28
0y 11m 30d
然后

返回

1997-03-29
1y 0m 0d
最后:

LocalDate date = LocalDate.of(1996, 2, 29);
LocalDate plusYear = date.plus(366, ChronoUnit.DAYS);
System.out.println(plusYear);
Period between = Period.between(date, plusYear);
System.out.println( between.getYears() + "y " +
                    between.getMonths() + "m " +
                    between.getDays() + "d");
返回:

1997-03-01
1y 0m 1d

请注意,将日期由366改为365天,将期限从11个月和30天增加到1年和1天(增加2天!)。

@dotvav:给出的示例对我来说非常清楚。。。我看不出有什么问题。这并不是因为他们计算年份的方式不同——这只是历法算术的一个怪癖。正如你所说,这种行为是合理的。你能准确地描述一下你希望这种行为是什么样的吗?(虽然说这是合理的,但野田佳彦在这种情况下确实有一年的时间:)@MenoHochschild:我强烈怀疑两种“模式”的算术在某些情况下都有用,而在其他情况下则不太有用。我认为故意宣称野田佳彦的时间完全按照文档记录的方式运行时存在缺陷是不合理的。(注意,这也是OP想要的行为,表明我认为它在某些情况下是有用的……)考虑到一个太阳年超过365天,从1997年1月1日午夜到1998年1月1日午夜之间,地球并没有绕太阳公转一圈。。。这里把天文学视为真理的终极源泉就到此为止了。正如米沙所说——在国际海事组织看来,任何一种方式都是合理的,只要有记录在案。
1997-03-01
1y 0m 1d