参考DateTime重叠算法,如何改用LocalDate实现日期区间天数计算?
用LocalDate计算两个日期区间的重叠天数
我之前在处理日期区间重叠计算时也踩过类似的坑,Java 8引入的LocalDate确实比旧的DateTime好用,但需要调整一下计算逻辑来避免负数问题。下面是我验证过的可行实现:
核心逻辑梳理
两个日期区间[A_start, A_end]和[B_start, B_end]的重叠天数计算,关键是先找到实际重叠的区间:
- 重叠区间的起始日期是两个区间起始的最大值(
max(A_start, B_start)) - 重叠区间的结束日期是两个区间结束的最小值(
min(A_end, B_end))
如果重叠起始日期 <= 重叠结束日期,说明存在重叠,再计算这个区间的天数;否则重叠天数为0。
具体代码实现
import java.time.LocalDate; import java.time.temporal.ChronoUnit; public class DateOverlapCalculator { public static long calculateOverlapDays(LocalDate range1Start, LocalDate range1End, LocalDate range2Start, LocalDate range2End) { // 确定重叠区间的边界 LocalDate overlapStart = LocalDate.max(range1Start, range2Start); LocalDate overlapEnd = LocalDate.min(range1End, range2End); // 计算重叠天数:因为ChronoUnit.DAYS.between是左闭右开,所以要把结束日期加1来包含当天 long overlapDays = ChronoUnit.DAYS.between(overlapStart, overlapEnd.plusDays(1)); // 如果没有重叠(overlapStart > overlapEnd),between会返回负数,取0即可 return Math.max(overlapDays, 0); } public static void main(String[] args) { // 测试案例1:部分重叠 LocalDate r1s1 = LocalDate.of(2024, 1, 1); LocalDate r1e1 = LocalDate.of(2024, 1, 10); LocalDate r2s1 = LocalDate.of(2024, 1, 5); LocalDate r2e1 = LocalDate.of(2024, 1, 15); System.out.println(calculateOverlapDays(r1s1, r1e1, r2s1, r2e1)); // 输出6(5号到10号共6天) // 测试案例2:完全不重叠 LocalDate r1s2 = LocalDate.of(2024, 1, 1); LocalDate r1e2 = LocalDate.of(2024, 1, 5); LocalDate r2s2 = LocalDate.of(2024, 1, 6); LocalDate r2e2 = LocalDate.of(2024, 1, 10); System.out.println(calculateOverlapDays(r1s2, r1e2, r2s2, r2e2)); // 输出0 // 测试案例3:一个区间完全包含另一个 LocalDate r1s3 = LocalDate.of(2024, 1, 1); LocalDate r1e3 = LocalDate.of(2024, 1, 20); LocalDate r2s3 = LocalDate.of(2024, 1, 5); LocalDate r2e3 = LocalDate.of(2024, 1, 15); System.out.println(calculateOverlapDays(r1s3, r1e3, r2s3, r2e3)); // 输出11(5号到15号共11天) // 测试案例4:区间首尾相连(比如range1结束于10号,range2开始于10号) LocalDate r1s4 = LocalDate.of(2024, 1, 1); LocalDate r1e4 = LocalDate.of(2024, 1, 10); LocalDate r2s4 = LocalDate.of(2024, 1, 10); LocalDate r2e4 = LocalDate.of(2024, 1, 15); System.out.println(calculateOverlapDays(r1s4, r1e4, r2s4, r2e4)); // 输出1(包含10号) } }
为什么之前的方法会失效?
你之前直接用ChronoUnit.DAYS.between(LD1, LD2.plusDays(1))没有先判断重叠区间的有效性,当两个区间完全不重叠时,计算出来的天数会是负数,而如果直接拿这个负数参与后续的“取最小数”逻辑,就会得到错误的结果。通过先确定重叠边界,再用Math.max(overlapDays, 0)把负数转为0,就能完美解决这个问题。
内容的提问来源于stack exchange,提问作者3rdRockSoftware
相关产品推荐
相关产品推荐

