2008-09-30 85 views
46

¿Cómo puedo iterar durante un intervalo de tiempo después de días, horas, semanas o meses?¿Cómo iterar durante un intervalo de tiempo después de días, horas, semanas y meses en Python?

Algo así como:

for date in foo(from_date, to_date, delta=HOURS): 
    print date 

donde foo es una función, que devuelve un iterador. He estado mirando el módulo de calendario, pero eso solo funciona para un año o mes específico, no entre fechas.

+0

¿O es que desea una función con la firma anterior? –

Respuesta

75

Uso dateutil y su aplicación RRULE, de este modo:

from dateutil import rrule 
from datetime import datetime, timedelta 

now = datetime.now() 
hundredDaysLater = now + timedelta(days=100) 

for dt in rrule.rrule(rrule.MONTHLY, dtstart=now, until=hundredDaysLater): 
    print dt 

salida es

2008-09-30 23:29:54 
2008-10-30 23:29:54 
2008-11-30 23:29:54 
2008-12-30 23:29:54 

Reemplace MENSUALMENTE con cualquiera de AÑO, MENSUALMENTE, SEMANALMENTE, DIARIAMENTE, HORAS, MINUTOS O SEGUNDAMENTE. Reemplace dtstart y hasta con el objeto datetime que desee.

Esta receta tiene la ventaja de funcionar en todos los casos, incluido MENSUALMENTE. La única advertencia que puedo encontrar es que si pasa un número de día que no existe en todos los meses, se salta esos meses.

+1

http://niemeyer.net/python-dateutil explica cómo usarlo para recuperar "una fecha en el día especificado del mes, a menos que esté más allá fin de mes, en cuyo caso será el último día del mes ". Esto corrige la única advertencia que enumeró. Como ejemplo, ahora = fecha y hora (2010, 8, 31, 1, 1, 1); para dt en rrule.rrule (rrule.MONTHLY, dtstart = now, bymonthday = (31, -1), count = 6): print dt – Smerity

-1

Esta biblioteca proporciona una herramienta de calendario a la mano: mxDateTime, eso debería ser suficiente :)

38

no creo que hay un método en la biblioteca de Python, pero usted puede crear fácilmente uno por sí mismo utilizando datetime módulo:

from datetime import date, datetime, timedelta 

def datespan(startDate, endDate, delta=timedelta(days=1)): 
    currentDate = startDate 
    while currentDate < endDate: 
     yield currentDate 
     currentDate += delta 

Posteriormente, se podría utilizar de esta manera:

>>> for day in datespan(date(2007, 3, 30), date(2007, 4, 3), 
>>>      delta=timedelta(days=1)): 
>>>  print day 
2007-03-30 
2007-03-31 
2007-04-01 
2007-04-02 

O bien, si desea hacer su delta más pequeño:

>>> for timestamp in datespan(datetime(2007, 3, 30, 15, 30), 
>>>       datetime(2007, 3, 30, 18, 35), 
>>>       delta=timedelta(hours=1)): 
>>>  print timestamp 
2007-03-30 15:30:00 
2007-03-30 16:30:00 
2007-03-30 17:30:00 
2007-03-30 18:30:00 
+1

No puede especificar un timedelta de un mes – dangonfast

6

Para iterar durante meses, necesita una receta diferente, ya que timedeltas no puede expresar "un mes".

from datetime import date 

def jump_by_month(start_date, end_date, month_step=1): 
    current_date = start_date 
    while current_date < end_date: 
     yield current_date 
     carry, new_month = divmod(current_date.month - 1 + month_step, 12) 
     new_month += 1 
     current_date = current_date.replace(year=current_date.year + carry, 
              month=new_month) 

(Nota: hay que restar 1 al mes para la operación de módulo a continuación, añadir de nuevo a new_month, ya que en meses datetime.date s inicio en 1.)

+0

Dos cosas: - este código plantea 'ValueError' si establece el día de fecha_inicio en un número que no existe en todos los meses - probablemente, exactamente por eso no hay mes -timedelta; Sugeriría usar 'timedelta (days = 30)' para una buena aproximación. – DzinX

+0

Buena captura. A veces, sin embargo, una aproximación no es lo suficientemente buena (mi recordatorio "pague el alquiler" * debe * ser a las 6:30 el primero de cada mes). La receta podría modificarse -probablemente con algún estado adicional- para proporcionar una funcionalidad sana, sea lo que sea. – giltay

+0

También puede tener problemas para iterar año tras año el 29 de febrero. – giltay

-2

Debe modificar esta línea para que esto funcione correctamente:

fecha_actual = current_date.replace (año = + current_date.year llevar, mes = new_month, día = 1)

;)

0

Mes método de iteración:

def months_between(date_start, date_end): 
    months = [] 

    # Make sure start_date is smaller than end_date 
    if date_start > date_end: 
     tmp = date_start 
     date_start = date_end 
     date_end = tmp 

    tmp_date = date_start 
    while tmp_date.month <= date_end.month or tmp_date.year < date_end.year: 
     months.append(tmp_date) # Here you could do for example: months.append(datetime.datetime.strftime(tmp_date, "%b '%y")) 

     if tmp_date.month == 12: # New year 
      tmp_date = datetime.date(tmp_date.year + 1, 1, 1) 
     else: 
      tmp_date = datetime.date(tmp_date.year, tmp_date.month + 1, 1) 
    return months 

Más código, pero lo hará trato bien con largos períodos de tiempo comprobando que las fechas dadas son en orden ...

Cuestiones relacionadas