You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java中计算同一任务下type=0的多段时间范围总时长并去除重叠时间

如何在Java中合并重叠时间段并计算总耗时?

我完全懂你的痛点——直接用Duration.between计算每段时间再累加,会把重叠部分重复计算,得先把重叠的时间段合并成不重叠的连续段,再算总时长就准确了。针对你给出的SQL数据,咱们一步步来实现:

核心思路

  1. 排序:先把所有type=0的时间段按开始时间从小到大排序,这是合并操作的基础;
  2. 合并重叠/连续段:遍历排序后的时间段,和已合并的最后一段对比,重叠或连续就更新结束时间,不重叠就新增一段;
  3. 计算总时长:对合并后的每段时间用Duration.between计算时长,再累加得到总耗时。

代码实现

首先定义对应数据库表的实体类:

import java.time.LocalDateTime;

public class Timeline {
    private LocalDateTime startTime;
    private LocalDateTime endTime;
    private int type;

    // 构造器
    public Timeline(LocalDateTime startTime, LocalDateTime endTime, int type) {
        this.startTime = startTime;
        this.endTime = endTime;
        this.type = type;
    }

    // Getter和Setter
    public LocalDateTime getStartTime() { return startTime; }
    public void setStartTime(LocalDateTime startTime) { this.startTime = startTime; }
    public LocalDateTime getEndTime() { return endTime; }
    public void setEndTime(LocalDateTime endTime) { this.endTime = endTime; }
    public int getType() { return type; }
    public void setType(int type) { this.type = type; }
}

然后写合并和计算的核心逻辑:

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class NonOverlappingTimeCalculator {

    public static Duration calculateTotalNonOverlappingTime(List<Timeline> type0Timelines) {
        // 第一步:按开始时间排序
        type0Timelines.sort(Comparator.comparing(Timeline::getStartTime));

        List<Timeline> mergedTimelines = new ArrayList<>();
        for (Timeline current : type0Timelines) {
            if (mergedTimelines.isEmpty()) {
                // 第一个时间段直接加入合并列表
                mergedTimelines.add(current);
            } else {
                Timeline lastMerged = mergedTimelines.get(mergedTimelines.size() - 1);
                // 判断当前时间段是否和最后一段重叠或连续
                if (current.getStartTime().isBefore(lastMerged.getEndTime()) || current.getStartTime().isEqual(lastMerged.getEndTime())) {
                    // 合并操作:更新最后一段的结束时间为两者的最大值
                    LocalDateTime newEnd = lastMerged.getEndTime().isAfter(current.getEndTime()) 
                        ? lastMerged.getEndTime() 
                        : current.getEndTime();
                    lastMerged.setEndTime(newEnd);
                } else {
                    // 不重叠,直接加入合并列表
                    mergedTimelines.add(current);
                }
            }
        }

        // 第二步:计算合并后的总时长
        Duration totalDuration = Duration.ZERO;
        for (Timeline timeline : mergedTimelines) {
            totalDuration = totalDuration.plus(Duration.between(timeline.getStartTime(), timeline.getEndTime()));
        }
        return totalDuration;
    }

    public static void main(String[] args) {
        // 模拟从数据库查询到的type=0数据
        List<Timeline> type0Records = new ArrayList<>();
        type0Records.add(new Timeline(
            LocalDateTime.parse("2022-07-29T15:30:03.412754"),
            LocalDateTime.parse("2022-07-29T15:57:03.965432"),
            0
        ));
        type0Records.add(new Timeline(
            LocalDateTime.parse("2022-07-29T15:40:03.414000"),
            LocalDateTime.parse("2022-07-29T16:32:03.004323"),
            0
        ));
        type0Records.add(new Timeline(
            LocalDateTime.parse("2022-07-29T16:50:03.643231"),
            LocalDateTime.parse("2022-07-29T17:35:03.234562"),
            0
        ));

        Duration total = calculateTotalNonOverlappingTime(type0Records);
        System.out.println("无重叠总耗时:" + total);
        // 输出结果对应合并后的两段时间总和:1小时2分59秒左右
    }
}

额外说明

  • 如果不想合并连续的时间段(比如前一段的结束时间刚好等于后一段的开始时间),只需要把判断条件里的|| current.getStartTime().isEqual(lastMerged.getEndTime())去掉即可;
  • 这个逻辑同样能处理包含关系的时间段(比如一个大时间段完全包含小时间段),会自动保留最长的结束时间;
  • 实际项目中,你只需要把数据库查询到的type=0数据转换成Timeline列表,传入方法即可。

内容的提问来源于stack exchange,提问作者Berkan Aslan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 20:42:52