有效的日期范围重叠计算?

2025-03-13 08:49:00
admin
原创
54
摘要:问题描述:我有两个日期范围,每个范围由开始日期和结束日期决定(显然,datetime.date实例)。这两个范围可以重叠也可以不重叠。我需要重叠的天数。当然,我可以用两个范围内的所有日期预先填充两个集合,然后执行集合交集,但这可能效率低下……除了使用涵盖所有情况的长部分的另一个解决方案之外,还有其他更好的方法...

问题描述:

我有两个日期范围,每个范围由开始日期和结束日期决定(显然,datetime.date实例)。这两个范围可以重叠也可以不重叠。我需要重叠的天数。当然,我可以用两个范围内的所有日期预先填充两个集合,然后执行集合交集,但这可能效率低下……除了使用涵盖所有情况的长部分的另一个解决方案之外,还有其他更好的方法ifelif


解决方案 1:

  • 确定两个开始日期中最晚的日期和两个结束日期中最早的日期。

  • 通过减去它们来计算时间增量。

  • 如果增量为正,那么这就是重叠的天数。

以下是一个计算示例:

>>> from datetime import datetime
>>> from collections import namedtuple
>>> Range = namedtuple('Range', ['start', 'end'])

>>> r1 = Range(start=datetime(2012, 1, 15), end=datetime(2012, 5, 10))
>>> r2 = Range(start=datetime(2012, 3, 20), end=datetime(2012, 9, 15))
>>> latest_start = max(r1.start, r2.start)
>>> earliest_end = min(r1.end, r2.end)
>>> delta = (earliest_end - latest_start).days + 1
>>> overlap = max(0, delta)
>>> overlap
52

解决方案 2:

函数调用比算术运算更昂贵。

最快的方法是进行 2 次减法和 1 次 min():

min(r1.end - r2.start, r2.end - r1.start).days + 1

与下一个最佳值相比,它需要 1 次减法、1 次 min() 和一次 max():

(min(r1.end, r2.end) - max(r1.start, r2.start)).days + 1

当然,对于这两种表达式,您仍然需要检查是否存在正重叠。

解决方案 3:

我实现了一个 TimeRange 类,如下所示。

get_overlapped_range 首先通过简单条件否定所有不重叠的选项,然后考虑所有可能的选项来计算重叠范围。

要获得天数,您需要获取 get_overlapped_range 返回的 TimeRange 值,然后将持续时间除以 606024。

class TimeRange(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end
        self.duration = self.end - self.start

    def is_overlapped(self, time_range):
        if max(self.start, time_range.start) < min(self.end, time_range.end):
            return True
        else:
            return False

    def get_overlapped_range(self, time_range):
        if not self.is_overlapped(time_range):
            return

        if time_range.start >= self.start:
            if self.end >= time_range.end:
                return TimeRange(time_range.start, time_range.end)
            else:
                return TimeRange(time_range.start, self.end)
        elif time_range.start < self.start:
            if time_range.end >= self.end:
                return TimeRange(self.start, self.end)
            else:
                return TimeRange(self.start, time_range.end)

    def __repr__(self):
        return '{0} ------> {1}'.format(*[time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(d))
                                          for d in [self.start, self.end]])

解决方案 4:

您可以使用 datetimerange 包:https://pypi.org/project/DateTimeRange/

from datetimerange import DateTimeRange
time_range1 = DateTimeRange("2015-01-01T00:00:00+0900", "2015-01-04T00:20:00+0900") 
time_range2 = DateTimeRange("2015-01-01T00:00:10+0900", "2015-01-04T00:20:00+0900")
tem3 = time_range1.intersection(time_range2)
if tem3.NOT_A_TIME_STR == 'NaT':  # No overlap
    S_Time = 0
else: # Output the overlap seconds
    S_Time = tem3.timedelta.total_seconds()

DateTimeRange() 中的 "2015-01-01T00:00:00+0900" 也可以是日期时间格式,如 Timestamp('2017-08-30 20:36:25')。

解决方案 5:

基于@Raymond Hettinger 的解决方案,从 python 3.6 开始您现在可以NamedTupletyping模块中使用该解决方案。

from datetime import datetime
from typing import NamedTuple

class Range(NamedTuple):
    start: datetime
    end: datetime
>>> r1 = Range(start=datetime(2012, 1, 15), end=datetime(2012, 5, 10))
>>> r2 = Range(start=datetime(2012, 3, 20), end=datetime(2012, 9, 15))
>>> latest_start = max(r1.start, r2.start)
>>> earliest_end = min(r1.end, r2.end)
>>> delta = (earliest_end - latest_start).days + 1
>>> overlap = max(0, delta)
>>> overlap
52

解决方案 6:

伪代码:

1 + max( -1, (min( a.dateEnd, b.dateEnd) - max( a.dateStart, b.dateStart)).days )

解决方案 7:

def get_overlap(r1,r2):
    latest_start=max(r1[0],r2[0])
    earliest_end=min(r1[1],r2[1])
    delta=(earliest_end-latest_start).days
    if delta>0:
        return delta+1
    else:
        return 0

解决方案 8:

好吧,我的解决方案有点奇怪,因为我的数据表使用了所有系列 - 但假设您有以下几列,其中 2 列是固定的,即您的“财政年度”。PoP 是“绩效期”,这是您的可变数据:

df['PoP_Start']
df['PoP_End']
df['FY19_Start'] = '10/1/2018'
df['FY19_End'] = '09/30/2019'

假设所有数据都采用日期时间格式,即 -

df['FY19_Start'] = pd.to_datetime(df['FY19_Start'])
df['FY19_End'] = pd.to_datetime(df['FY19_End'])

尝试以下公式来计算重叠的天数:

min1 = np.minimum(df['POP_End'], df['FY19_End'])
max2 = np.maximum(df['POP_Start'], df['FY19_Start'])

df['Overlap_2019'] = (min1 - max2) / np.timedelta64(1, 'D')
df['Overlap_2019'] = np.maximum(df['Overlap_2019']+1,0)

解决方案 9:

另一种解决方案是先按升序对源数组进行排序,然后循环并比较日期,如下所示:

date_ranges = sorted(
    date_ranges,
    key=lambda item: item['start_date'],
)
for i in range(len(date_ranges)-1):
    if date_ranges[i]['end_date'] > date_ranges[i+1]['start_date']:
        raise Exception('Overlap'})

解决方案 10:

我在我的一个应用程序中使用的操作是创建一个日期差异列表,并查询建议保存的日期范围内的日期差异。

如果所有旧日期范围的日期差异值(以为单位)列表为:

dateDiffOld = [2920753, 2920746, 2920698, 2920387, 2920360, 2920296]

对于新的日期范围,其结果为:

dateDiffNew = 2920360

然后使用:

if dateDiffNew in dateDiffOld:
    # do something

我寻求具有类似要求的可能解决方案,结果在 SO 上找到了各种答案,但不知何故(对于我的用例而言),我发现这个方法有效(到目前为止,有大量记录)。还没有机会在其他地方使用它。

注意:我描述的即时应用程序是使用Django创建的。

注2:请各位成员就此方法可能存在的任何缺陷(我目前还没有遇到过)提出建议。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2560  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1552  
  IPD(Integrated Product Development)流程作为一种先进的产品开发管理模式,在众多企业中得到了广泛应用。其中,技术评审与决策评审是IPD流程中至关重要的环节,它们既有明显的区别,又存在紧密的协同关系。深入理解这两者的区别与协同,对于企业有效实施IPD流程,提升产品开发效率与质量具有重要意义...
IPD管理流程   1  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、ClickUp、Freshdesk、GanttPRO、Planview、Smartsheet、Asana、Nifty、HubPlanner、Teamwork。在当今快速变化的商业环境中,项目管理软件已成为企业提升效率、优化资源分配和确保项目按时交付的关键工具。然而...
项目管理系统   2  
  建设工程项目质量关乎社会公众的生命财产安全,也影响着企业的声誉和可持续发展。高质量的建设工程不仅能为使用者提供舒适、安全的环境,还能提升城市形象,推动经济的健康发展。在实际的项目操作中,诸多因素会对工程质量产生影响,从规划设计到施工建设,再到后期的验收维护,每一个环节都至关重要。因此,探寻并运用有效的方法来提升建设工程...
工程项目管理制度   3  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用