生成间隔之间的日期时间列表

时间:2022-11-15 00:58:16

Given two datetimes (start_date and end_date), I'd like to generate a list of other datetimes between these two dates, the new datetimes being separated by a variable interval. e.g. every 4 days between 2011-10-10 and 2011-12-12 or every 8 hours between now and tomorrow 19p.m.

给定两个日期时间(start_date和end_date),我想在这两个日期之间生成一个其他日期时间的列表,新的日期时间由一个变量间隔分隔。在2011-10至2011-12-12之间每4天,从现在到明天19点每8小时。

Maybe something roughly equivalent to the Dateperiod PHP class.

可能是类似于Dateperiod PHP类的东西。

What would be the most efficient way to accomplish this in Python?

用Python实现这一点最有效的方法是什么?

4 个解决方案

#1


66  

Use datetime.timedelta:

使用datetime.timedelta:

from datetime import date, datetime, timedelta

def perdelta(start, end, delta):
    curr = start
    while curr < end:
        yield curr
        curr += delta

>>> for result in perdelta(date(2011, 10, 10), date(2011, 12, 12), timedelta(days=4)):
...     print result
...
2011-10-10
2011-10-14
2011-10-18
2011-10-22
2011-10-26
2011-10-30
2011-11-03
2011-11-07
2011-11-11
2011-11-15
2011-11-19
2011-11-23
2011-11-27
2011-12-01
2011-12-05
2011-12-09

Works for both dates and datetime objects. Your second example:

适用于日期和日期时间对象。你的第二个例子:

>>> for result in perdelta(datetime.now(),
...         datetime.now().replace(hour=19) + timedelta(days=1),
...         timedelta(hours=8)):
...     print result
... 
2012-05-21 17:25:47.668022
2012-05-22 01:25:47.668022
2012-05-22 09:25:47.668022
2012-05-22 17:25:47.668022

#2


14  

Try this:

试试这个:

from datetime import datetime
from dateutil.relativedelta import relativedelta

def date_range(start_date, end_date, increment, period):
    result = []
    nxt = start_date
    delta = relativedelta(**{period:increment})
    while nxt <= end_date:
        result.append(nxt)
        nxt += delta
    return result

The example in the question, "every 8 hours between now and tomorrow 19:00" would be written like this:

问题中的“从现在到明天19:00每8个小时”的例子是这样写的:

start_date = datetime.now()
end_date = start_date + relativedelta(days=1)
end_date = end_date.replace(hour=19, minute=0, second=0, microsecond=0)
date_range(start_date, end_date, 8, 'hours')    

Notice that the valid values for period are those defined for the relativedelta relative information, namely: 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'microseconds'.

注意,周期的有效值是相对delta相对信息定义的值,即“年”、“月”、“周”、“天”、“小时”、“分钟”、“秒”、“微秒”。

My solution returns a list, as required in the question. If you don't need all the elements at once you can use generators, as in @MartijnPieters answer.

我的解决方案返回一个列表,如问题中所要求的。如果您不需要同时使用所有元素,可以使用生成器,如@MartijnPieters的回答。

#3


5  

I really liked both answers by @Martijn Pieters and @Óscar López. Let me suggest my combined solution between those two answers.

我非常喜欢@Martijn Pieters和@Oscar Lopez的两个答案。让我提出这两个答案之间的组合解。

from datetime import date, datetime, timedelta

def datetime_range(start, end, delta):
    current = start
    if not isinstance(delta, timedelta):
        delta = timedelta(**delta)
    while current < end:
        yield current
        current += delta


start = datetime(2015,1,1)
end = datetime(2015,1,31)

#this unlocks the following interface:
for dt in datetime_range(start, end, {'days': 2, 'hours':12}):
    print dt
    print dt

2015-01-01 00:00:00
2015-01-03 12:00:00
2015-01-06 00:00:00
2015-01-08 12:00:00
2015-01-11 00:00:00
2015-01-13 12:00:00
2015-01-16 00:00:00
2015-01-18 12:00:00
2015-01-21 00:00:00
2015-01-23 12:00:00
2015-01-26 00:00:00
2015-01-28 12:00:00

#4


0  

The solutions suggested here work well for intervals of days, hours, etc. using timedelta, or anything that dateutil.relativedelta supports if you want to rely on third-party libraries. But I wanted to share my solution for the specific case of monthly intervals in the format yyyymm, asked here (but marked as a duplicate of this question).

这里建议的解决方案可以使用timedelta或任何dateutil的方法在几天、几个小时的间隔内正常工作。如果您想要依赖第三方库,相对论三角洲支持。但是我想要分享我的解决方案,以yyyyymm的格式,在这里被问(但是标记为这个问题的副本)。

def iterate_months(start_ym, end_ym):
    for ym in range(int(start_ym), int(end_ym) + 1):
        if ym % 100 > 12 or ym % 100 == 0:
            continue
        yield str(ym)

list(iterate_months('201710', '201803'))

Output:

输出:

['201710', '201711', '201712', '201801', '201802', '201803']

This solution is fairly specific to this particular need for yyyymm formatting (though it comes up frequently in my world, at least) and may not be the most efficient answer with the large number of continues, but has the advantages of being concise, easy to understand, and doesn't involve a number of libraries or date-conversion code.

这个解决方案是相当需要yyyymm特有的格式(尽管它经常出现在我的世界里,至少)和可能不是最有效的回答大量的继续,但具有简洁、易于理解,不涉及大量的库或日期转换代码。

#1


66  

Use datetime.timedelta:

使用datetime.timedelta:

from datetime import date, datetime, timedelta

def perdelta(start, end, delta):
    curr = start
    while curr < end:
        yield curr
        curr += delta

>>> for result in perdelta(date(2011, 10, 10), date(2011, 12, 12), timedelta(days=4)):
...     print result
...
2011-10-10
2011-10-14
2011-10-18
2011-10-22
2011-10-26
2011-10-30
2011-11-03
2011-11-07
2011-11-11
2011-11-15
2011-11-19
2011-11-23
2011-11-27
2011-12-01
2011-12-05
2011-12-09

Works for both dates and datetime objects. Your second example:

适用于日期和日期时间对象。你的第二个例子:

>>> for result in perdelta(datetime.now(),
...         datetime.now().replace(hour=19) + timedelta(days=1),
...         timedelta(hours=8)):
...     print result
... 
2012-05-21 17:25:47.668022
2012-05-22 01:25:47.668022
2012-05-22 09:25:47.668022
2012-05-22 17:25:47.668022

#2


14  

Try this:

试试这个:

from datetime import datetime
from dateutil.relativedelta import relativedelta

def date_range(start_date, end_date, increment, period):
    result = []
    nxt = start_date
    delta = relativedelta(**{period:increment})
    while nxt <= end_date:
        result.append(nxt)
        nxt += delta
    return result

The example in the question, "every 8 hours between now and tomorrow 19:00" would be written like this:

问题中的“从现在到明天19:00每8个小时”的例子是这样写的:

start_date = datetime.now()
end_date = start_date + relativedelta(days=1)
end_date = end_date.replace(hour=19, minute=0, second=0, microsecond=0)
date_range(start_date, end_date, 8, 'hours')    

Notice that the valid values for period are those defined for the relativedelta relative information, namely: 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'microseconds'.

注意,周期的有效值是相对delta相对信息定义的值,即“年”、“月”、“周”、“天”、“小时”、“分钟”、“秒”、“微秒”。

My solution returns a list, as required in the question. If you don't need all the elements at once you can use generators, as in @MartijnPieters answer.

我的解决方案返回一个列表,如问题中所要求的。如果您不需要同时使用所有元素,可以使用生成器,如@MartijnPieters的回答。

#3


5  

I really liked both answers by @Martijn Pieters and @Óscar López. Let me suggest my combined solution between those two answers.

我非常喜欢@Martijn Pieters和@Oscar Lopez的两个答案。让我提出这两个答案之间的组合解。

from datetime import date, datetime, timedelta

def datetime_range(start, end, delta):
    current = start
    if not isinstance(delta, timedelta):
        delta = timedelta(**delta)
    while current < end:
        yield current
        current += delta


start = datetime(2015,1,1)
end = datetime(2015,1,31)

#this unlocks the following interface:
for dt in datetime_range(start, end, {'days': 2, 'hours':12}):
    print dt
    print dt

2015-01-01 00:00:00
2015-01-03 12:00:00
2015-01-06 00:00:00
2015-01-08 12:00:00
2015-01-11 00:00:00
2015-01-13 12:00:00
2015-01-16 00:00:00
2015-01-18 12:00:00
2015-01-21 00:00:00
2015-01-23 12:00:00
2015-01-26 00:00:00
2015-01-28 12:00:00

#4


0  

The solutions suggested here work well for intervals of days, hours, etc. using timedelta, or anything that dateutil.relativedelta supports if you want to rely on third-party libraries. But I wanted to share my solution for the specific case of monthly intervals in the format yyyymm, asked here (but marked as a duplicate of this question).

这里建议的解决方案可以使用timedelta或任何dateutil的方法在几天、几个小时的间隔内正常工作。如果您想要依赖第三方库,相对论三角洲支持。但是我想要分享我的解决方案,以yyyyymm的格式,在这里被问(但是标记为这个问题的副本)。

def iterate_months(start_ym, end_ym):
    for ym in range(int(start_ym), int(end_ym) + 1):
        if ym % 100 > 12 or ym % 100 == 0:
            continue
        yield str(ym)

list(iterate_months('201710', '201803'))

Output:

输出:

['201710', '201711', '201712', '201801', '201802', '201803']

This solution is fairly specific to this particular need for yyyymm formatting (though it comes up frequently in my world, at least) and may not be the most efficient answer with the large number of continues, but has the advantages of being concise, easy to understand, and doesn't involve a number of libraries or date-conversion code.

这个解决方案是相当需要yyyymm特有的格式(尽管它经常出现在我的世界里,至少)和可能不是最有效的回答大量的继续,但具有简洁、易于理解,不涉及大量的库或日期转换代码。