【问题标题】:How to identify missing days from a list of start and end dates?如何从开始和结束日期列表中识别缺失的日期?
【发布时间】:2017-04-19 04:19:25
【问题描述】:

如何从(start_date, end_date) 元组列表中识别缺失的日期?

例如,如何识别以下列表中的缺失日期:

dates = [('2011-01-01', '2011-01-14'), ('2011-01-15','2011-01-31'), 
         ('2011-02-01', '2011-02-14'), ('2011-03-01', '2011-03-14'), 
         ('2011-03-16', '2011-03-31')]

以上示例缺少以下日期:

  • 2011-02-152011-02-28
  • 2011-03-15

如何从开始和结束日期元组列表中识别所有缺失的日期?

【问题讨论】:

  • 添加相同月份的天数并与实际需要的天数进行比较。
  • 您希望输出的效果如何?
  • @timgeb 理想情况下作为缺失日期列表
  • @Dave 不够精确,需要嵌套列表还是平面列表?
  • @timgeb 一个平面列表将是完美的

标签: python date datetime date-range


【解决方案1】:

更面向对象的解决方案:

from functools import total_ordering
from datetime import timedelta, datetime


@total_ordering
class DateRange(object):
    def __init__(self, start, end):
        assert start <= end
        self.start = start
        self.end = end

    def __contains__(self, other):
        return self.start <= other and self.end >= other

    def __lt__(self, other):
        if self.start == other.start:
            return self.end < other.end
        return self.start < other.start

    def __eq__(self, other):
        return self.start == other.start and self.end == other.end

    def __str__(self):
        return '<%s, %s>' % (self.start.strftime('%Y-%m-%d'), self.end.strftime('%Y-%m-%d'))

    def __iter__(self):
        class DateIterator(object):
            def __init__(self, start, end):
                self.current = start
                self.end = end

            def next(self):
                if self.current > self.end:
                    raise StopIteration()
                self.current += timedelta(days=1)
                return self.current

        return DateIterator(self.start, self.end)

    __repr__ = __str__

dates = [('2011-01-01', '2011-01-14'), ('2011-01-15','2011-01-31'), ('2011-02-01','2011-02-14'), ('2011-03-01','2011-03-14'), ('2011-03-16','2011-03-31')]
dates = [DateRange(datetime.strptime(start, '%Y-%m-%d'), datetime.strptime(end, '%Y-%m-%d')) for start, end in dates]
dates = sorted(dates)

missing = []

previous = None
for date_range in dates:
    if previous is not None and previous < date_range.start:
        missing.append(DateRange(previous, date_range.start + timedelta(days=-1)))

    previous = date_range.end + timedelta(days=1)

print missing

【讨论】:

    【解决方案2】:

    有点冗长,但你明白了

    编辑:稍微清理一下

    from datetime import date, timedelta
    
    dates = [('2011-01-01', '2011-01-14'), ('2011-01-15','2011-01-31'), 
             ('2011-02-01', '2011-02-14'), ('2011-03-01', '2011-03-14'), 
             ('2011-03-16', '2011-03-31')]
    
    def d_range(d1,d2):
        delta = d2 - d1 #assumes second date is always after first
        return [d1 + timedelta(days=i) for i in range(delta.days + 1)]
    
    my_days = []
    
    #calc the date range between each tuple
    for d in dates:
    
        d1 = datetime.strptime(d[0],'%Y-%m-%d')
        d2 = datetime.strptime(d[1],'%Y-%m-%d')
    
        my_days.extend(d_range(d1,d2))
    
    
    #now do the same for the max and min dates
    my_range = d_range(min(my_days), max(my_days))
    
    
    missing_dates = set(my_range).difference(set(my_days))
    

    为了解决您的评论:

    missing_dates_list = list(missing_dates)
    

    或回到原来的格式:

    missing_dates_str =  [datetime.strftime(date, '%Y-%m-%d') for date in missing_dates]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-13
      • 2022-01-23
      • 2023-03-17
      • 2012-08-19
      • 2018-11-03
      • 1970-01-01
      相关资源
      最近更新 更多