如何将Java集合中连续间隔1天的日期划分成时间段?
嗨,这个需求我之前做项目的时候碰到过,其实核心就是利用TreeSet的有序特性(LocalDate默认按自然日期排序),遍历的时候把连续的日期归为同一个时间段就行,我给你捋捋具体的实现思路和代码:
实现思路
- 先判断集合是否为空,为空直接返回空结果
- 初始化第一个时间段的开始和结束为集合的第一个日期
- 按顺序遍历集合中的每个日期:
- 如果当前日期是上一个时间段结束日期的次日(间隔1天),就把当前日期设为时间段的新结束
- 如果不连续,就把之前的时间段存入结果列表,然后以当前日期为起点开始新的时间段
- 遍历结束后,别忘了把最后一个时间段加入结果列表
具体代码实现
首先我们可以自定义一个简单的DateRange类来存储时间段的开始和结束日期:
import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.TreeSet; // 自定义时间段类,封装开始和结束日期 class DateRange { private final LocalDate start; private final LocalDate end; public DateRange(LocalDate start, LocalDate end) { this.start = start; this.end = end; } // 重写toString,方便输出:单日期直接显示日期,多日期显示"开始至结束" @Override public String toString() { return start.equals(end) ? start.toString() : start + " 至 " + end; } // 按需添加getter方法 public LocalDate getStart() { return start; } public LocalDate getEnd() { return end; } }
然后是核心的时间段划分方法:
public static List<DateRange> splitIntoContinuousRanges(TreeSet<LocalDate> dates) { List<DateRange> resultRanges = new ArrayList<>(); if (dates.isEmpty()) { return resultRanges; } // 初始化第一个时间段的开始和结束 LocalDate currentStart = dates.first(); LocalDate currentEnd = currentStart; for (LocalDate date : dates) { // 跳过第一个元素,已经初始化过了 if (date.equals(currentStart)) { continue; } // 检查当前日期是否和上一个结束日期连续(间隔1天) if (date.equals(currentEnd.plusDays(1))) { currentEnd = date; } else { // 不连续,把当前时间段存入结果,开始新的时间段 resultRanges.add(new DateRange(currentStart, currentEnd)); currentStart = date; currentEnd = date; } } // 把最后一个时间段加入结果 resultRanges.add(new DateRange(currentStart, currentEnd)); return resultRanges; }
调用示例(结合你的代码)
public static void main(String[] args) { TreeSet<LocalDate> dates = getDaysBetween("2017-02-01","2017-03-31"); dates.removeAll(getDaysBetween("2017-01-01","2017-02-01")); dates.removeAll(getDaysBetween("2017-03-01","2017-03-04")); dates.removeAll(getDaysBetween("2017-03-08","2017-03-08")); dates.removeAll(getDaysBetween("2017-03-10","2017-03-12")); // 假设还有其他removeAll操作... // 划分时间段并输出 List<DateRange> continuousRanges = splitIntoContinuousRanges(dates); continuousRanges.forEach(System.out::println); }
一些注意点
- 因为TreeSet是有序集合,遍历的时候不需要额外排序,这也是这个方案高效的原因
- 要注意
removeAll的逻辑,比如你第一个removeAll操作会把2017-02-01从集合中移除,所以后续的时间段会从2017-02-02开始 - 如果你的
getDaysBetween方法包含起始和结束日期,那remove操作会准确移除这些日期,没问题
内容的提问来源于stack exchange,提问作者Carl
相关产品推荐
相关产品推荐

