Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate list of months between interval in python

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 
like image 654
Birlla Avatar asked Jan 20 '16 11:01

Birlla


People also ask

How do you calculate months between two dates in pandas?

Use df. dates1-df. dates2 to find the difference between the two dates and then convert the result in the form of months.


2 Answers

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.

like image 90
atkat12 Avatar answered Nov 11 '22 06:11

atkat12


>>> 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 :)

like image 21
simleo Avatar answered Nov 11 '22 05:11

simleo