在两个日期之间枚举天数/周数/月数是否有一致的方法?

4
我有两个datetime对象,一个是开始日期,另一个是结束日期。我需要枚举这两个日期之间的天数、周数和月数,包括这两个日期。
理想情况下,结果应该以datetime形式呈现,但任何兼容的形式都可以。星期和月份由对应于一周/月的第一天的日期表示,其中星期的第一天是ISO-8601中的星期一。这意味着结果可能包含早于开始日期的日期。
例如,给定2010-11-28到2010-12-01,结果如下:
天:2010-11-28、2010-11-29、2010-11-30、2010-12-01
周:2010-11-22、2010-11-29
月:2010-11-01、2010-12-01
我知道列出天数本身很简单,但我希望有一个干净而一致的解决方案,使用类似的方法来处理所有三个问题。似乎calendar模块应该有用,但我没有看到一个好的方法来使用它来实现这个目的。

当您从2011-01-31开始迭代月份时会发生什么?您期望收到的下一个日期是什么? - Brent Newey
如果您想知道开始日期晚于结束日期的情况,可以假设开始日期小于等于结束日期;如果您真的想处理它,我希望结果为空。如果您的问题涉及未来的日期,解决方案应该不受当前日期的影响。 - DNS
这是一个关于一致性的问题。2011-01-31加一个月后变成2011-02-28吗?再加一个月后又会变成2011-03-28吗? - Brent Newey
嗯,我不确定那有什么关系;这是关于列出两个日期之间的月份,而不是按一定数量从起始点迭代的问题。 - DNS
我建议您获取第三方日期模块,例如NormalDate或mxDateTime。我已经使用前者多年了(它是一个单独的.py文件),但后者看起来维护得更好。 - martineau
1个回答

4
使用dateutil
import datetime
import dateutil.rrule as drrule
import dateutil.relativedelta as drel
import pprint

def dt2d(date):
    '''
    Convert a datetime.datetime to datetime.date object
    '''
    return datetime.date(date.year,date.month,date.day)

def enumerate_dates(start,end):
    days=map(dt2d,drrule.rrule(drrule.DAILY, dtstart=start, until=end))

    # Find the Monday on or before start
    start_week=start+drel.relativedelta(weekday=drel.MO(-1))
    end_week=end+drel.relativedelta(weekday=drel.MO(-1))
    weeks=map(dt2d,drrule.rrule(drrule.WEEKLY, dtstart=start_week, until=end_week))

    # Find the first day of the month
    start_month=start.replace(day=1)
    end_month=end.replace(day=1)
    months=map(dt2d,drrule.rrule(drrule.MONTHLY, dtstart=start_month, until=end_month))
    return days,weeks,months


if __name__=='__main__':
    days,weeks,months=enumerate_dates(datetime.date(2010,11,28),
                                      datetime.date(2010,12,01))
    print('''\
days: {d}
weeks: {w}
months: {m}'''.format(d=map(str,days),w=map(str,weeks),m=map(str,months)))

产生。
days: ['2010-11-28', '2010-11-29', '2010-11-30', '2010-12-01']
weeks: ['2010-11-22', '2010-11-29']
months: ['2010-11-01', '2010-12-01']

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