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

时间:2012-01-28 09:01:23

标签: python date date-range

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

9 个答案:

答案 0 :(得分:139)

  • 确定两个开始日期的最新日期和两个结束日期中最早的日期。
  • 通过减去timedelta来计算它们。
  • 如果delta是正数,那就是重叠的天数。

以下是一个示例计算:

>>> 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 :(得分:7)

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

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

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

与需要1减法,1分钟()和最大()的下一个最佳比较:

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

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

答案 2 :(得分:5)

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

//Get note from a slide
private static String getNotesText(XSLFSlide slide) {

    XSLFNotes mynotes = slide.getNotes();
    for (XSLFShape shape : mynotes) {
        if (shape instanceof XSLFTextShape) {
            XSLFTextShape txShape = (XSLFTextShape) shape;
            for (XSLFTextParagraph xslfParagraph : txShape.getTextParagraphs()) {

                resultBuffer.append(xslfParagraph.getText())
                .append("\n");
            }
        }
    }

    return resultBuffer.toString();
}

private static void createNewPpt(XSLFSlide slide, Dimension pageSize) throws IOException {

    try (XMLSlideShow ppt = new XMLSlideShow()) {

        ppt.setPageSize(pageSize);

        XSLFSlide targetSlide = ppt.createSlide();
        targetSlide.importContent(slide);

        XSLFNotes targetNotes = ppt.getNotesSlide(targetSlide);
        for (XSLFTextShape targetShape : targetNotes.getPlaceholders()) {

            if (targetShape.getTextType() == Placeholder.BODY) {

                targetShape.setText(getNotesText(slide));
                break;
            }
        }


        FileOutputStream out = new FileOutputStream(getNextFileName(RESULT_DIR, charName));
        ppt.write(out);
        out.close();
    }
}

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

答案 3 :(得分:3)

伪代码:

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

答案 4 :(得分:3)

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

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

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

类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]])

答案 5 :(得分:0)

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

答案 6 :(得分:0)

好吧,我的解决方案有点奇怪,因为我的df使用了所有系列-但可以说您有以下几列,其中两列是固定的,即您的“会计年度”。 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)

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

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

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
相关问题