2012-05-21 16 views
42

Biorąc pod uwagę dwa datetimes (start_date i end_date), chciałbym wygenerować listę innych datetimes między tymi dwiema datami, nowe czasy są oddzielone przez zmienny przedział. na przykład co 4 dni od 2011-10-10 do 2011-12-12 lub co 8 godzin od teraz do jutra 19 pm.Generowanie listy datetimes między interwałem

Może coś mniej więcej odpowiada klasie PHP Dateperiod.

Jaki byłby najskuteczniejszy sposób osiągnięcia tego w Pythonie?

Odpowiedz

65

Zastosowanie 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 

działa zarówno dat i obiektów datetime. Twój drugi przykład:

>>> 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 powinien dopuszczać daty w "zakresie". Miałoby to sens tylko. Jest powód, dla którego jest słabo wpisany ... –

+3

@TylerCrompton: "Jawny jest lepszy niż niejawny." Co zwiększyłoby się w zakresie: dni, sekundy, mikrosekundy, milisekundy, minuty, godziny lub tygodnie? –

+3

@NoctisSkytower Wartość kroku byłaby obiektem 'timedelta'. –

13

Spróbuj tego:

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 

Przykład na pytanie, "co 8 godzin między teraz i jutro 19:00" będzie napisane tak:

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

Należy zauważyć, że prawidłowe wartości dla period są wartościami zdefiniowanymi dla względnej informacji relativedelta, a mianowicie: 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'microseconds'.

Moje rozwiązanie zwraca listę, zgodnie z wymaganiami w pytaniu. Jeśli nie potrzebujesz wszystkich elementów jednocześnie, możesz użyć generatorów, tak jak w odpowiedzi @MartijnPieters.

4

Bardzo podobały mi się obie odpowiedzi @Martijna Pietersa i @ Óscar López. Pozwól mi zaproponować moje połączone rozwiązanie między tymi dwiema odpowiedziami.

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 
Powiązane problemy