Generate list of months between interval in python
Question:
I want to generate a python list containing all months occurring between two dates, with the input and output formatted as follows:
date1 = "2014-10-10" # input start date
date2 = "2016-01-07" # input end date
month_list = ['Oct-14', 'Nov-14', 'Dec-14', 'Jan-15', 'Feb-15', 'Mar-15', 'Apr-15', 'May-15', 'Jun-15', 'Jul-15', 'Aug-15', 'Sep-15', 'Oct-15', 'Nov-15', 'Dec-15', 'Jan-16'] # output
Answers:
>>> from datetime import datetime, timedelta
>>> from collections import OrderedDict
>>> dates = ["2014-10-10", "2016-01-07"]
>>> start, end = [datetime.strptime(_, "%Y-%m-%d") for _ in dates]
>>> OrderedDict(((start + timedelta(_)).strftime(r"%b-%y"), None) for _ in xrange((end - start).days)).keys()
['Oct-14', 'Nov-14', 'Dec-14', 'Jan-15', 'Feb-15', 'Mar-15', 'Apr-15', 'May-15', 'Jun-15', 'Jul-15', 'Aug-15', 'Sep-15', 'Oct-15', 'Nov-15', 'Dec-15', 'Jan-16']
Update: a bit of explanation, as requested in one comment. There are three problems here: parsing the dates into appropriate data structures (strptime
); getting the date range given the two extremes and the step (one month); formatting the output dates (strftime
). The datetime
type overloads the subtraction operator, so that end - start
makes sense. The result is a timedelta
object that represents the difference between the two dates, and the .days
attribute gets this difference expressed in days. There is no .months
attribute, so we iterate one day at a time and convert the dates to the desired output format. This yields a lot of duplicates, which the OrderedDict
removes while keeping the items in the right order.
Now this is simple and concise because it lets the datetime module do all the work, but it’s also horribly inefficient. We’re calling a lot of methods for each day while we only need to output months. If performance is not an issue, the above code will be just fine. Otherwise, we’ll have to work a bit more. Let’s compare the above implementation with a more efficient one:
from datetime import datetime, timedelta
from collections import OrderedDict
dates = ["2014-10-10", "2016-01-07"]
def monthlist_short(dates):
start, end = [datetime.strptime(_, "%Y-%m-%d") for _ in dates]
return OrderedDict(((start + timedelta(_)).strftime(r"%b-%y"), None) for _ in xrange((end - start).days)).keys()
def monthlist_fast(dates):
start, end = [datetime.strptime(_, "%Y-%m-%d") for _ in dates]
total_months = lambda dt: dt.month + 12 * dt.year
mlist = []
for tot_m in xrange(total_months(start)-1, total_months(end)):
y, m = divmod(tot_m, 12)
mlist.append(datetime(y, m+1, 1).strftime("%b-%y"))
return mlist
assert monthlist_fast(dates) == monthlist_short(dates)
if __name__ == "__main__":
from timeit import Timer
for func in "monthlist_short", "monthlist_fast":
print func, Timer("%s(dates)" % func, "from __main__ import dates, %s" % func).timeit(1000)
On my laptop, I get the following output:
monthlist_short 2.3209939003
monthlist_fast 0.0774540901184
The concise implementation is about 30 times slower, so I would not recommend it in time-critical applications 🙂
You have to use Calendar and Datetime
import calendar
from datetime import *
date1 = datetime.strptime("2014-10-10", "%Y-%m-%d")
date2 = datetime.strptime("2016-01-07", "%Y-%m-%d")
date1 = date1.replace(day = 1)
date2 = date2.replace(day = 1)
months_str = calendar.month_name
months = []
while date1 < date2:
month = date1.month
year = date1.year
month_str = months_str[month][0:3]
months.append("{0}-{1}".format(month_str,str(year)[-2:]))
next_month = month+1 if month != 12 else 1
next_year = year + 1 if next_month == 1 else year
date1 = date1.replace( month = next_month, year= next_year)
print months
This code returns
['Oct-14', 'Nov-14', 'Dec-14', 'Jan-14', 'Feb-15', 'Mar-15', 'Apr-15', 'May-15', 'Jun-15', 'Jul-15', 'Aug-15', 'Sep-15', 'Oct-15', 'Nov-15', 'Dec-15', 'Jan-15']
Having done similar stuff previously, I took a stab at solving this. Using distinct components for doing this is more flexible and enables you to mix and match them for different use-cases. They also can be tested more easily this way, as you can see by the doctests in iterate_months
.
Also I suggest to use datetime.date
objects for your input as you can just do more with those. To do that you’ll have to first parse your input string, but this is very easily done.
Parsing the date-strings
def datify(date):
if isinstance(date, datetime.date):
return date
elif isinstance(date, datetime.datetime):
return date.date()
else:
# taken from simleo's answer
return datetime.strptime(date, "%Y-%m-%d")
First, we iterate through the months
import datetime
def iterate_months(start_date, end_date):
"""Iterate monthly between two given dates.
Emitted will be the first day of each month.
>>> list(iterate_months(datetime.date(1999, 11, 1),
... datetime.date(2000, 2, 1)))
[datetime.date(1999, 11, 1), datetime.date(1999, 12, 1),
datetime.date(2000, 1, 1), datetime.date(2000, 2, 1)]
"""
assert isinstance(start_date, datetime.date)
assert isinstance(end_date, datetime.date)
assert start_date < end_date
year = start_date.year
month = start_date.month
while True:
current = datetime.date(year, month, 1)
yield current
if current.month == end_date.month and current.year == end_date.year:
break
else:
month = ((month + 1) % 12) or 12
if month == 1:
year += 1
if __name__ == '__main__':
import doctest
doctest.testmod()
To format your dates, use something like this
def format_month(date):
return date.strftime(r"%b-%y")
Putting it all together
start = datify("2014-10-10")
end = datify("2016-01-07")
for entry in iterate_months(start, end):
print format_month(entry)
Or save it as a list:
result = list(iterate_months(start, end))
Here is my solution with a simple list comprehension which uses range
to know where months must start and end
from datetime import datetime as dt
sd = dt.strptime('2014-10-10', "%Y-%m-%d")
ed = dt.strptime('2016-01-07', "%Y-%m-%d")
lst = [dt.strptime('%2.2d-%2.2d' % (y, m), '%Y-%m').strftime('%b-%y')
for y in xrange(sd.year, ed.year+1)
for m in xrange(sd.month if y==sd.year else 1, ed.month+1 if y == ed.year else 13)]
print lst
produces
['Oct-14', 'Nov-14', 'Dec-14', 'Jan-15', 'Feb-15', 'Mar-15', 'Apr-15', 'May-15', 'Jun-15', 'Jul-15', 'Aug-15', 'Sep-15', 'Oct-15', 'Nov-15', 'Dec-15', 'Jan-16']
Find below my approach to this problem using split and simple modulo-based iterations without importing any special module.
date1 = "2014-10-10"
date2 = "2016-01-07"
y0 = int( date1.split('-')[0] ) # 2014
y1 = int( date2.split('-')[0] ) # 2016
m0 = int( date1.split('-')[1] ) - 1 # 10-1 --> 9 because will be used for indexing
m1 = int( date2.split('-')[1] ) - 1 # 01-1 --> 0 because will be used for indexing
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
result = []
start = m0
for y in range(y0, y1+1):
for m in range(start,12):
result.append( str( months[m % 12])+'-'+str(y) )
if y == y1 and (m % 12) == m1:
break
start = 0
print result
$ python dates.py
['Oct-2014', 'Nov-2014', 'Dec-2014', 'Jan-2015', 'Feb-2015', 'Mar-2015', 'Apr-2015', 'May-2015', 'Jun-2015', 'Jul-2015', 'Aug-2015', 'Sep-2015', 'Oct-2015', 'Nov-2015', 'Dec-2015', 'Jan-2016']
I found a very succinct way to do this with Pandas, sharing in case it helps anybody:
UPDATE: I’ve got it down to a one-liner with the help of this post 🙂
pd.date_range('2014-10-10','2016-01-07',
freq='MS').strftime("%Y-%b").tolist()
OLD ANSWER:
daterange = pd.date_range('2014-10-10','2016-01-07' , freq='1M')
daterange = daterange.union([daterange[-1] + 1])
daterange = [d.strftime('%y-%b') for d in daterange]
The second line prevents the last date from getting clipped off the list.
With pandas, you can have a one liner like this:
import pandas as pd
date1 = "2014-10-10" # input start date
date2 = "2016-01-07" # input end date
month_list = [i.strftime("%b-%y") for i in pd.date_range(start=date1, end=date2, freq='MS')]
If you’re interested in keeping your dates in a Python format, you can try using to_pydatetime()
.
import pandas as pd
from datetime import datetime
datemin = datetime(2010, 1, 1)
datemax = datetime(2019, 12, 31)
# First day of month
pd.date_range(datemin, datemax, freq='MS').to_pydatetime().tolist()
# Last day of month
pd.date_range(datemin, datemax, freq='M').to_pydatetime().tolist()
I came to a solution that uses python-dateutil
and works with Python 3.8+:
https://gist.github.com/anatoly-scherbakov/593770d446a06f109438a134863ba969
def month_range(
start: datetime.date,
end: datetime.date,
) -> Iterator[datetime.date]:
"""Yields the 1st day of each month in the given date range."""
yield from itertools.takewhile(
lambda date: date < end,
itertools.accumulate(
itertools.repeat(relativedelta(months=1)),
operator.add,
initial=start,
)
)
here is the similar version of what Pynchia suggestioned, the below implementation is for python 3.8 the one he implemented is for python 2.x
import datetime
st="2020-06-24"
ed="2020-11-24"
start_date = datetime.datetime.strptime(st.strip(), '%Y-%m-%d')
end_date = datetime.datetime.strptime(ed.strip(), '%Y-%m-%d')
months = [datetime.datetime.strptime('%2.2d-%2.2d' % (y, m), '%Y-%m').strftime('%b-%y')
for y in range(start_date.year, end_date.year + 1)
for m in range(start_date.month if y == start_date.year else 1, end_date.month + 1 if y == end_date.year else 13)]
print(months)
If you want a dictionary that contains pair of month’s starting date and ending date between your desired years, then here’s how to get that.
start_year = int(input("Enter Starting Year: "))
end_year = int(input("Enter Ending Year: "))
import calendar
month_dict = {}
for x in range(start_year, end_year):
for y in range(1, 13):
if y < 10:
start_date = '01'+'-'+'0'+str(y)+'-'+str(x)
end_date = str(calendar.monthrange(x, y)[1])+'-'+'0'+str(y)+'-'+str(x)
month_dict[start_date] = end_date
else:
start_date = '01'+'-'+str(y)+'-'+str(x)
end_date = str(calendar.monthrange(x, y)[1])+'-'+str(y)+'-'+str(x)
month_dict[start_date] = end_date
This gives the following output:
{'01-01-2000': '31-01-2000',
'01-02-2000': '29-02-2000',
'01-03-2000': '31-03-2000',
'01-04-2000': '30-04-2000',
'01-05-2000': '31-05-2000',
'01-06-2000': '30-06-2000',
'01-07-2000': '31-07-2000',
'01-08-2000': '31-08-2000',
'01-09-2000': '30-09-2000',
'01-10-2000': '31-10-2000',
'01-11-2000': '30-11-2000',
'01-12-2000': '31-12-2000',
'01-01-2001': '31-01-2001',
'01-02-2001': '28-02-2001',
'01-03-2001': '31-03-2001',
'01-04-2001': '30-04-2001',
'01-05-2001': '31-05-2001',
'01-06-2001': '30-06-2001',
'01-07-2001': '31-07-2001',
'01-08-2001': '31-08-2001',
'01-09-2001': '30-09-2001',
'01-10-2001': '31-10-2001',
'01-11-2001': '30-11-2001',
'01-12-2001': '31-12-2001',
'01-01-2002': '31-01-2002',
'01-02-2002': '28-02-2002',
'01-03-2002': '31-03-2002',
'01-04-2002': '30-04-2002',
'01-05-2002': '31-05-2002',
'01-06-2002': '30-06-2002',
'01-07-2002': '31-07-2002',
'01-08-2002': '31-08-2002',
'01-09-2002': '30-09-2002',
'01-10-2002': '31-10-2002',
'01-11-2002': '30-11-2002',
'01-12-2002': '31-12-2002',
'01-01-2003': '31-01-2003',
'01-02-2003': '28-02-2003',
'01-03-2003': '31-03-2003',
'01-04-2003': '30-04-2003',
'01-05-2003': '31-05-2003',
'01-06-2003': '30-06-2003',
'01-07-2003': '31-07-2003',
'01-08-2003': '31-08-2003',
'01-09-2003': '30-09-2003',
'01-10-2003': '31-10-2003',
'01-11-2003': '30-11-2003',
'01-12-2003': '31-12-2003',
'01-01-2004': '31-01-2004',
'01-02-2004': '29-02-2004',
'01-03-2004': '31-03-2004',
'01-04-2004': '30-04-2004',
'01-05-2004': '31-05-2004',
'01-06-2004': '30-06-2004',
'01-07-2004': '31-07-2004',
'01-08-2004': '31-08-2004',
'01-09-2004': '30-09-2004',
'01-10-2004': '31-10-2004',
'01-11-2004': '30-11-2004',
'01-12-2004': '31-12-2004',
'01-01-2005': '31-01-2005',
'01-02-2005': '28-02-2005',
'01-03-2005': '31-03-2005',
'01-04-2005': '30-04-2005',
'01-05-2005': '31-05-2005',
'01-06-2005': '30-06-2005',
'01-07-2005': '31-07-2005',
'01-08-2005': '31-08-2005',
'01-09-2005': '30-09-2005',
'01-10-2005': '31-10-2005',
'01-11-2005': '30-11-2005',
'01-12-2005': '31-12-2005',
'01-01-2006': '31-01-2006',
'01-02-2006': '28-02-2006',
'01-03-2006': '31-03-2006',
'01-04-2006': '30-04-2006',
'01-05-2006': '31-05-2006',
'01-06-2006': '30-06-2006',
'01-07-2006': '31-07-2006',
'01-08-2006': '31-08-2006',
'01-09-2006': '30-09-2006',
'01-10-2006': '31-10-2006',
'01-11-2006': '30-11-2006',
'01-12-2006': '31-12-2006',
'01-01-2007': '31-01-2007',
'01-02-2007': '28-02-2007',
'01-03-2007': '31-03-2007',
'01-04-2007': '30-04-2007',
'01-05-2007': '31-05-2007',
'01-06-2007': '30-06-2007',
'01-07-2007': '31-07-2007',
'01-08-2007': '31-08-2007',
'01-09-2007': '30-09-2007',
'01-10-2007': '31-10-2007',
'01-11-2007': '30-11-2007',
'01-12-2007': '31-12-2007',
'01-01-2008': '31-01-2008',
'01-02-2008': '29-02-2008',
'01-03-2008': '31-03-2008',
'01-04-2008': '30-04-2008',
'01-05-2008': '31-05-2008',
'01-06-2008': '30-06-2008',
'01-07-2008': '31-07-2008',
'01-08-2008': '31-08-2008',
'01-09-2008': '30-09-2008',
'01-10-2008': '31-10-2008',
'01-11-2008': '30-11-2008',
'01-12-2008': '31-12-2008',
'01-01-2009': '31-01-2009',
'01-02-2009': '28-02-2009',
'01-03-2009': '31-03-2009',
'01-04-2009': '30-04-2009',
'01-05-2009': '31-05-2009',
'01-06-2009': '30-06-2009',
'01-07-2009': '31-07-2009',
'01-08-2009': '31-08-2009',
'01-09-2009': '30-09-2009',
'01-10-2009': '31-10-2009',
'01-11-2009': '30-11-2009',
'01-12-2009': '31-12-2009',
'01-01-2010': '31-01-2010',
'01-02-2010': '28-02-2010',
'01-03-2010': '31-03-2010',
'01-04-2010': '30-04-2010',
'01-05-2010': '31-05-2010',
'01-06-2010': '30-06-2010',
'01-07-2010': '31-07-2010',
'01-08-2010': '31-08-2010',
'01-09-2010': '30-09-2010',
'01-10-2010': '31-10-2010',
'01-11-2010': '30-11-2010',
'01-12-2010': '31-12-2010',
'01-01-2011': '31-01-2011',
'01-02-2011': '28-02-2011',
'01-03-2011': '31-03-2011',
'01-04-2011': '30-04-2011',
'01-05-2011': '31-05-2011',
'01-06-2011': '30-06-2011',
'01-07-2011': '31-07-2011',
'01-08-2011': '31-08-2011',
'01-09-2011': '30-09-2011',
'01-10-2011': '31-10-2011',
'01-11-2011': '30-11-2011',
'01-12-2011': '31-12-2011',
'01-01-2012': '31-01-2012',
'01-02-2012': '29-02-2012',
'01-03-2012': '31-03-2012',
'01-04-2012': '30-04-2012',
'01-05-2012': '31-05-2012',
'01-06-2012': '30-06-2012',
'01-07-2012': '31-07-2012',
'01-08-2012': '31-08-2012',
'01-09-2012': '30-09-2012',
'01-10-2012': '31-10-2012',
'01-11-2012': '30-11-2012',
'01-12-2012': '31-12-2012',
'01-01-2013': '31-01-2013',
'01-02-2013': '28-02-2013',
'01-03-2013': '31-03-2013',
'01-04-2013': '30-04-2013',
'01-05-2013': '31-05-2013',
'01-06-2013': '30-06-2013',
'01-07-2013': '31-07-2013',
'01-08-2013': '31-08-2013',
'01-09-2013': '30-09-2013',
'01-10-2013': '31-10-2013',
'01-11-2013': '30-11-2013',
'01-12-2013': '31-12-2013',
'01-01-2014': '31-01-2014',
'01-02-2014': '28-02-2014',
'01-03-2014': '31-03-2014',
'01-04-2014': '30-04-2014',
'01-05-2014': '31-05-2014',
'01-06-2014': '30-06-2014',
'01-07-2014': '31-07-2014',
'01-08-2014': '31-08-2014',
'01-09-2014': '30-09-2014',
'01-10-2014': '31-10-2014',
'01-11-2014': '30-11-2014',
'01-12-2014': '31-12-2014',
'01-01-2015': '31-01-2015',
'01-02-2015': '28-02-2015',
'01-03-2015': '31-03-2015',
'01-04-2015': '30-04-2015',
'01-05-2015': '31-05-2015',
'01-06-2015': '30-06-2015',
'01-07-2015': '31-07-2015',
'01-08-2015': '31-08-2015',
'01-09-2015': '30-09-2015',
'01-10-2015': '31-10-2015',
'01-11-2015': '30-11-2015',
'01-12-2015': '31-12-2015',
'01-01-2016': '31-01-2016',
'01-02-2016': '29-02-2016',
'01-03-2016': '31-03-2016',
'01-04-2016': '30-04-2016',
'01-05-2016': '31-05-2016',
'01-06-2016': '30-06-2016',
'01-07-2016': '31-07-2016',
'01-08-2016': '31-08-2016',
'01-09-2016': '30-09-2016',
'01-10-2016': '31-10-2016',
'01-11-2016': '30-11-2016',
'01-12-2016': '31-12-2016',
'01-01-2017': '31-01-2017',
'01-02-2017': '28-02-2017',
'01-03-2017': '31-03-2017',
'01-04-2017': '30-04-2017',
'01-05-2017': '31-05-2017',
'01-06-2017': '30-06-2017',
'01-07-2017': '31-07-2017',
'01-08-2017': '31-08-2017',
'01-09-2017': '30-09-2017',
'01-10-2017': '31-10-2017',
'01-11-2017': '30-11-2017',
'01-12-2017': '31-12-2017',
'01-01-2018': '31-01-2018',
'01-02-2018': '28-02-2018',
'01-03-2018': '31-03-2018',
'01-04-2018': '30-04-2018',
'01-05-2018': '31-05-2018',
'01-06-2018': '30-06-2018',
'01-07-2018': '31-07-2018',
'01-08-2018': '31-08-2018',
'01-09-2018': '30-09-2018',
'01-10-2018': '31-10-2018',
'01-11-2018': '30-11-2018',
'01-12-2018': '31-12-2018',
'01-01-2019': '31-01-2019',
'01-02-2019': '28-02-2019',
'01-03-2019': '31-03-2019',
'01-04-2019': '30-04-2019',
'01-05-2019': '31-05-2019',
'01-06-2019': '30-06-2019',
'01-07-2019': '31-07-2019',
'01-08-2019': '31-08-2019',
'01-09-2019': '30-09-2019',
'01-10-2019': '31-10-2019',
'01-11-2019': '30-11-2019',
'01-12-2019': '31-12-2019',
'01-01-2020': '31-01-2020',
'01-02-2020': '29-02-2020',
'01-03-2020': '31-03-2020',
'01-04-2020': '30-04-2020',
'01-05-2020': '31-05-2020',
'01-06-2020': '30-06-2020',
'01-07-2020': '31-07-2020',
'01-08-2020': '31-08-2020',
'01-09-2020': '30-09-2020',
'01-10-2020': '31-10-2020',
'01-11-2020': '30-11-2020',
'01-12-2020': '31-12-2020',
'01-01-2021': '31-01-2021',
'01-02-2021': '28-02-2021',
'01-03-2021': '31-03-2021',
'01-04-2021': '30-04-2021',
'01-05-2021': '31-05-2021',
'01-06-2021': '30-06-2021',
'01-07-2021': '31-07-2021',
'01-08-2021': '31-08-2021',
'01-09-2021': '30-09-2021',
'01-10-2021': '31-10-2021',
'01-11-2021': '30-11-2021',
'01-12-2021': '31-12-2021'}
Try this out, it will list down all the month from start to end as a continuous chain starting from the start date.
import datetime
a='2021-12-1'
b='2022-1-2'
d1=datetime.datetime.strptime(a,'%Y-%m-%d')
d2=datetime.datetime.strptime(b,'%Y-%m-%d')
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
totalmonts=(d2.year-d1.year)*12+d2.month-11+12-d1.month
print(totalmonts)
for i in range(totalmonts):
print(months[(d1.month+i-1)%12])
I want to generate a python list containing all months occurring between two dates, with the input and output formatted as follows:
date1 = "2014-10-10" # input start date
date2 = "2016-01-07" # input end date
month_list = ['Oct-14', 'Nov-14', 'Dec-14', 'Jan-15', 'Feb-15', 'Mar-15', 'Apr-15', 'May-15', 'Jun-15', 'Jul-15', 'Aug-15', 'Sep-15', 'Oct-15', 'Nov-15', 'Dec-15', 'Jan-16'] # output
>>> from datetime import datetime, timedelta
>>> from collections import OrderedDict
>>> dates = ["2014-10-10", "2016-01-07"]
>>> start, end = [datetime.strptime(_, "%Y-%m-%d") for _ in dates]
>>> OrderedDict(((start + timedelta(_)).strftime(r"%b-%y"), None) for _ in xrange((end - start).days)).keys()
['Oct-14', 'Nov-14', 'Dec-14', 'Jan-15', 'Feb-15', 'Mar-15', 'Apr-15', 'May-15', 'Jun-15', 'Jul-15', 'Aug-15', 'Sep-15', 'Oct-15', 'Nov-15', 'Dec-15', 'Jan-16']
Update: a bit of explanation, as requested in one comment. There are three problems here: parsing the dates into appropriate data structures (strptime
); getting the date range given the two extremes and the step (one month); formatting the output dates (strftime
). The datetime
type overloads the subtraction operator, so that end - start
makes sense. The result is a timedelta
object that represents the difference between the two dates, and the .days
attribute gets this difference expressed in days. There is no .months
attribute, so we iterate one day at a time and convert the dates to the desired output format. This yields a lot of duplicates, which the OrderedDict
removes while keeping the items in the right order.
Now this is simple and concise because it lets the datetime module do all the work, but it’s also horribly inefficient. We’re calling a lot of methods for each day while we only need to output months. If performance is not an issue, the above code will be just fine. Otherwise, we’ll have to work a bit more. Let’s compare the above implementation with a more efficient one:
from datetime import datetime, timedelta
from collections import OrderedDict
dates = ["2014-10-10", "2016-01-07"]
def monthlist_short(dates):
start, end = [datetime.strptime(_, "%Y-%m-%d") for _ in dates]
return OrderedDict(((start + timedelta(_)).strftime(r"%b-%y"), None) for _ in xrange((end - start).days)).keys()
def monthlist_fast(dates):
start, end = [datetime.strptime(_, "%Y-%m-%d") for _ in dates]
total_months = lambda dt: dt.month + 12 * dt.year
mlist = []
for tot_m in xrange(total_months(start)-1, total_months(end)):
y, m = divmod(tot_m, 12)
mlist.append(datetime(y, m+1, 1).strftime("%b-%y"))
return mlist
assert monthlist_fast(dates) == monthlist_short(dates)
if __name__ == "__main__":
from timeit import Timer
for func in "monthlist_short", "monthlist_fast":
print func, Timer("%s(dates)" % func, "from __main__ import dates, %s" % func).timeit(1000)
On my laptop, I get the following output:
monthlist_short 2.3209939003
monthlist_fast 0.0774540901184
The concise implementation is about 30 times slower, so I would not recommend it in time-critical applications 🙂
You have to use Calendar and Datetime
import calendar
from datetime import *
date1 = datetime.strptime("2014-10-10", "%Y-%m-%d")
date2 = datetime.strptime("2016-01-07", "%Y-%m-%d")
date1 = date1.replace(day = 1)
date2 = date2.replace(day = 1)
months_str = calendar.month_name
months = []
while date1 < date2:
month = date1.month
year = date1.year
month_str = months_str[month][0:3]
months.append("{0}-{1}".format(month_str,str(year)[-2:]))
next_month = month+1 if month != 12 else 1
next_year = year + 1 if next_month == 1 else year
date1 = date1.replace( month = next_month, year= next_year)
print months
This code returns
['Oct-14', 'Nov-14', 'Dec-14', 'Jan-14', 'Feb-15', 'Mar-15', 'Apr-15', 'May-15', 'Jun-15', 'Jul-15', 'Aug-15', 'Sep-15', 'Oct-15', 'Nov-15', 'Dec-15', 'Jan-15']
Having done similar stuff previously, I took a stab at solving this. Using distinct components for doing this is more flexible and enables you to mix and match them for different use-cases. They also can be tested more easily this way, as you can see by the doctests in iterate_months
.
Also I suggest to use datetime.date
objects for your input as you can just do more with those. To do that you’ll have to first parse your input string, but this is very easily done.
Parsing the date-strings
def datify(date):
if isinstance(date, datetime.date):
return date
elif isinstance(date, datetime.datetime):
return date.date()
else:
# taken from simleo's answer
return datetime.strptime(date, "%Y-%m-%d")
First, we iterate through the months
import datetime
def iterate_months(start_date, end_date):
"""Iterate monthly between two given dates.
Emitted will be the first day of each month.
>>> list(iterate_months(datetime.date(1999, 11, 1),
... datetime.date(2000, 2, 1)))
[datetime.date(1999, 11, 1), datetime.date(1999, 12, 1),
datetime.date(2000, 1, 1), datetime.date(2000, 2, 1)]
"""
assert isinstance(start_date, datetime.date)
assert isinstance(end_date, datetime.date)
assert start_date < end_date
year = start_date.year
month = start_date.month
while True:
current = datetime.date(year, month, 1)
yield current
if current.month == end_date.month and current.year == end_date.year:
break
else:
month = ((month + 1) % 12) or 12
if month == 1:
year += 1
if __name__ == '__main__':
import doctest
doctest.testmod()
To format your dates, use something like this
def format_month(date):
return date.strftime(r"%b-%y")
Putting it all together
start = datify("2014-10-10")
end = datify("2016-01-07")
for entry in iterate_months(start, end):
print format_month(entry)
Or save it as a list:
result = list(iterate_months(start, end))
Here is my solution with a simple list comprehension which uses range
to know where months must start and end
from datetime import datetime as dt
sd = dt.strptime('2014-10-10', "%Y-%m-%d")
ed = dt.strptime('2016-01-07', "%Y-%m-%d")
lst = [dt.strptime('%2.2d-%2.2d' % (y, m), '%Y-%m').strftime('%b-%y')
for y in xrange(sd.year, ed.year+1)
for m in xrange(sd.month if y==sd.year else 1, ed.month+1 if y == ed.year else 13)]
print lst
produces
['Oct-14', 'Nov-14', 'Dec-14', 'Jan-15', 'Feb-15', 'Mar-15', 'Apr-15', 'May-15', 'Jun-15', 'Jul-15', 'Aug-15', 'Sep-15', 'Oct-15', 'Nov-15', 'Dec-15', 'Jan-16']
Find below my approach to this problem using split and simple modulo-based iterations without importing any special module.
date1 = "2014-10-10"
date2 = "2016-01-07"
y0 = int( date1.split('-')[0] ) # 2014
y1 = int( date2.split('-')[0] ) # 2016
m0 = int( date1.split('-')[1] ) - 1 # 10-1 --> 9 because will be used for indexing
m1 = int( date2.split('-')[1] ) - 1 # 01-1 --> 0 because will be used for indexing
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
result = []
start = m0
for y in range(y0, y1+1):
for m in range(start,12):
result.append( str( months[m % 12])+'-'+str(y) )
if y == y1 and (m % 12) == m1:
break
start = 0
print result
$ python dates.py
['Oct-2014', 'Nov-2014', 'Dec-2014', 'Jan-2015', 'Feb-2015', 'Mar-2015', 'Apr-2015', 'May-2015', 'Jun-2015', 'Jul-2015', 'Aug-2015', 'Sep-2015', 'Oct-2015', 'Nov-2015', 'Dec-2015', 'Jan-2016']
I found a very succinct way to do this with Pandas, sharing in case it helps anybody:
UPDATE: I’ve got it down to a one-liner with the help of this post 🙂
pd.date_range('2014-10-10','2016-01-07',
freq='MS').strftime("%Y-%b").tolist()
OLD ANSWER:
daterange = pd.date_range('2014-10-10','2016-01-07' , freq='1M')
daterange = daterange.union([daterange[-1] + 1])
daterange = [d.strftime('%y-%b') for d in daterange]
The second line prevents the last date from getting clipped off the list.
With pandas, you can have a one liner like this:
import pandas as pd
date1 = "2014-10-10" # input start date
date2 = "2016-01-07" # input end date
month_list = [i.strftime("%b-%y") for i in pd.date_range(start=date1, end=date2, freq='MS')]
If you’re interested in keeping your dates in a Python format, you can try using to_pydatetime()
.
import pandas as pd
from datetime import datetime
datemin = datetime(2010, 1, 1)
datemax = datetime(2019, 12, 31)
# First day of month
pd.date_range(datemin, datemax, freq='MS').to_pydatetime().tolist()
# Last day of month
pd.date_range(datemin, datemax, freq='M').to_pydatetime().tolist()
I came to a solution that uses python-dateutil
and works with Python 3.8+:
https://gist.github.com/anatoly-scherbakov/593770d446a06f109438a134863ba969
def month_range(
start: datetime.date,
end: datetime.date,
) -> Iterator[datetime.date]:
"""Yields the 1st day of each month in the given date range."""
yield from itertools.takewhile(
lambda date: date < end,
itertools.accumulate(
itertools.repeat(relativedelta(months=1)),
operator.add,
initial=start,
)
)
here is the similar version of what Pynchia suggestioned, the below implementation is for python 3.8 the one he implemented is for python 2.x
import datetime
st="2020-06-24"
ed="2020-11-24"
start_date = datetime.datetime.strptime(st.strip(), '%Y-%m-%d')
end_date = datetime.datetime.strptime(ed.strip(), '%Y-%m-%d')
months = [datetime.datetime.strptime('%2.2d-%2.2d' % (y, m), '%Y-%m').strftime('%b-%y')
for y in range(start_date.year, end_date.year + 1)
for m in range(start_date.month if y == start_date.year else 1, end_date.month + 1 if y == end_date.year else 13)]
print(months)
If you want a dictionary that contains pair of month’s starting date and ending date between your desired years, then here’s how to get that.
start_year = int(input("Enter Starting Year: "))
end_year = int(input("Enter Ending Year: "))
import calendar
month_dict = {}
for x in range(start_year, end_year):
for y in range(1, 13):
if y < 10:
start_date = '01'+'-'+'0'+str(y)+'-'+str(x)
end_date = str(calendar.monthrange(x, y)[1])+'-'+'0'+str(y)+'-'+str(x)
month_dict[start_date] = end_date
else:
start_date = '01'+'-'+str(y)+'-'+str(x)
end_date = str(calendar.monthrange(x, y)[1])+'-'+str(y)+'-'+str(x)
month_dict[start_date] = end_date
This gives the following output:
{'01-01-2000': '31-01-2000',
'01-02-2000': '29-02-2000',
'01-03-2000': '31-03-2000',
'01-04-2000': '30-04-2000',
'01-05-2000': '31-05-2000',
'01-06-2000': '30-06-2000',
'01-07-2000': '31-07-2000',
'01-08-2000': '31-08-2000',
'01-09-2000': '30-09-2000',
'01-10-2000': '31-10-2000',
'01-11-2000': '30-11-2000',
'01-12-2000': '31-12-2000',
'01-01-2001': '31-01-2001',
'01-02-2001': '28-02-2001',
'01-03-2001': '31-03-2001',
'01-04-2001': '30-04-2001',
'01-05-2001': '31-05-2001',
'01-06-2001': '30-06-2001',
'01-07-2001': '31-07-2001',
'01-08-2001': '31-08-2001',
'01-09-2001': '30-09-2001',
'01-10-2001': '31-10-2001',
'01-11-2001': '30-11-2001',
'01-12-2001': '31-12-2001',
'01-01-2002': '31-01-2002',
'01-02-2002': '28-02-2002',
'01-03-2002': '31-03-2002',
'01-04-2002': '30-04-2002',
'01-05-2002': '31-05-2002',
'01-06-2002': '30-06-2002',
'01-07-2002': '31-07-2002',
'01-08-2002': '31-08-2002',
'01-09-2002': '30-09-2002',
'01-10-2002': '31-10-2002',
'01-11-2002': '30-11-2002',
'01-12-2002': '31-12-2002',
'01-01-2003': '31-01-2003',
'01-02-2003': '28-02-2003',
'01-03-2003': '31-03-2003',
'01-04-2003': '30-04-2003',
'01-05-2003': '31-05-2003',
'01-06-2003': '30-06-2003',
'01-07-2003': '31-07-2003',
'01-08-2003': '31-08-2003',
'01-09-2003': '30-09-2003',
'01-10-2003': '31-10-2003',
'01-11-2003': '30-11-2003',
'01-12-2003': '31-12-2003',
'01-01-2004': '31-01-2004',
'01-02-2004': '29-02-2004',
'01-03-2004': '31-03-2004',
'01-04-2004': '30-04-2004',
'01-05-2004': '31-05-2004',
'01-06-2004': '30-06-2004',
'01-07-2004': '31-07-2004',
'01-08-2004': '31-08-2004',
'01-09-2004': '30-09-2004',
'01-10-2004': '31-10-2004',
'01-11-2004': '30-11-2004',
'01-12-2004': '31-12-2004',
'01-01-2005': '31-01-2005',
'01-02-2005': '28-02-2005',
'01-03-2005': '31-03-2005',
'01-04-2005': '30-04-2005',
'01-05-2005': '31-05-2005',
'01-06-2005': '30-06-2005',
'01-07-2005': '31-07-2005',
'01-08-2005': '31-08-2005',
'01-09-2005': '30-09-2005',
'01-10-2005': '31-10-2005',
'01-11-2005': '30-11-2005',
'01-12-2005': '31-12-2005',
'01-01-2006': '31-01-2006',
'01-02-2006': '28-02-2006',
'01-03-2006': '31-03-2006',
'01-04-2006': '30-04-2006',
'01-05-2006': '31-05-2006',
'01-06-2006': '30-06-2006',
'01-07-2006': '31-07-2006',
'01-08-2006': '31-08-2006',
'01-09-2006': '30-09-2006',
'01-10-2006': '31-10-2006',
'01-11-2006': '30-11-2006',
'01-12-2006': '31-12-2006',
'01-01-2007': '31-01-2007',
'01-02-2007': '28-02-2007',
'01-03-2007': '31-03-2007',
'01-04-2007': '30-04-2007',
'01-05-2007': '31-05-2007',
'01-06-2007': '30-06-2007',
'01-07-2007': '31-07-2007',
'01-08-2007': '31-08-2007',
'01-09-2007': '30-09-2007',
'01-10-2007': '31-10-2007',
'01-11-2007': '30-11-2007',
'01-12-2007': '31-12-2007',
'01-01-2008': '31-01-2008',
'01-02-2008': '29-02-2008',
'01-03-2008': '31-03-2008',
'01-04-2008': '30-04-2008',
'01-05-2008': '31-05-2008',
'01-06-2008': '30-06-2008',
'01-07-2008': '31-07-2008',
'01-08-2008': '31-08-2008',
'01-09-2008': '30-09-2008',
'01-10-2008': '31-10-2008',
'01-11-2008': '30-11-2008',
'01-12-2008': '31-12-2008',
'01-01-2009': '31-01-2009',
'01-02-2009': '28-02-2009',
'01-03-2009': '31-03-2009',
'01-04-2009': '30-04-2009',
'01-05-2009': '31-05-2009',
'01-06-2009': '30-06-2009',
'01-07-2009': '31-07-2009',
'01-08-2009': '31-08-2009',
'01-09-2009': '30-09-2009',
'01-10-2009': '31-10-2009',
'01-11-2009': '30-11-2009',
'01-12-2009': '31-12-2009',
'01-01-2010': '31-01-2010',
'01-02-2010': '28-02-2010',
'01-03-2010': '31-03-2010',
'01-04-2010': '30-04-2010',
'01-05-2010': '31-05-2010',
'01-06-2010': '30-06-2010',
'01-07-2010': '31-07-2010',
'01-08-2010': '31-08-2010',
'01-09-2010': '30-09-2010',
'01-10-2010': '31-10-2010',
'01-11-2010': '30-11-2010',
'01-12-2010': '31-12-2010',
'01-01-2011': '31-01-2011',
'01-02-2011': '28-02-2011',
'01-03-2011': '31-03-2011',
'01-04-2011': '30-04-2011',
'01-05-2011': '31-05-2011',
'01-06-2011': '30-06-2011',
'01-07-2011': '31-07-2011',
'01-08-2011': '31-08-2011',
'01-09-2011': '30-09-2011',
'01-10-2011': '31-10-2011',
'01-11-2011': '30-11-2011',
'01-12-2011': '31-12-2011',
'01-01-2012': '31-01-2012',
'01-02-2012': '29-02-2012',
'01-03-2012': '31-03-2012',
'01-04-2012': '30-04-2012',
'01-05-2012': '31-05-2012',
'01-06-2012': '30-06-2012',
'01-07-2012': '31-07-2012',
'01-08-2012': '31-08-2012',
'01-09-2012': '30-09-2012',
'01-10-2012': '31-10-2012',
'01-11-2012': '30-11-2012',
'01-12-2012': '31-12-2012',
'01-01-2013': '31-01-2013',
'01-02-2013': '28-02-2013',
'01-03-2013': '31-03-2013',
'01-04-2013': '30-04-2013',
'01-05-2013': '31-05-2013',
'01-06-2013': '30-06-2013',
'01-07-2013': '31-07-2013',
'01-08-2013': '31-08-2013',
'01-09-2013': '30-09-2013',
'01-10-2013': '31-10-2013',
'01-11-2013': '30-11-2013',
'01-12-2013': '31-12-2013',
'01-01-2014': '31-01-2014',
'01-02-2014': '28-02-2014',
'01-03-2014': '31-03-2014',
'01-04-2014': '30-04-2014',
'01-05-2014': '31-05-2014',
'01-06-2014': '30-06-2014',
'01-07-2014': '31-07-2014',
'01-08-2014': '31-08-2014',
'01-09-2014': '30-09-2014',
'01-10-2014': '31-10-2014',
'01-11-2014': '30-11-2014',
'01-12-2014': '31-12-2014',
'01-01-2015': '31-01-2015',
'01-02-2015': '28-02-2015',
'01-03-2015': '31-03-2015',
'01-04-2015': '30-04-2015',
'01-05-2015': '31-05-2015',
'01-06-2015': '30-06-2015',
'01-07-2015': '31-07-2015',
'01-08-2015': '31-08-2015',
'01-09-2015': '30-09-2015',
'01-10-2015': '31-10-2015',
'01-11-2015': '30-11-2015',
'01-12-2015': '31-12-2015',
'01-01-2016': '31-01-2016',
'01-02-2016': '29-02-2016',
'01-03-2016': '31-03-2016',
'01-04-2016': '30-04-2016',
'01-05-2016': '31-05-2016',
'01-06-2016': '30-06-2016',
'01-07-2016': '31-07-2016',
'01-08-2016': '31-08-2016',
'01-09-2016': '30-09-2016',
'01-10-2016': '31-10-2016',
'01-11-2016': '30-11-2016',
'01-12-2016': '31-12-2016',
'01-01-2017': '31-01-2017',
'01-02-2017': '28-02-2017',
'01-03-2017': '31-03-2017',
'01-04-2017': '30-04-2017',
'01-05-2017': '31-05-2017',
'01-06-2017': '30-06-2017',
'01-07-2017': '31-07-2017',
'01-08-2017': '31-08-2017',
'01-09-2017': '30-09-2017',
'01-10-2017': '31-10-2017',
'01-11-2017': '30-11-2017',
'01-12-2017': '31-12-2017',
'01-01-2018': '31-01-2018',
'01-02-2018': '28-02-2018',
'01-03-2018': '31-03-2018',
'01-04-2018': '30-04-2018',
'01-05-2018': '31-05-2018',
'01-06-2018': '30-06-2018',
'01-07-2018': '31-07-2018',
'01-08-2018': '31-08-2018',
'01-09-2018': '30-09-2018',
'01-10-2018': '31-10-2018',
'01-11-2018': '30-11-2018',
'01-12-2018': '31-12-2018',
'01-01-2019': '31-01-2019',
'01-02-2019': '28-02-2019',
'01-03-2019': '31-03-2019',
'01-04-2019': '30-04-2019',
'01-05-2019': '31-05-2019',
'01-06-2019': '30-06-2019',
'01-07-2019': '31-07-2019',
'01-08-2019': '31-08-2019',
'01-09-2019': '30-09-2019',
'01-10-2019': '31-10-2019',
'01-11-2019': '30-11-2019',
'01-12-2019': '31-12-2019',
'01-01-2020': '31-01-2020',
'01-02-2020': '29-02-2020',
'01-03-2020': '31-03-2020',
'01-04-2020': '30-04-2020',
'01-05-2020': '31-05-2020',
'01-06-2020': '30-06-2020',
'01-07-2020': '31-07-2020',
'01-08-2020': '31-08-2020',
'01-09-2020': '30-09-2020',
'01-10-2020': '31-10-2020',
'01-11-2020': '30-11-2020',
'01-12-2020': '31-12-2020',
'01-01-2021': '31-01-2021',
'01-02-2021': '28-02-2021',
'01-03-2021': '31-03-2021',
'01-04-2021': '30-04-2021',
'01-05-2021': '31-05-2021',
'01-06-2021': '30-06-2021',
'01-07-2021': '31-07-2021',
'01-08-2021': '31-08-2021',
'01-09-2021': '30-09-2021',
'01-10-2021': '31-10-2021',
'01-11-2021': '30-11-2021',
'01-12-2021': '31-12-2021'}
Try this out, it will list down all the month from start to end as a continuous chain starting from the start date.
import datetime
a='2021-12-1'
b='2022-1-2'
d1=datetime.datetime.strptime(a,'%Y-%m-%d')
d2=datetime.datetime.strptime(b,'%Y-%m-%d')
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
totalmonts=(d2.year-d1.year)*12+d2.month-11+12-d1.month
print(totalmonts)
for i in range(totalmonts):
print(months[(d1.month+i-1)%12])