4

I want to get a date-range where every month day are the same that is in the starting date, e.g if the starting date is 2018-05-16, I want to get ['2018-09-15, 2018-10-15,...]

I have the following code in Python3:

(pd.date_range(start=date, periods=12, freq='M') \
+ pd.DateOffset(days=datetime.strptime(date, '%Y-%m-%d').day)).strftime('%d-%m-%Y')

It work fine when the day of the month is less than 29, e.g the date = '2018-08-31' outputs:

 array(['01-10-2018', '31-10-2018', '01-12-2018',
'31-12-2018', '31-01-2019', '03-03-2019', 
'31-03-2019', '01-05-2019', '31-05-2019', 
'01-07-2019', '31-07-2019', '31-08-2019'], dtype='|S10')

However, I want the output to be:

array(['30-09-2018', '31-10-2018', '30-11-2018', 
'31-12-2018', '31-01-2019', '28-02-2019', 
'31-03-2019', '30-04-2019', '31-05-2019', 
'30-06-2019', '31-07-2019', '31-08-2019'], dtype='|S10')
mloning
  • 825
  • 7
  • 18
McNulty
  • 57
  • 1
  • 6
  • So you want to get the last day of the month starting from the month after the currect one? – Shaido Aug 15 '18 at 09:24
  • 1
    Sa'haido, I want to get every month the same month day of the starting date, unless the corresponding month don't have such day. E.g. if the starting month day is 30 I want every month day 30, except in Febraury that I want 28 or 29 in leap years. – McNulty Aug 15 '18 at 19:07
  • @McNulty, please edit your question to reflect what you just said in the comment, this wasn't clear! – mloning Aug 16 '18 at 08:08
  • @McNulty, please also check my updated answer below! I hope this gives you what you're looking for! – mloning Aug 16 '18 at 16:53

2 Answers2

2

Updated answer:

For a range of dates with monthly frequency on a specific day of month given in the start date (or the last feasible day of the month, accounting for different numbers of days of months and leap years), this function should work, at least for monthly frequencies:

import pandas as pd

def month_range_day(start=None, periods=None):
    start_date = pd.Timestamp(start).date()
    month_range = pd.date_range(start=start_date, periods=periods, freq='M')
    month_day = month_range.day.values
    month_day[start_date.day < month_day] = start_date.day
    return pd.to_datetime(month_range.year*10000+month_range.month*100+month_day, format='%Y%m%d')

Example 1:

start_date = '2020-01-31'
month_range_day(start=start_date, periods=12)

Output:

DatetimeIndex(['2020-01-31', '2020-02-29', '2020-03-31', '2020-04-30',
               '2020-05-31', '2020-06-30', '2020-07-31', '2020-08-31',
               '2020-09-30', '2020-10-31', '2020-11-30', '2020-12-31'],
              dtype='datetime64[ns]', freq=None) 

Example 2:

start_date = '2019-01-29'
month_range_day(start=start_date, periods=12)

Output:

DatetimeIndex(['2019-01-29', '2019-02-28', '2019-03-29', '2019-04-29',
               '2019-05-29', '2019-06-29', '2019-07-29', '2019-08-29',
               '2019-09-29', '2019-10-29', '2019-11-29', '2019-12-29'],
              dtype='datetime64[ns]', freq=None)

Previous Answer:

Assuming that you simply want the end-of-month frequencies, there is no need to use pd.DateOffset:

import pandas as pd
start_date = '2018-09-01'
pd.date_range(start=start_date, periods=12, freq='M').strftime('%d-%m-%Y')

Output:

Index(['30-09-2018', '31-10-2018', '30-11-2018', '31-12-2018', '31-01-2019',
       '28-02-2019', '31-03-2019', '30-04-2019', '31-05-2019', '30-06-2019',
       '31-07-2019', '31-08-2019'],
      dtype='object')

For more details, have a look at the offset aliases in pandas. Changing the data format and type, if necessary, should be straight forward from here.

mloning
  • 825
  • 7
  • 18
  • Thanks mloning for your time. But that I want is to get every month exactly the same month day as I use in the start date, only if the corresponding month no have such day I want the end of month day. E.g. if the start date is '2018-08-29' the output I am trying to get is: ['29-09-2018', '29-10-2011', ...., '28-02-2018', ...., '29-08-2018']. I am sorry for my english. – McNulty Aug 15 '18 at 18:58
  • Thank you very much for your time, mloning. Your code solves my problem, exactly as I wanted. – McNulty Aug 16 '18 at 20:55
  • @McNulty, great! Please accept the answer then. – mloning Aug 17 '18 at 06:01
0

Why don't just remove the 0th element?

date = '2018-08-31'
(pd.date_range(
    start = date,
    periods = 12+1,
    freq ='M')
).strftime('%d-%m-%Y')[1:]

Output:

Index(['30-09-2018', '31-10-2018', '30-11-2018', '31-12-2018', '31-01-2019',
       '28-02-2019', '31-03-2019', '30-04-2019', '31-05-2019', '30-06-2019',
       '31-07-2019', '31-08-2019'],
  dtype='object')
Dmitry Mottl
  • 842
  • 10
  • 17
  • This does not seem to contribute anything new and is rather confusing, as you simply move the start date one month backwards and then select all monthly frequencies without the first one. – mloning Aug 15 '18 at 16:18
  • Thanks, Dmitry Mottl, for your answer and your time. I am no trying to get the end of month day see my comment above. – McNulty Aug 15 '18 at 18:54