获取时间段内所有日期的Pythonic方法

Pythonic way to get all dates within time period

必须在下面的伪代码中更改哪些特定语法才能使 getDatesList(startDate,endDate) 函数 return 每个有效日期的列表,包括任意 startDateendDate 值?

生成的函数应尽可能以最 Pythonic 的方式处理所有日期计算,从而最大限度地减少混入错误的可能性,因为此代码是随着时间的推移进行管理的。这包括您在下面的示例中看到的闰日,但它还应该包括其他内容,例如无需告知即可自动知道任何月份的天数。

伪代码:

from datetime import date

def getDatesList(startDate,endDate):  
  startDateParts = startDate.split('-')
  yearNum = int(startDateParts[0])
  monthNum = int(startDateParts[1])
  dayNum = int(startDateParts[2])
  startDateObj = date(yearNum,monthNum,dayNum)
  endDateParts = endDate.split('-')
  endYearNum = int(endDateParts[0])
  endMonthNum = int(endDateParts[1])
  endDayNum = int(endDateParts[2])
  endDateObj = date(endYearNum,endMonthNum,endDayNum)
  datesList = []  
  dateObj = date(yearNum,monthNum,dayNum)
  while dateObj<endDateObj:
    datesList.append(dateObj)
    dateObj+=1day
  return datesList

listOfDates = getDatesList('2020-02-27','2020-03-02')
for eachDate in listOfDates:
  print(eachDate)

运行上述代码的结果应该是开始日期和结束日期之间的所有日期的列表,对于上述示例输入,它是:

2020-02-27
2020-02-28
2020-02-29
2020-03-02
2020-03-03

注意上面结果中的闰日 2020-02-29

但是,如果给定任意两个任意日期作为输入,例如 '1986-02-11''2018-09-27'

,结果函数应该 运行 同样干净

您可以使用 timedelta 执行此操作,这是代码片段

from datetime import datetime, timedelta

def date_range(start, end):
    start_date = datetime.strptime(start, '%Y-%m-%d').date()
    end_date = datetime.strptime(end, '%Y-%m-%d').date()
    delta = end_date - start_date 
    days = [start_date + timedelta(days=i) for i in range(delta.days + 1)]
    return list(map(lambda n: n.strftime("%Y-%m-%d"), days))


print(date_range('2020-02-27', '2020-03-02'))

这是最pythonic的做法,如果有更好的做法请指正:

from datetime import datetime, timedelta
def get_dates_list(start_date, end_date):
        return [(datetime.strptime(start_date, '%Y-%m-%d').date() + timedelta(days = count)).strftime("%Y-%m-%d") for count in range((datetime.strptime(end_date, '%Y-%m-%d').date() - datetime.strptime(start_date, '%Y-%m-%d').date()).days + 2)]

关键是使用 datetime 和 timedelta 对象为您进行日期解析、格式化和算术——就像上面的两个答案一样。 ...这就是为什么存在这些模块并使约会变得相对容易的原因!

所以第一个答案的更多 pythonic 版本,使用像第二个答案一样的列表理解(我会说它更 pythonic,并且不会创建中间列表),但不会全部压缩成一行(这不是那么 pythonic 并且很难理解 - 虽然它很简洁!),所以它更容易理解正在发生的事情:-):

from datetime import datetime, timedelta

def date_range(start, end):
    start_date = datetime.strptime(start, '%Y-%m-%d').date()
    end_date = datetime.strptime(end, '%Y-%m-%d').date()
    delta = end_date - start_date 
    dates = [
        (start_date + timedelta(days=d)).strftime('%Y-%m-%d')
        for d in range(delta.days + 2)
    ]

    return dates


print(date_range('2020-02-27', '2020-03-02'))

我会用发电机来做这个:

from datetime import timedelta

def get_dates_in_range(start_date, end_date):
    curr = start_date
    while curr < end_date:
        yield curr
        curr += timedelta(days=1)

start_dateend_date 被假定为 date 对象。如果您有字符串,那么调用者应该使用 strptime() 将它们解析为日期。