Skip to content

BDay offset behaviour vs docs & implementation #10978

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
devqinves opened this issue Sep 3, 2015 · 8 comments
Open

BDay offset behaviour vs docs & implementation #10978

devqinves opened this issue Sep 3, 2015 · 8 comments
Labels

Comments

@devqinves
Copy link

apologies if this has already been raised but couldn't find an answer.

from the docs :

DateOffsets can be created to move dates forward a given number of valid dates. For example, Bday(2) can be added to a date to move it two business days forward. If the date does not start on a valid date, first it is moved to a valid date.

pd.Timestamp('20150830')+BDay(0) == pd.Timestamp('20150830')+BDay(1) is True

it doesn't move it first to a valid date and the code seem to confirm that. not sure what's the intended behaviour here but would be great to clarify. thanks in advance.

@jreback
Copy link
Contributor

jreback commented Sep 3, 2015

The doc-string of DateOffset is pretty clear on this. The 0th day is defined to rollforward.

In [2]: pd.offsets.DateOffset?
Init signature: pd.offsets.DateOffset(self, n=1, normalize=False, **kwds)
Docstring:
Standard kind of date increment used for a date range.

Works exactly like relativedelta in terms of the keyword args you
pass in, use of the keyword n is discouraged-- you would be better
off specifying n in the keywords you use, but regardless it is
there for you. n is needed for DateOffset subclasses.

DateOffets work as follows.  Each offset specify a set of dates
that conform to the DateOffset.  For example, Bday defines this
set to be the set of dates that are weekdays (M-F).  To test if a
date is in the set of a DateOffset dateOffset we can use the
onOffset method: dateOffset.onOffset(date).

If a date is not on a valid date, the rollback and rollforward
methods can be used to roll the date to the nearest valid date
before/after the date.

DateOffsets can be created to move dates forward a given number of
valid dates.  For example, Bday(2) can be added to a date to move
it two business days forward.  If the date does not start on a
valid date, first it is moved to a valid date.  Thus psedo code
is:

def __add__(date):
  date = rollback(date) # does nothing if date is valid
  return date + <n number of periods>

When a date offset is created for a negitive number of periods,
the date is first rolled forward.  The pseudo code is:

def __add__(date):
  date = rollforward(date) # does nothing is date is valid
  return date + <n number of periods>

Zero presents a problem.  Should it roll forward or back?  We
arbitrarily have it rollforward:

date + BDay(0) == BDay.rollforward(date)

Since 0 is a bit weird, we suggest avoiding its use.
File:           ~/pandas/pandas/tseries/offsets.py
Type:           type

@devqinves
Copy link
Author

the problem is not with 0th day but with 1th and this is the part of the doc that is confusing : If the date does not start on a valid date, first it is moved to a valid date. so you would expect to have

pd.Timestamp('20150830')+BDay(1) to add 1 BD after its moved to a valid BD and its not.

@jreback
Copy link
Contributor

jreback commented Sep 3, 2015

this has been this way for quite some time, eg.. I think since this was written.

so BDay(0) == BDay(1) if the anchor is not a business day.

will reopen for some comments

cc @sinhrks
cc @chris-b1
cc @cancan101

@jreback jreback reopened this Sep 3, 2015
@jreback jreback added the Needs Discussion Requires discussion from core team before further action label Sep 3, 2015
@chris-b1
Copy link
Contributor

chris-b1 commented Sep 3, 2015

It's kind of inconsistent with the Period behavior e,g:

In [59]: d = pd.Timestamp('20150830')

In [61]: (d.to_period('B') + 1).to_timestamp()
Out[61]: Timestamp('2015-09-01 00:00:00')

In [64]: (d + BDay(1))
Out[64]: Timestamp('2015-08-31 00:00:00')

But I also feel like the ship may have sailed - I believe all of the other anchored offsets work like this too:

 In [66]: d + pd.offsets.MonthEnd(1)
 Out[66]: Timestamp('2015-08-31 00:00:00')

@jreback jreback removed the Docs label Sep 3, 2015
@jreback
Copy link
Contributor

jreback commented Sep 3, 2015

the period transform is more like:

In [5]: (d+pd.offsets.BDay(0)) + pd.offsets.BDay(1) 
Out[5]: Timestamp('2015-09-01 00:00:00')

so actually ok with that. I think this could use some docs expanding on exactly this.

@sinhrks
Copy link
Member

sinhrks commented Sep 3, 2015

It is related to #10575, whether business day should implicitly anchor to the next valid date. CC @MaximilianR

@max-sixty
Copy link
Contributor

As far as the Period implementation goes: I find it unintuitive on gaps. If you ask for the business day and pass in a Sunday, do you really want Monday?
#10575

@max-sixty
Copy link
Contributor

OK, we crossed there @sinhrks. Great minds think alike (but fools seldom differ?)

@mroeschke mroeschke added the Docs label Jun 28, 2020
@mroeschke mroeschke removed the Needs Discussion Requires discussion from core team before further action label Apr 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants