【问题标题】:How to create a date range until some date inclusive with python dateutils?python - 如何使用python dateutils创建一个日期范围,直到包含某个日期?
【发布时间】:2016-01-22 14:29:14
【问题描述】:

我正在尝试获取给定范围内的月份列表。具体来说,给定2015-12-31 - 2016-01-01的范围,我想得到2015-12和2016-01的列表。

我正在使用 dateutil 的 rrule,但 until 参数并没有真正帮助,因为它似乎正在寻找完整的月份。

例如:

from dateutil.relativedelta import relativedelta
from dateutil.rrule import rrule, MONTHLY

list(rrule(MONTHLY, dtstart=datetime(2015, 12, 31), until=datetime(2016,01,01)))

这只会返回[datetime.datetime(2015, 12, 31, 0, 0)],而不是[datetime.datetime(2015, 12, 31, 0, 0), datetime.datetime(2016, 01, 01, 0, 0)]

同样,我希望 12 月的任何开始日和 1 月的任何结束日都具有相同的输出。也就是说,我只关心月份是2015-12 和2016-01。白天部分对我来说并不重要,但我每月只需要一个 datetime(这些输入最多 2 个,day 组件的值可以是任意值)。

是否有一个简单的解决方案,还是我必须每天增加并建立自己的月份?

【问题讨论】:

    标签: python date datetime python-dateutil


    【解决方案1】:

    您的list(rrule(MONTHLY, dtstart=datetime(2015, 12, 31), until=datetime(2016,01,01))) 没有返回 1 月的原因是因为在 12 月 31 日和 1 月 1 日之间没有一个月(基于 MONTHLY 参数)。

    由于您不需要为此使用日期组件,因此我将执行一些日期操作:

    def date_list(start, end):
        start = datetime.date(start.year, start.month, 1)
        end = datetime.date(end.year, end.month, 1)
        dates = [dt for dt in rrule(MONTHLY, dtstart=start, until=end)]
        return dates
    

    它的作用是接受任何开始和结束日期,然后将这两个日期重置为当月的第一天。这可确保存在整整一个月。它将返回一个日期列表,每个日期都是本月的第一天。

    例如,您的输入

    >>> print date_list(datetime.date(2015,12,28), datetime.date(2016,1,1))
    [datetime.datetime(2015, 12, 1, 0, 0), datetime.datetime(2016, 1, 1, 0, 0)]
    

    同月:

    >>> print date_list(datetime.date(2015,12,28), datetime.date(2015,12,31))
    [datetime.datetime(2015, 12, 1, 0, 0)]
    

    范围无效(开始前结束):

    >>> print date_list(datetime.date(2015,12,28), datetime.date(2015,11,30))
    []
    

    射程更长:

    >>> print date_list(datetime.date(2015,12,28), datetime.date(2016,8,3))
    [datetime.datetime(2015, 12, 1, 0, 0), 
    datetime.datetime(2016, 1, 1, 0, 0), 
    datetime.datetime(2016, 2, 1, 0, 0), 
    datetime.datetime(2016, 3, 1, 0, 0), 
    datetime.datetime(2016, 4, 1, 0, 0), 
    datetime.datetime(2016, 5, 1, 0, 0), 
    datetime.datetime(2016, 6, 1, 0, 0), 
    datetime.datetime(2016, 7, 1, 0, 0), 
    datetime.datetime(2016, 8, 1, 0, 0)]
    

    【讨论】:

    • 好答案。不过,[dt for dt in rrule(...)] 不是有点冗长吗list(rrule(...)) 就足够了。
    【解决方案2】:

    我已经使用集合完成了:

    months = set()
    
    for dt in rrule(DAILY, dtstart=start_date, until=end_date):
        months.add(dt.strftime('%Y-%m-.*'))
    

    【讨论】:

      【解决方案3】:

      我认为您将不得不执行某种迭代。例如,使用deltas,下面的代码就可以了:

      import datetime
      
      start = datetime.datetime(2015, 12, 31)
      stop = datetime.datetime(2016, 1, 8)
      
      delta = stop - start
      
      answer = [start+datetime.timedelta(days=idx) for idx in range(delta.days+1)]
      print(answer)
      

      输出

      [datetime.datetime(2015, 12, 31, 0, 0),
       datetime.datetime(2016, 1, 1, 0, 0),
       datetime.datetime(2016, 1, 2, 0, 0),
       datetime.datetime(2016, 1, 3, 0, 0),
       datetime.datetime(2016, 1, 4, 0, 0),
       datetime.datetime(2016, 1, 5, 0, 0),
       datetime.datetime(2016, 1, 6, 0, 0),
       datetime.datetime(2016, 1, 7, 0, 0),
       datetime.datetime(2016, 1, 8, 0, 0)]
      

      【讨论】:

        【解决方案4】:

        只需使用月份的差异作为计数:

        start = datetime(2015, 12, 31)
        end = datetime(2016,01,01)
        diff_month = lambda e, s: (e.year - s.year)*12 + e.month - s.month
        list(rrule(MONTHLY, count=diff_month(end,start)+1, dtstart=start))
        

        【讨论】:

        • OP 想要一份月份列表
        • OP 只关心年月,但不只要求它们(尽管这很容易提取)。这将返回 DateTime 对象中正确的年月列表。通过将日期设置为相同,接受的答案也是如此。
        • 对不起,我误读了您的解决方案,我认为它只是给出月份的计数,而不是月份的列表。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-02
        • 2019-08-13
        • 1970-01-01
        相关资源
        最近更新 更多