2012-05-21 4 views
42

Gegeben zwei Datumsangaben (start_date und end_date), ich möchte eine Liste der anderen Datumsangaben zwischen diesen beiden Daten generieren, die neuen Datumsangaben durch ein variables Intervall getrennt werden. z.B. alle 4 Tage zwischen 2011-10-10 und 2011-12-12 oder alle 8 Stunden zwischen heute und morgen 19:00 UhrGenerieren Sie eine Liste der Datumsangaben zwischen einem Intervall

Vielleicht etwas in etwa der Dateperiod PHP-Klasse entspricht.

Was wäre der effizienteste Weg, dies in Python zu erreichen?

Antwort

65

Verwendung 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 

funktioniert sowohl für Termine und Datetime-Objekte. Ihr zweites Beispiel:

>>> 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 sollte Daten in 'Bereich' erlauben. Es würde nur Sinn machen. Es gibt einen Grund, warum es schwach typisiert ist ... –

+3

@TylerCrompton: "Explizit ist besser als implizit." Was würde in dem Bereich erhöht werden: Tage, Sekunden, Mikrosekunden, Millisekunden, Minuten, Stunden oder Wochen? –

+3

@NoctisSkytower Der Schrittwert wäre ein 'timedelta'-Objekt. –

13

Versuchen Sie folgendes:

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 

Das Beispiel in der Frage, "alle 8 Stunden zwischen jetzt und morgen 19.00 Uhr" geschrieben werden würden wie folgt:

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

Beachten Sie, dass die gültigen Werte für period diejenigen sind, die für die relative Information relativedelta definiert sind, nämlich: 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'microseconds'.

Meine Lösung gibt eine Liste, wie in der Frage erforderlich. Wenn Sie nicht alle Elemente auf einmal benötigen, können Sie Generatoren verwenden, wie in @MartijnPieters antworten.

4

Ich mochte beide Antworten von @Martijn Pieters und @ Óscar López. Lassen Sie mich meine kombinierte Lösung zwischen diesen beiden Antworten vorschlagen.

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