Na verdade, eu precisava fazer algo bem parecido agora
Acabei escrevendo uma função que retorna uma lista de tuplas indicando o start
eend
de cada mês entre dois conjuntos de datas para que eu pudesse escrever algumas consultas SQL atrás dela para totais mensais de vendas etc.
Tenho certeza que pode ser melhorado por alguém que sabe o que está fazendo, mas espero que ajude ...
O valor retornado é o seguinte (gerando para hoje - 365 dias até hoje como exemplo)
[ (datetime.date(2013, 5, 1), datetime.date(2013, 5, 31)),
(datetime.date(2013, 6, 1), datetime.date(2013, 6, 30)),
(datetime.date(2013, 7, 1), datetime.date(2013, 7, 31)),
(datetime.date(2013, 8, 1), datetime.date(2013, 8, 31)),
(datetime.date(2013, 9, 1), datetime.date(2013, 9, 30)),
(datetime.date(2013, 10, 1), datetime.date(2013, 10, 31)),
(datetime.date(2013, 11, 1), datetime.date(2013, 11, 30)),
(datetime.date(2013, 12, 1), datetime.date(2013, 12, 31)),
(datetime.date(2014, 1, 1), datetime.date(2014, 1, 31)),
(datetime.date(2014, 2, 1), datetime.date(2014, 2, 28)),
(datetime.date(2014, 3, 1), datetime.date(2014, 3, 31)),
(datetime.date(2014, 4, 1), datetime.date(2014, 4, 30)),
(datetime.date(2014, 5, 1), datetime.date(2014, 5, 31))]
Código da seguinte forma (tem algumas coisas de depuração que podem ser removidas):
#! /usr/env/python
import datetime
def gen_month_ranges(start_date=None, end_date=None, debug=False):
today = datetime.date.today()
if not start_date: start_date = datetime.datetime.strptime(
"{0}/01/01".format(today.year),"%Y/%m/%d").date() # start of this year
if not end_date: end_date = today
if debug: print("Start: {0} | End {1}".format(start_date, end_date))
# sense-check
if end_date < start_date:
print("Error. Start Date of {0} is greater than End Date of {1}?!".format(start_date, end_date))
return None
date_ranges = [] # list of tuples (month_start, month_end)
current_year = start_date.year
current_month = start_date.month
while current_year <= end_date.year:
next_month = current_month + 1
next_year = current_year
if next_month > 12:
next_month = 1
next_year = current_year + 1
month_start = datetime.datetime.strptime(
"{0}/{1}/01".format(current_year,
current_month),"%Y/%m/%d").date() # start of month
month_end = datetime.datetime.strptime(
"{0}/{1}/01".format(next_year,
next_month),"%Y/%m/%d").date() # start of next month
month_end = month_end+datetime.timedelta(days=-1) # start of next month less one day
range_tuple = (month_start, month_end)
if debug: print("Month runs from {0} --> {1}".format(
range_tuple[0], range_tuple[1]))
date_ranges.append(range_tuple)
if current_month == 12:
current_month = 1
current_year += 1
if debug: print("End of year encountered, resetting months")
else:
current_month += 1
if debug: print("Next iteration for {0}-{1}".format(
current_year, current_month))
if current_year == end_date.year and current_month > end_date.month:
if debug: print("Final month encountered. Terminating loop")
break
return date_ranges
if __name__ == '__main__':
print("Running in standalone mode. Debug set to True")
from pprint import pprint
pprint(gen_month_ranges(debug=True), indent=4)
pprint(gen_month_ranges(start_date=datetime.date.today()+datetime.timedelta(days=-365),
debug=True), indent=4)