Eva*_*les 9 java leap-year java-8 java-time
在计算两个日期之间的年份时,第二个日期是从第一个日期开始计算的(这是我正在研究的一个简化示例),LocalDate并且Period似乎计算一年略有不同.
例如,
LocalDate date = LocalDate.of(1996, 2, 29);
LocalDate plusYear = date.plusYears(1);
System.out.println(Period.between(date, plusYear).getYears());
Run Code Online (Sandbox Code Playgroud)
而
LocalDate date = LocalDate.of(1996, 3, 29);
LocalDate plusYear = date.plusYears(1);
System.out.println(Period.between(date, plusYear).getYears());
Run Code Online (Sandbox Code Playgroud)
尽管明确增加了一年,但第一次Period返回的年份为0第二种情况1.
这有什么好的方法吗?
这个问题具有哲学性质,涵盖了一些问题,例如时间测量和日期格式约定。
LocalDate是ISO 8601数据交换标准的实施。Java Doc 明确指出该类不表示时间,而仅提供标准日期表示法。
API 仅提供对符号本身的简单操作,所有计算都是通过递增给定日期的Year、Month或Day来完成的。
换句话说,打电话时LocalDate.plusYears()您添加的是每年 365 天的概念年,而不是一年内的确切时间量。
这使得日成为可以添加到由 表示的日期的最小时间单位LocalDate。
在人类的理解中,日期不是时间中的一个时刻,而是一个时期。
它以 00h 00m 00s (...) 开始,以 23h 59m 59s (...) 结束。
LocalDate然而,避免了时间测量和人类时间单位模糊的问题(小时、天、月和年都可以有不同的长度),并将日期符号简单地建模为元组:
(years, months within a year, days within a month )
从纪元开始计算。
在这种解释中,日是影响日期的最小单位是有道理的。
如下所示:
LocalDate date = LocalDate.of(1996, 2, 29);
LocalDate plusSecond = date.plus(1, ChronoUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)
回报
java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
Run Code Online (Sandbox Code Playgroud)
...这表明,使用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);
Run Code Online (Sandbox Code Playgroud)
您仍然会遇到以下奇怪的情况(为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");
Run Code Online (Sandbox Code Playgroud)
回报
1997-02-28
0y 11m 30d
Run Code Online (Sandbox Code Playgroud)
然后
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");
Run Code Online (Sandbox Code Playgroud)
回报
1997-03-29
1y 0m 0d
Run Code Online (Sandbox Code Playgroud)
最后:
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");
Run Code Online (Sandbox Code Playgroud)
返回:
1997-03-01
1y 0m 1d
Run Code Online (Sandbox Code Playgroud)
请注意,将日期移动366 天(而不是365天)会将期限从11 个月零 30 天增加到1 年零 1 天(增加 2 天!)。
| 归档时间: |
|
| 查看次数: |
456 次 |
| 最近记录: |