【问题标题】:overlapping dates between two date ranges in pythonpython中两个日期范围之间的重叠日期
【发布时间】:2016-06-16 19:44:27
【问题描述】:

我正在寻找两个日期范围之间的重叠日期,如下所示:

range1 = start(2016-06-01) end (2016-06-20)
range2 = start(2016-06-10) end (2016-06-13)

这里的结果是 4 个日期 (2016-06-10,2016-06-11,2016-06-12,2016-06-13)。 另一个例子:

 range1 = start(2016-06-01) end (2016-06-20) range2 = start(2016-06-18)
 end (2016-06-25)

这里的结果是 3 个日期 (2016-06-18,2016-06-19,2016-06-20)。 如果没有日期重叠,则结果为 0 个日期。

我发现this 的帖子有助于确定重叠日期的数量,但我想知道是否可以在不使用长 if/else 语句的情况下获得实际日期?

提前致谢!

【问题讨论】:

    标签: python date date-range


    【解决方案1】:

    我建议在两个范围内生成日期,然后选择两个集合之间的交集。这样做的片段可能如下所示:

    from datetime import date, timedelta
    
    
    def f(d1, d2):
        delta = d2 - d1
        return set([d1 + timedelta(days=i) for i in range(delta.days + 1)])
    
    range1 = [date(2016, 6, 1), date(2016, 6, 20)]
    range2 = [date(2016, 6, 10), date(2016, 6, 13)]
    
    print f(*range1) & f(*range2)
    

    出于性能目的,您还可以在生成给定范围内的日期时将d1 + timedelta(days=i) 转换为str

    【讨论】:

    • 感谢卡达杰!只是想知道性能部分,为什么转换为字符串会提高性能?
    • 因为在您要生成大量日期的情况下,您更愿意存储不太复杂的数据结构,例如字符串,在这种情况下,不会导致信息丢失.
    【解决方案2】:

    当您还没有使用 Python3 并因此无法利用内存高效的 range 对象时,您可以创建一个命名元组,如 the answer you link to 所示(否则您也可以使用新的 range对象)。 从那里,您需要做的就是在重叠的日期范围上使用datetime.date.fromordinal

    >>> from datetime import date
    >>> from collections import namedtuple
    >>> Range = namedtuple('Range', ['start', 'end'])
    >>> r1 = Range(start=date(2016, 1, 1), end=date(2016, 2, 5))
    >>> r2 = Range(start=date(2016, 1, 28), end=date(2016, 2, 28))
    >>> latest_start = max(r1.start, r2.start)
    >>> earliest_end = min(r1.end, r2.end)
    >>> overlap = (earliest_end - latest_start).days + 1
    >>> overlapping_dates = [] # default
    >>> if overlap > 0:
    ...     overlapping_dates = range(latest_start.toordinal(), earliest_end.toordinal() + 1) # as numbers
    ...     overlapping_dates = [ date.fromordinal(x) for x in overlapping_dates ] # back to datetime.date objects
    ...
    >>> overlapping_dates
    [datetime.date(2016, 1, 28),
     datetime.date(2016, 1, 29),
     datetime.date(2016, 1, 30),
     datetime.date(2016, 1, 31),
     datetime.date(2016, 2, 1),
     datetime.date(2016, 2, 2),
     datetime.date(2016, 2, 3),
     datetime.date(2016, 2, 4),
     datetime.date(2016, 2, 5)]
    

    使用set 的方法也可以(其中一种方法在此答案的编辑历史记录中),但通常效率较低,因为它必须在内存中有 all 日期,即使是那些不在路口。

    【讨论】:

      【解决方案3】:

      我最近为此写了一个小函数,它返回是否有重叠,然后返回从到范围

      def date_overlap(start1, end1, start2, end2):
          overlaps = start1 <= end2 and end1 >= start2
          if not overlaps:
              return False, None, None
          return True, max(start1, start2), min(end1, end2)
      

      显然,输出格式可以适应任何需要。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-19
        • 2017-06-08
        • 2023-03-30
        • 2018-03-03
        • 1970-01-01
        • 2023-01-19
        • 2020-06-21
        • 1970-01-01
        相关资源
        最近更新 更多