Iterando a través de un rango de fechas en Python

Resuelto ShawnMilo asked hace 15 años • 27 respuestas

Tengo el siguiente código para hacer esto, pero ¿cómo puedo hacerlo mejor? En este momento creo que es mejor que los bucles anidados, pero comienza a volverse Perl-one-liner cuando tienes un generador en una lista por comprensión.

day_count = (end_date - start_date).days + 1
for single_date in [d for d in (start_date + timedelta(n) for n in range(day_count)) if d <= end_date]:
    print strftime("%Y-%m-%d", single_date.timetuple())

Notas

  • En realidad, no estoy usando esto para imprimir. Esto es sólo para fines de demostración.
  • Las variables start_datey son objetos porque no necesito las marcas de tiempo. (Se utilizarán para generar un informe).end_datedatetime.date

Salida de muestra

Para una fecha de inicio 2009-05-30y una fecha de finalización de 2009-06-09:

2009-05-30
2009-05-31
2009-06-01
2009-06-02
2009-06-03
2009-06-04
2009-06-05
2009-06-06
2009-06-07
2009-06-08
2009-06-09
ShawnMilo avatar Jun 30 '09 03:06 ShawnMilo
Aceptado

¿Por qué hay dos iteraciones anidadas? Para mí produce la misma lista de datos con una sola iteración:

for single_date in (start_date + timedelta(n) for n in range(day_count)):
    print ...

Y no se almacena ninguna lista, solo se repite un generador. Además, el "si" en el generador parece innecesario.

Después de todo, una secuencia lineal sólo debería requerir un iterador, no dos.

Actualización después de la discusión con John Machin:

Quizás la solución más elegante sea usar una función generadora para ocultar/abstraer completamente la iteración en el rango de fechas:

from datetime import date, timedelta

def daterange(start_date, end_date):
    for n in range(int((end_date - start_date).days)):
        yield start_date + timedelta(n)

start_date = date(2013, 1, 1)
end_date = date(2015, 6, 2)
for single_date in daterange(start_date, end_date):
    print(single_date.strftime("%Y-%m-%d"))

NB: Para mantener la coherencia con la función incorporada, range()esta iteración se detiene antes de llegar al archivo end_date. Entonces, para una iteración inclusiva, use el día siguiente, como lo haría con range().

Ber avatar Jun 29 '2009 20:06 Ber

Esto podría ser más claro:

from datetime import date, timedelta

start_date = date(2019, 1, 1)
end_date = date(2020, 1, 1)
delta = timedelta(days=1)
while start_date <= end_date:
    print(start_date.strftime("%Y-%m-%d"))
    start_date += delta
Sean Cavanagh avatar Jun 29 '2009 20:06 Sean Cavanagh

Utilice la dateutilbiblioteca:

from datetime import date
from dateutil.rrule import rrule, DAILY

a = date(2009, 5, 30)
b = date(2009, 6, 9)

for dt in rrule(DAILY, dtstart=a, until=b):
    print dt.strftime("%Y-%m-%d")

Esta biblioteca de Python tiene muchas funciones más avanzadas, algunas muy útiles, como relative deltas, y se implementa como un único archivo (módulo) que se incluye fácilmente en un proyecto.

nosklo avatar Jun 30 '2009 04:06 nosklo

Pandas es excelente para series temporales en general y tiene soporte directo para rangos de fechas.

import pandas as pd
daterange = pd.date_range(start_date, end_date)

Luego puede recorrer el rango de fechas para imprimir la fecha:

for single_date in daterange:
    print (single_date.strftime("%Y-%m-%d"))

También tiene muchas opciones para hacer la vida más fácil. Por ejemplo, si solo quisiera los días laborables, simplemente cambiaría bdate_range. Consulte http://pandas.pydata.org/pandas-docs/stable/timeseries.html#generating-ranges-of-timestamps

El poder de Pandas son realmente sus marcos de datos, que admiten operaciones vectorizadas (muy parecidas a numpy) que hacen que las operaciones en grandes cantidades de datos sean muy rápidas y sencillas.

EDITAR: También puede omitir completamente el bucle for e imprimirlo directamente, lo cual es más fácil y eficiente:

print(daterange)
fantabolous avatar May 25 '2014 08:05 fantabolous