12

consider the DateTimeIndex dates

dates = pd.date_range('2016-01-29', periods=4, freq='BM')
dates

DatetimeIndex(['2016-01-29', '2016-02-29', '2016-03-31', '2016-04-29'],
              dtype='datetime64[ns]', freq='BM')

I want to extend the index by one period at the frequency attached to the object.


I expect

pd.date_range('2016-01-29', periods=5, freq='BM')

DatetimeIndex(['2016-01-29', '2016-02-29', '2016-03-31', '2016-04-29',
               '2016-05-31'],
              dtype='datetime64[ns]', freq='BM')

I've tried

dates.append(dates[[-1]] + pd.offsets.BusinessMonthEnd())

However

  • Not generalized to use frequency of dates
  • I get a performance warning

    PerformanceWarning: Non-vectorized DateOffset being applied to Series or DatetimeIndex

piRSquared
  • 285,575
  • 57
  • 475
  • 624

5 Answers5

11

The timestamps in your DatetimeIndex already know that they are describing business month ends, so you can simply add 1:

import pandas as pd
dates = pd.date_range('2016-01-29', periods=4, freq='BM')

print(repr(dates[-1]))
# => Timestamp('2016-04-29 00:00:00', offset='BM')

print(repr(dates[-1] + 1))
# => Timestamp('2016-05-31 00:00:00', offset='BM')

You can add the latter to your index using .union:

dates = dates.union([dates[-1] + 1])
print(dates)
# => DatetimeIndex(['2016-01-29', '2016-02-29', '2016-03-31', '2016-04-29',
#                   '2016-05-31'],
#                  dtype='datetime64[ns]', freq='BM')

Compared to .append, this retains knowledge of the offset.

Alicia Garcia-Raboso
  • 13,193
  • 1
  • 43
  • 48
6

pandas==1.1.1 Answer for +1

To follow up on this, for pandas==1.1.1, I found this to be the best solution:

dates.union(pd.date_range(dates[-1] + dates.freq, periods=1, freq=dates.freq))

Generalised Answer Using n

n=3
dates.union(pd.date_range(dates[-1] + dates.freq, periods=n, freq=dates.freq))

Credits

Taken by combining @alberto-garcia-raboso's answer and @ballpointben's comment.

What Didn't Work

  • The following just got formatted to an Index, not a DateTimeIndex: dates.union([dates[-1] + dates.freq])
  • Also dates[-1] + 1 is deprecated.
dylanmorroll
  • 345
  • 2
  • 12
  • 1
    `+ dates.freq` wasn't working consistently for me, although this worked: `dates.union(pd.date_range(dates[-1], periods=(n + 1), freq=dates.freq)[1:])` – Colin Catlin Aug 02 '21 at 09:13
6

The best solution is:

import pandas as pd
dates = pd.date_range('2016-01-29', periods=4, freq='BM')
extended = dates.union(dates.shift(n)[-n:])

where n is the number of periods you want to add. With n=4, you will get an extended date range like this:

DatetimeIndex(['2016-01-29', '2016-02-29', '2016-03-31', '2016-04-29',
               '2016-05-31', '2016-06-30', '2016-07-29', '2016-08-31'],
              dtype='datetime64[ns]', freq='BM')
fccoelho
  • 6,012
  • 10
  • 55
  • 67
1

try this:

In [207]: dates = dates.append(pd.DatetimeIndex(pd.Series(dates[-1] + pd.offsets.BusinessMonthEnd())))

In [208]: dates
Out[208]: DatetimeIndex(['2016-01-29', '2016-02-29', '2016-03-31', '2016-04-29', '2016-05-31'], dtype='datetime64[ns]', freq=None)

or using list ([...]) instead of pd.Series():

In [211]: dates.append(pd.DatetimeIndex([dates[-1] + pd.offsets.BusinessMonthEnd()]))
Out[211]: DatetimeIndex(['2016-01-29', '2016-02-29', '2016-03-31', '2016-04-29', '2016-05-31'], dtype='datetime64[ns]', freq=None)
MaxU - stand with Ukraine
  • 205,989
  • 36
  • 386
  • 419
1

I'd use the .tshift function and then use accordingly:

dr = pd.date_range(start='1/1/2020', periods=5, freq='D')
df = pd.DataFrame(data=[1,2,3,4,5], 
                  index=dr,
                  columns=['A'])
df.head()
            A
2020-01-01  1
2020-01-02  2
2020-01-03  3
2020-01-04  4
2020-01-05  5 <-

df.tshift()
            A
2020-01-02  1
2020-01-03  2
2020-01-04  3
2020-01-05  4
2020-01-06  5 <-

other = pd.DataFrame([6], columns=['A'], index=[df.tshift().index[-1]])
other.head()
            A
2020-01-06  6

df.append(other)
            A
2020-01-01  1
2020-01-02  2
2020-01-03  3
2020-01-04  4
2020-01-05  5
2020-01-06  6 <-
Mauricio Maroto
  • 119
  • 1
  • 2
  • 11