计算实际时间天数(时间范围去重)

image.png
举例 1.2-1.5 , 1.4-1.6
去重后就是 1.2 1.3 1.4 1.5 .16 一共5天

阅读 3.6k
3 个回答
function getDays (ranges: readonly (readonly [number, number])[]): number {
  const days = new Set<number>();
  for (const [start, end] of ranges) {
    for (let time = start; end >= time; time += 8.64e7) {
      days.add(time);
    }
  }
  return days.size;
}

getDays([
  [Date.parse("2021-01-02"), Date.parse("2021-01-05")],
  [Date.parse("2021-01-04"), Date.parse("2021-01-06")],
]);

把时间看成数轴,其实这就是两个区间的相对位置;要么有区间重叠,时间就是最小值到最大值的天数;
要么不重叠,各自区间相减的和 就是最后结果

Python version:

# 设一个包含重复和不重复起止日期的列表
# 可知2021-01-02 ~ 2021-01-06 共5天(含头尾)。
# 2021-01-09 到2021-01-12 共4天(含头尾)
# 总天数为9天
date_list = [('2021-01-04','2021-01-06'),('2021-01-02','2021-01-05'),('2021-01-09','2021-01-12')]

# 先转换成日期对象以便比较大小和算术运算
# 并进行排序,保证每一组开始日期都是比下一组要小
date_list = sorted([(datetime.strptime(i,'%Y-%m-%d'),datetime.strptime(j,'%Y-%m-%d')) for i,j in date_list])

# 总天数
length_of_dates = 0

#从第一组日期到倒数第二组日期进行循环
for i in range(len(date_list)-1):
    # 如果当前结束如期比下一个起始日期小,则没有重叠:
    # 完整天数则是当前结束日期-当前开始日期+1天 
    if date_list[i][1] < date_list[i+1][0]:
        length_of_dates += (date_list[i][1] - date_list[i][0]).days +1
        
    # 如果当前结束日期比下一个起始日期大
    # 则只增加当前起始日期到下一个起始日期的天数。
    else:
        length_of_dates += (date_list[i+1][0] - date_list[i][0]).days

# 补上最后一组日期的天数
length_of_dates += (date_list[-1][1] - date_list[-1][0]).days + 1

# 结果
print(length_of_dates) # 9