【问题标题】:How to iterate over a timespan after days, hours, weeks and months?如何在数天、数小时、数周和数月之后迭代一个时间跨度?
【发布时间】:2008-09-30 15:35:22
【问题描述】:

如何在数天、数小时、数周或数月之后迭代一个时间跨度?

类似:

for date in foo(from_date, to_date, delta=HOURS):
    print date

其中 foo 是一个函数,返回一个迭代器。我一直在查看日历模块,但它仅适用于特定年份或月份,而不适用于日期之间。

【问题讨论】:

  • 或者,你想要一个上面签名的函数吗?

标签: python datetime


【解决方案1】:

使用 dateutil 及其 rrule 实现,如下所示:

from dateutil import rrule
from datetime import datetime, timedelta

now = datetime.now()
hundredDaysLater = now + timedelta(days=100)

for dt in rrule.rrule(rrule.MONTHLY, dtstart=now, until=hundredDaysLater):
    print dt

输出是

2008-09-30 23:29:54
2008-10-30 23:29:54
2008-11-30 23:29:54
2008-12-30 23:29:54

将 MONTHLY 替换为 YEARLY、MONTHLY、WEEKLY、DAILY、HOURLY、MINUTELY 或 SECONDLY。将 dtstart 和 until 替换为您想要的任何日期时间对象。

此配方的优势在于适用于所有情况,包括每月一次。我能发现的唯一警告是,如果您传递一个并非所有月份都存在的天数,它会跳过那些月份。

【讨论】:

  • niemeyer.net/python-dateutil 解释了如何使用它来检索“一个月中指定日期的日期,除非它超出月末,在这种情况下它将是本月的最后一天” .这修复了您列出的一个警告。例如,now = datetime(2010, 8, 31, 1, 1, 1);对于 rrule.rrule(rrule.MONTHLY, dtstart=now, bymonthday=(31, -1), count=6) 中的 dt:打印 dt
【解决方案2】:

我认为 Python 库中没有方法,但您可以使用 datetime 模块轻松地自己创建一个:

from datetime import date, datetime, timedelta

def datespan(startDate, endDate, delta=timedelta(days=1)):
    currentDate = startDate
    while currentDate < endDate:
        yield currentDate
        currentDate += delta

那么你可以这样使用它:

>>> for day in datespan(date(2007, 3, 30), date(2007, 4, 3), 
>>>                     delta=timedelta(days=1)):
>>>     print day
2007-03-30
2007-03-31
2007-04-01
2007-04-02

或者,如果您希望缩小增量:

>>> for timestamp in datespan(datetime(2007, 3, 30, 15, 30), 
>>>                           datetime(2007, 3, 30, 18, 35), 
>>>                           delta=timedelta(hours=1)):
>>>     print timestamp
2007-03-30 15:30:00
2007-03-30 16:30:00
2007-03-30 17:30:00
2007-03-30 18:30:00

【讨论】:

  • 您不能指定一个月的时间增量
  • 要指定一个月的增量,您可以使用 relativedelta:from dateutil.relativedelta import relativedelta。然后你让for month in datespan(start_date, end_date, delta=relativedelta(months=1)).
【解决方案3】:

对于几个月的迭代,您需要不同的配方,因为 timedeltas 不能表示“一个月”。

from datetime import date

def jump_by_month(start_date, end_date, month_step=1):
    current_date = start_date
    while current_date < end_date:
        yield current_date
        carry, new_month = divmod(current_date.month - 1 + month_step, 12)
        new_month += 1
        current_date = current_date.replace(year=current_date.year + carry,
                                            month=new_month)

(注意:您必须从月份中减去 1 才能进行取模运算,然后将其添加回 new_month,因为 datetime.dates 中的月份从 1 开始。)

【讨论】:

  • 两件事:-如果您将 start_date 的日期设置为每个月都不存在的数字,则此代码引发ValueError - 可能正是因为这个原因,没有月份时间增量;我建议使用timedelta(days=30) 进行近似。
  • 好收获。但有时,近似值还不够好(我的“支付房租”提醒必须在每个月的第一天 6:30 进行)。可以修改配方——可能有一些额外的状态——以提供健全的功能,不管是什么。
  • 您也可能会在 2 月 29 日遇到逐年迭代的问题。
【解决方案4】:

我使用 pandas 和 datetime 库实现了这一点,如下所示。这对我来说更方便。

import pandas as pd
from datetime import datetime


DATE_TIME_FORMAT = '%Y-%m-%d %H:%M:%S'

start_datetime = datetime.strptime('2018-05-18 00:00:00', DATE_TIME_FORMAT)
end_datetime = datetime.strptime('2018-05-23 13:00:00', DATE_TIME_FORMAT)

timedelta_index = pd.date_range(start=start_datetime, end=end_datetime, freq='H').to_series()
for index, value in timedelta_index.iteritems():
    dt = index.to_pydatetime()
    print(dt)

【讨论】:

  • 欢迎来到 Stack Overflow!一般来说,如果答案包含对代码的用途的解释,以及为什么在不介绍其他人的情况下解决了问题,那么答案会更有帮助。
  • 很好的答案。这正是我想要的。我刚刚将 H 替换为 m。 ;)
  • 你能解释一下最后一次迭代是如何工作的吗?例如value 不再使用,我不明白为什么索引会产生输出。
【解决方案5】:

月迭代法:

def months_between(date_start, date_end):
    months = []

    # Make sure start_date is smaller than end_date
    if date_start > date_end:
        tmp = date_start
        date_start = date_end
        date_end = tmp

    tmp_date = date_start
    while tmp_date.month <= date_end.month or tmp_date.year < date_end.year:
        months.append(tmp_date)  # Here you could do for example: months.append(datetime.datetime.strftime(tmp_date, "%b '%y"))

        if tmp_date.month == 12: # New year
            tmp_date = datetime.date(tmp_date.year + 1, 1, 1)
        else:
            tmp_date = datetime.date(tmp_date.year, tmp_date.month + 1, 1)
    return months

更多代码,但它可以很好地处理长时间检查给定日期是否有序...

【讨论】:

  • 不需要使用'tmp'来交换两个变量;您可以一步完成:“date_start, date_end = date_end, date_start”
【解决方案6】:

这个库提供了一个方便的日历工具:mxDateTime,应该够了:)

【讨论】:

    【解决方案7】:

    您应该修改此行以使其正常工作:

    current_date = current_date.replace(year=current_date.year + carry,month=new_month,day=1)

    ;)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-24
      • 2019-09-10
      • 2021-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多