Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python中高效的日期范围重叠计算?_Python_Date_Date Range - Fatal编程技术网

python中高效的日期范围重叠计算?

python中高效的日期范围重叠计算?,python,date,date-range,Python,Date,Date Range,我有两个日期范围,其中每个范围由开始日期和结束日期决定(显然是datetime.date()实例)。这两个范围可以重叠,也可以不重叠。我需要重叠的天数。当然,我可以用两个范围内的所有日期预先填充两个集合,并执行集合交集,但这可能是低效的……除了使用涵盖所有情况的长if elif部分的另一个解决方案之外,还有更好的方法吗? 确定两个开始日期中的最晚日期和两个结束日期中的最早日期 通过减去时间差来计算时间差 如果增量为正值,则表示重叠天数 以下是一个计算示例: >>> from

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

  • 确定两个开始日期中的最晚日期和两个结束日期中的最早日期
  • 通过减去时间差来计算时间差
  • 如果增量为正值,则表示重叠天数
以下是一个计算示例:

>>> 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
伪代码:

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

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

最快的方法是2次减法和1分钟()

与需要1个减法、1 min()和一个max()的次优相比:


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

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

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
get_overlapped_range首先通过一个简单条件否定所有非重叠选项,然后通过考虑所有可能的选项来计算重叠范围

要获取天数,您需要获取从get_overlapped_range返回的时间范围值,并将持续时间除以60*60*24

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]])
类时间范围(对象):
定义初始(自我、开始、结束):
self.start=开始
self.end=结束
self.duration=self.end-self.start
def重叠(自身、时间范围):
如果最大值(self.start,time\u range.start)=self.start:
如果self.end>=time\u range.end:
返回时间范围(time\u range.start、time\u range.end)
其他:
返回时间范围(time\u range.start、self.end)
elif time_range.start=self.end:
返回时间范围(self.start、self.end)
其他:
返回时间范围(self.start、time\u range.end)
定义报告(自我):
返回“{0}------>{1}”。格式(*[time.strftime(“%Y-%m-%d%H:%m:%S”,time.localtime(d))
对于[self.start,self.end]]中的d)

好的,我的解决方案有点不可靠,因为我的df使用所有系列-但假设您有以下列,其中2列是固定的,这是您的“会计年度”。PoP是“绩效期间”,是您的可变数据:

df['PoP_Start']
df['PoP_End']
df['FY19_Start'] = '10/1/2018'
df['FY19_End'] = '09/30/2019'
假设所有数据都是datetime格式,即-

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)

您可以使用datetimerange软件包:


DateTimeRange()中的“2015-01-01T00:00:00+0900”也可以是datetime格式,如时间戳(“2017-08-30 20:36:25”)。

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

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'})

+1非常好的解决方案。尽管如此,对于完全包含在另一个表中的日期,这并不十分有效。为了简化整数:范围(1,4)和范围(2,3)返回1@darkless实际上,它返回2,这是正确的。尝试这些输入
r1=Range(开始=日期时间(2012,1,1),结束=日期时间(2012,1,4));r2=范围(开始=日期时间(2012,1,2),结束=日期时间(2012,1,3))
。我想你在重叠计算中遗漏了
+1
(因为两端的间隔是闭合的,所以这是必要的)。哦,你完全正确,我似乎遗漏了这一点。谢谢:)如果你想计算2次而不是2次日期,怎么办@RaymondHettingerIf使用datetime对象的时间可以代替.days write.total_seconds()。此方法不会始终返回正确答案。e、 g.
Range=namedtuple('Range',['start','end'])r1=Range(start=datetime(2016,6,15),end=datetime(2016,6,15))r2=Range(start=datetime(2016,6,11),end=datetime(2016,6,18))打印分钟数(r1.end-r2.start,r2.end-r1.start).days+1
将在支持打印1的位置打印4。使用第一个公式,我得到一个不明确的序列错误。我需要一个特定的库吗?@L.Guthardt同意,但是这个解决方案是有组织的,并且具有更多的功能OK…功能越多越好,但实际上在StackOverflow上,答案应该正好符合OP的特定需要。所以不多也不少。:)谢谢,刚刚查看了
DateTimeRange
软件包的文档,它们似乎支持
is\u intersection
,它本机返回一个布尔值(True或False),具体取决于两个日期范围之间是否存在交集。例如:
time\u range1.is\u intersection(time\u range2)
将返回
True
如果它们相交,否则
False
这是否回答了您的问题?
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)
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()
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'})