Dado un intervalo de fechas, ¿cómo podemos dividirlo en N subintervalos contiguos?

Estoy accediendo a algunos datos a través de una API en la que necesito proporcionar el rango de fechas para mi solicitud, ej. inicio = ‘20100101’, final = ‘20150415’. Pensé que aceleraría esto al dividir el intervalo de fechas en intervalos no superpuestos y utilizar el multiprocesamiento en cada intervalo.

Mi problema es que la forma en que estoy dividiendo el intervalo de fechas no siempre me da el resultado esperado. Esto es lo que he hecho:

from datetime import date begin = '20100101' end = '20101231' 

Supongamos que quisiéramos dividir esto en cuartos. Primero cambio la cadena en fechas:

 def get_yyyy_mm_dd(yyyymmdd): # given string 'yyyymmdd' return (yyyy, mm, dd) year = yyyymmdd[0:4] month = yyyymmdd[4:6] day = yyyymmdd[6:] return int(year), int(month), int(day) y1, m1, d1 = get_yyyy_mm_dd(begin) d1 = date(y1, m1, d1) y2, m2, d2 = get_yyyy_mm_dd(end) d2 = date(y2, m2, d2) 

Luego divide este rango en sub-intervalos:

 def remove_tack(dates_list): # given a list of dates in form YYYY-MM-DD return a list of strings in form 'YYYYMMDD' tackless = [] for d in dates_list: s = str(d) tackless.append(s[0:4]+s[5:7]+s[8:]) return tackless def divide_date(date1, date2, intervals): dates = [date1] for i in range(0, intervals): dates.append(dates[i] + (date2 - date1)/intervals) return remove_tack(dates) 

Usando comenzar y terminar desde arriba obtenemos:

 listdates = divide_date(d1, d2, 4) print listdates # ['20100101', '20100402', '20100702', '20101001', '20101231'] looks correct 

Pero si en cambio utilizo las fechas:

 begin = '20150101' end = '20150228' 

 listdates = divide_date(d1, d2, 4) print listdates # ['20150101', '20150115', '20150129', '20150212', '20150226'] 

Me faltan dos días a finales de febrero. No necesito tiempo ni zona horaria para mi aplicación y no me importa instalar otra biblioteca.

De hecho, seguiría un enfoque diferente y confiaría en la adición de fecha y hora para determinar los rangos no superpuestos

Implementación

 def date_range(start, end, intv): from datetime import datetime start = datetime.strptime(start,"%Y%m%d") end = datetime.strptime(end,"%Y%m%d") diff = (end - start ) / intv for i in range(intv): yield (start + diff * i).strftime("%Y%m%d") yield end.strftime("%Y%m%d") 

Ejecución

 >>> begin = '20150101' >>> end = '20150228' >>> list(date_range(begin, end, 4)) ['20150101', '20150115', '20150130', '20150213', '20150228'] 

debes cambiar la fecha por fecha y hora

 from datetime import date, datetime, timedelta begin = '20150101' end = '20150228' def get_yyyy_mm_dd(yyyymmdd): # given string 'yyyymmdd' return (yyyy, mm, dd) year = yyyymmdd[0:4] month = yyyymmdd[4:6] day = yyyymmdd[6:] return int(year), int(month), int(day) y1, m1, d1 = get_yyyy_mm_dd(begin) d1 = datetime(y1, m1, d1) y2, m2, d2 = get_yyyy_mm_dd(end) d2 = datetime(y2, m2, d2) def remove_tack(dates_list): # given a list of dates in form YYYY-MM-DD return a list of strings in form 'YYYYMMDD' tackless = [] for d in dates_list: s = str(d) tackless.append(s[0:4]+s[5:7]+s[8:]) return tackless def divide_date(date1, date2, intervals): dates = [date1] delta = (date2-date1).total_seconds()/4 for i in range(0, intervals): dates.append(dates[i] + timedelta(0,delta)) return remove_tack(dates) listdates = divide_date(d1, d2, 4) print listdates 

resultado:

[‘20150101 00:00:00’, ‘20150115 12:00:00’, ‘20150130 00:00:00’, ‘20150213 12:00:00’, ‘20150228 00:00:00’]

¿Podría utilizar los objetos datetime.date en su lugar?

Si lo haces:

 import datetime begin = datetime.date(2001, 1, 1) end = datetime.date(2010, 12, 31) intervals = 4 date_list = [] delta = (end - begin)/4 for i in range(1, intervals + 1): date_list.append((begin+i*delta).strftime('%Y%m%d')) 

y date_list deben tener las fechas de finalización para cada inteval.

Uso de Datetimeindex y Periods from Pandas, junto con la comprensión del diccionario:

 import pandas as pd begin = '20100101' end = '20101231' start = dt.datetime.strptime(begin, '%Y%m%d') finish = dt.datetime.strptime(end, '%Y%m%d') dates = pd.DatetimeIndex(start=start, end=finish, freq='D').tolist() quarters = [d.to_period('Q') for d in dates] df = pd.DataFrame([quarters, dates], index=['Quarter', 'Date']).T quarterly_dates = {str(q): [ts.strftime('%Y%m%d') for ts in df[df.Quarter == q].Date.values.tolist()] for q in quarters} >>> quarterly_dates {'2010Q1': ['20100101', '20100102', '20100103', '20100104', '20100105', ... '20101227', '20101228', '20101229', '20101230', '20101231']} >>> quarterly_dates.keys() ['2010Q1', '2010Q2', '2010Q3', '2010Q4']