这个问题具有哲学性质,涉及时间测量和日期格式约定等几个问题。
LocalDate
是ISO 8601日期交换标准的实施。Java Doc 明确指出该类不表示时间,而仅提供标准日期表示法。
API 仅提供对符号本身的简单操作,所有计算都是通过递增给定日期的Year或Month或Day来完成的。
换句话说,当你打电话给你时,LocalDate.plusYears()
你是在添加每个 365 天的概念年份,而不是一年内的确切时间量。
这使得Day成为可以添加到由 表示的日期的最低时间单位LocalDate
。
在人类的理解中,日期不是一个时刻,而是一个时期。
它以 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()
which 返回给定年份的天数,并在闰年返回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 年零 1 天(增加 2 天!)。