Generate a list of datetimes between an interval

一个人想着一个人 提交于 2019-12-17 02:44:19

问题


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.

Maybe something roughly equivalent to the Dateperiod PHP class.

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


回答1:


Use 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:


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:

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'.

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.




回答3:


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

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:


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).

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.




回答5:


All the solutions given here so far are specific to cases where start < stop, but you can easily adapt them to handle cases where stop < start using the operator module as the following code, adapted from @MartijnPieters's answer, illustrates.

import datetime
import operator

def time_range(start: datetime.datetime, stop, step: datetime.timedelta):
    "Imitate range function for datetimes instead of ints."
    sec = step.total_seconds()
    if sec == 0:
        raise ValueError("step must not be 0 seconds")
    if sec < 0:
        compare = operator.gt
    else:
        compare = operator.lt
    x = start
    while compare(x, stop):
        yield x
        x += step  # immutable


来源:https://stackoverflow.com/questions/10688006/generate-a-list-of-datetimes-between-an-interval

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!