It is convenient to be able to add one DateOffset to another one:
from pandas.tseries.offsets import DateOffset as DO
DO(hour=2) + DO(hour=3) # raises ValueError
Currently it is not supported. Note that DateOffset
s basically replicates the functionality of relativedelta
s from dateutil
module which support addition
from dateutil.relativedelta import relativedelta as RD
RD(hour=2) + RD(hour=3) # yields relativedelta(hour=3)
Comment From: jreback
In [17]: Timestamp('20130101') + DO(hour=2) + DO(hour=3)
Out[17]: Timestamp('2013-01-01 03:00:00')
These do not form composite objects. I suppose they could, but not sure if it has a useful case as these can operate directly on Series/Timestamps.
@aickley pls show the utility here.
Comment From: 1pakch
This would be useful when 1) offsets are defined at a different place from where there are used and 2) when offsets are defined relative to each other. For instance, currently I have some code conceptually similar to
# Parameters of a study
predictors_window_bdays = 3
predictors_window_end = DateOffset(...) # offset from an event
predictors_window_start = predictors_window_start - DateOffset(bdays=predictors_window_bdays)
# response_window_{bdays,start,end} defined similarly
# The code where the real work is done
# events is a DatetimeIndex()
x = predictors.ix[events+predictors_window_end] - predictors.ix[events+predictors_window_start]
y = response.ix[events+response_window_end] - response.ix[events+response_window_start]
# analyze the relationship between x and y
Now it is not possible to specify predictor_window_end
corresponding to, say, 12:00 of a business day preceding the day of the event (in my view the most intuitive syntax for that would be DateOffset(bdays=-1, hour=12)
as suggested in #10903). Additionally, it is not possible to define predictor_window_start
relative to predictor_window_end
using an intuitive syntax described above.
As a workaround, I am currently storing lists of DateOffset
s that are being applied to the index one after the other.
Comment From: jreback
This is currently not allowed because adding anything to a BusinessDays
(except other business days) is not defined without an absolute reference point. E.g. if you had Timestamp('20130101 11:59:59) + BDay(1) + Second(1)
it is clear what to do.
But if you have BDay(1) + Second()
then these have to be kept (and applied) independently.
So aside from BusinessHours
which I think could be added to a BuisinessDay
I don't think this is really possible.
I'll leave it open for you to provide a reasonable proof-of-concept.
Comment From: jreback
For non-business days I suppose these could be combinable as Timedeltas
are.
e.g.
Day() + Hour()
-> DateOffset(days=1,hours=1)
Comment From: 1pakch
Ok, I understand that BDay
s is not a time unit and hence it's very different from Hour
, Minute
etc. That being said, in principle, DateOffset
can have a bdays
offset independent from the other components. When such an extended DateOffset
is applied to a date the only ambiguity is whether offsetting by business days or usual time units is done first.
Apart from that, combining BDay
with absolute time of the day (BDay() + DateOffset(hour=12, minute=1)
) is a transparent operation which is very useful when looking at intraday financial time series.
BTW, surprisingly enough, now one can combine BDay
and Second
In [33]: delta = BDay() + Second()
In [34]: (pandas.DatetimeIndex(['2015-08-24']) - delta)[0]
Out[34]: Timestamp('2015-08-21 00:00:01')
and the result is different from the direct application
In [35]: (pandas.DatetimeIndex(['2015-08-24']) - BDay() - Second())[0]
Out[35]: Timestamp('2015-08-20 23:59:59')
which is clearly a bug. The same applies to Hour
(I checked) and, I guess, all the other units.
Comment From: chris-b1
@aickley It's not so clear to me that's a bug, because offsets
are not necessarily associative.
The way addition of a delta on BDay works right now is that the offset remains a BusinessDay
- the additional delta is applied at the last step without regard to sign/count on the offset.
E.g:
In [5]: delta = pd.offsets.BDay() + pd.offsets.Hour()
In [6]: delta
Out[6]: <BusinessDay: offset=Timedelta('0 days 01:00:00')>
In [9]: pd.Timestamp('2015-1-1') + delta
Out[9]: Timestamp('2015-01-02 01:00:00')
In [10]: pd.Timestamp('2015-1-1') + 2 * delta
Out[10]: Timestamp('2015-01-05 01:00:00')
In [11]: pd.Timestamp('2015-1-1') - 2 * delta
Out[11]: Timestamp('2014-12-30 01:00:00')
This definition actually makes sense if you think of the delta as an 'anchored' offset - that is, 1:00 on each business day. But it may be less surprising if the sign/count propagated to the additional delta and that maybe could be changed. It is a bit ambiguous / surprising.
In any case, I'm not seeing why you can't just apply multiple offsets
to your data? That would avoid any ambiguity.
Comment From: mroeschke
Yeah I think this has been disallowed specifically as it raises a TypeError now and due to https://github.com/pandas-dev/pandas/issues/10902#issuecomment-135006454 probably not easy to support so closing