Iterando a través de un rango de fechas en Python
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_date
y son objetos porque no necesito las marcas de tiempo. (Se utilizarán para generar un informe).end_date
datetime.date
Salida de muestra
Para una fecha de inicio 2009-05-30
y 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
¿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()
.
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
Utilice la dateutil
biblioteca:
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 delta
s, y se implementa como un único archivo (módulo) que se incluye fácilmente en un proyecto.
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)