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 continue
s, 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 continue
s, but has the advantages of being concise, easy to understand, and doesn't involve a number of libraries or date-conversion code.
这个解决方案是相当需要yyyymm特有的格式(尽管它经常出现在我的世界里,至少)和可能不是最有效的回答大量的继续,但具有简洁、易于理解,不涉及大量的库或日期转换代码。