2012-05-21 12 views
42

Dato due datatime (start_date e end_date), mi piacerebbe generare un elenco di altri datetimes tra queste due date, i nuovi datetimes separati da un intervallo variabile. per esempio. ogni 4 giorni tra il 2011-10-10 e il 2011-12-12 o ogni 8 ore tra oggi e domani 19:00.Generare un elenco di datetimes tra un intervallo

Forse qualcosa di approssimativamente equivalente alla classe PHP Dateperiod.

Quale sarebbe il modo più efficiente per realizzare questo in Python?

risposta

65

Uso 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 

Opere per entrambe le date e gli oggetti datetime. Il tuo secondo esempio:

>>> 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 
+0

Python dovrebbe consentire le date in "intervallo". Avrebbe solo un senso. C'è un motivo per cui è debole digitata ... –

+3

@TylerCrompton: "L'esplicito è meglio che implicito." Cosa sarebbe incrementato nell'intervallo: giorni, secondi, microsecondi, millisecondi, minuti, ore o settimane? –

+3

@NoctisSkytower Il valore del passo sarebbe un oggetto 'timedelta'. –

13

Prova questo:

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 

L'esempio nella domanda, "ogni 8 ore tra oggi e domani 19:00" dovranno essere scritte in questo modo:

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

Si noti che i valori validi per period sono quelli definiti per l'informazione relativa relativedelta, ovvero: 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'microseconds'.

La mia soluzione restituisce un elenco, come richiesto nella domanda. Se non hai bisogno di tutti gli elementi contemporaneamente puoi usare i generatori, come nella risposta @MartijnPieters.

4

Mi sono piaciute entrambe le risposte di @Martijn Pieters e @ Óscar López. Lasciatemi suggerire la mia soluzione combinata tra queste due risposte.

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 
Problemi correlati