计算从闰年之间的年份

时间:2015-10-05 08:52:03

标签: java java-8 java-time leap-year

在计算两个日期之间的年份时,第二个日期是从第一个日期开始计算的(这是我正在处理的简化示例),LocalDatePeriod似乎计算了一年略有不同。

例如,

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

,而

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

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

这有什么好办法吗?

1 个答案:

答案 0 :(得分:3)

这个问题具有哲学性质,并且几乎没有时间测量和日期格式约定等问题。

LocalDateISO 8601日期交换标准的实现。 Java Doc明确声明此类不表示时间,但仅提供标准日期表示法。

API仅对符号本身提供简单操作,所有计算均通过递增来完成。给定的日期。

换句话说,在调用LocalDate.plusYears()时,您每个概念年都会增加365天,而不是一年内的确切时间。

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

在人类的理解中, date 不是一个时刻,而是一个时期。

从00h 00m 00s(...)开始,以23h 59m 59s(...)结束。

然而,

LocalDate避免了时间测量和人类时间单位模糊的问题(小时,以及都可以有不同的长度)和模型日期符号只是作为一个元组:

(years, months within a year, days within a month )

从那个时代开始计算。

在此解释中, Day 是影响日期的最小单位。

以下为例:

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

返回

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds

...显示,使用LocalDate并添加秒数(或更小的单位来提高精度),您无法克服问题中列出的限制。

查看实施后,您会在添加年份后找到LocalDate.plusYears()来电话resolvePreviousValid()。然后,此方法检查闰年并按以下方式修改字段:

day = Math.min(day, IsoChronology.INSTANCE.isLeapYear((long)year)?29:28);

换句话说,它通过有效扣除1天来纠正它。

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

LocalDate plusYear = date.plus(Year.of(date.getYear()).length(), ChronoUnit.DAYS);

您仍然会遇到以下奇怪事项(为了简洁起见,将Year.length()替换为日期计数):

LocalDate date = LocalDate.of(1996, 2, 29); 
LocalDate plusYear = date.plus(365, 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-02-28
0y 11m 30d

然后

LocalDate date = LocalDate.of(1996, 3, 29);
LocalDate plusYear = date.plus(365, 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-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一年和一天(增加2天!)。