如何在Python中检测日期是否连续?

8

我有一个访问表,其中包含一个“日期”字段。每条记录都有随机的日期。我已经编写了一个脚本,将所有记录追加到列表中,然后设置列表以筛选出唯一值:

dateList = []
# cursor search through each record and append all records in the date 
# field to a python list
for row in rows:
   dateList.append(row.getValue("DATE_OBSERVATION").strftime('%m-%d-%Y'))

# Filter unique values to a set
newList = list(set(dateList))

以下是我测试表格返回的结果:

['2010年07月06日', '2010年06月24日', '2010年07月05日', '2010年06月25日']

现在,我已经获得了“DATE_OBSERVATION”字段的唯一值,我想检测:

  • 日期是否单一(即只有一个唯一日期被返回,因为这是每个记录中的日期)
  • 如果日期是连续的日期范围(即所有日期都属于连续的范围)
  • 如果日期是多个日期,但不是连续日期范围内的日期

非常感谢您的任何建议! Mike


1
简短懒散的回答:将它们转换为日期时间对象,对其进行排序,然后使用itertools文档页面中的“pairwise”方法来比较列表中的所有日期与下一个日期是否构成范围;对于单个日期,取第一个日期并检查其余日期是否都在同一天;如果这两种情况都不满足,则它们是不相关的日期。 - Daenyth
1
如果您不选择其他值,请使用select distinct date_observation from mytable order by date_observation desc,并且不要将日期转换为字符串。 - Aprillion
@deathApril:为什么要降序? - jfs
@J.F.Sebastian 嗯,没有什么特别的原因 - 我在问题中看到了'07-06-2010'和'06-24-2010',然后就跳过了其他的例子吧。 - Aprillion
4个回答

19

与其自己编写consecutive函数,您可以使用datetime对象的.toordinal()方法将日期对象转换为整数。序列日期集的最大值和最小值之间的差异比集合长度多一:

from datetime import datetime

date_strs = ['07-06-2010', '06-24-2010', '07-05-2010', '06-25-2010']
# date_strs = ['02-29-2012', '02-28-2012', '03-01-2012']
# date_strs = ['01-01-2000']
dates = [datetime.strptime(d, "%m-%d-%Y") for d in date_strs]

date_ints = set([d.toordinal() for d in dates])

if len(date_ints) == 1:
    print "unique"
elif max(date_ints) - min(date_ints) == len(date_ints) - 1:
    print "consecutive"
else:
    print "not consecutive"

谢谢Michael。这个对我的脚本很有效!感谢您的回复。 - Mike
@Michael Dillon:就像@deathApril的评论中所说的那样,使用select distinct ..会更好。 - jfs
如果我们认为 ['01-01-2000', '01-01-2000', '01-02-2000'] 不是连续的日期,使用这段代码会说这些日期是连续的,你该如何修改你的代码以满足这个要求?我还不知道集合是如何工作的。 - lessthanl0l
@lessthanl0l:设置去重。如果您希望将包含重复项的列表视为非连续列表,则可以测试日期列表的长度是否大于日期集合的长度。 - Michael Dunn

1

另一个版本使用了与我其他答案相同的逻辑。

from datetime import date, timedelta

# Definition 1: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider consecutive
# Definition 2: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider not consecutive

# datelist = [date(2014, 1, 1), date(2014, 1, 3),
#             date(2013, 12, 31), date(2013, 12, 30)]

# datelist = [date(2014, 2, 19), date(2014, 2, 19), date(2014, 2, 20),
#             date(2014, 2, 21), date(2014, 2, 22)]

datelist = [date(2014, 2, 19), date(2014, 2, 21),
            date(2014, 2, 22), date(2014, 2, 20)]

datelist.sort()

previousdate = datelist[0]

for i in range(1, len(datelist)):
    #if (datelist[i] - previousdate).days == 1 or (datelist[i] - previousdate).days == 0:  # for Definition 1
    if (datelist[i] - previousdate).days == 1:    # for Definition 2
        previousdate = datelist[i]
    else:
        previousdate = previousdate + timedelta(days=-1)

if datelist[-1] == previousdate:
    print "dates are consecutive"
else:
    print "dates are not consecutive"

0
使用数据库按升序选择唯一日期:
  • 如果查询返回单个日期,则为第一个情况

  • 否则,找出日期是否连续:

    import datetime
    
    def consecutive(a, b, step=datetime.timedelta(days=1)):
        return (a + step) == b
    

代码布局:

dates = <query database>
if all(consecutive(dates[i], dates[i+1]) for i in xrange(len(dates) - 1)):
   if len(dates) == 1: # unique
      # 1st case: all records have the same date
   else:
      # the dates are a range of dates
else:
   # non-consecutive dates

0
这是我的版本,使用了reduce()函数。
from datetime import date, timedelta


def checked(d1, d2):
    """
    We assume the date list is sorted.
    If d2 & d1 are different by 1, everything up to d2 is consecutive, so d2
    can advance to the next reduction.
    If d2 & d1 are not different by 1, returning d1 - 1 for the next reduction
    will guarantee the result produced by reduce() to be something other than
    the last date in the sorted date list.

    Definition 1: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider consecutive
    Definition 2: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider not consecutive

    """
    #if (d2 - d1).days == 1 or (d2 - d1).days == 0:  # for Definition 1
    if (d2 - d1).days == 1:                          # for Definition 2
        return d2
    else:
        return d1 + timedelta(days=-1)

# datelist = [date(2014, 1, 1), date(2014, 1, 3),
#             date(2013, 12, 31), date(2013, 12, 30)]

# datelist = [date(2014, 2, 19), date(2014, 2, 19), date(2014, 2, 20),
#             date(2014, 2, 21), date(2014, 2, 22)]

datelist = [date(2014, 2, 19), date(2014, 2, 21),
            date(2014, 2, 22), date(2014, 2, 20)]

datelist.sort()

if datelist[-1] == reduce(checked, datelist):
    print "dates are consecutive"
else:
    print "dates are not consecutive"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接