Skip to content

ENH: Support multiple opening hours intervals for BusinessHour #26628

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

Merged
merged 14 commits into from
Jun 28, 2019

Conversation

howsiwei
Copy link
Contributor

@howsiwei howsiwei commented Jun 3, 2019

I'm not sure why, but after rebasing on latest master my previous PR #26400 is automatically closed. So I created a new PR here. I have edited as per all the comments there.

@codecov
Copy link

codecov bot commented Jun 3, 2019

Codecov Report

Merging #26628 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master   #26628   +/-   ##
=======================================
  Coverage   91.88%   91.88%           
=======================================
  Files         174      174           
  Lines       50692    50729   +37     
=======================================
+ Hits        46576    46610   +34     
- Misses       4116     4119    +3
Flag Coverage Δ
#multiple 90.41% <100%> (ø) ⬆️
#single 41.83% <33.67%> (-0.06%) ⬇️
Impacted Files Coverage Δ
pandas/tseries/offsets.py 96.87% <100%> (+0.18%) ⬆️
pandas/io/gbq.py 78.94% <0%> (-10.53%) ⬇️
pandas/core/frame.py 97% <0%> (-0.12%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 23b0788...170d08b. Read the comment docs.

@codecov
Copy link

codecov bot commented Jun 3, 2019

Codecov Report

❗ No coverage uploaded for pull request base (master@deffee6). Click here to learn what that means.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master   #26628   +/-   ##
=========================================
  Coverage          ?   91.72%           
=========================================
  Files             ?      178           
  Lines             ?    50808           
  Branches          ?        0           
=========================================
  Hits              ?    46605           
  Misses            ?     4203           
  Partials          ?        0
Flag Coverage Δ
#multiple 90.32% <100%> (?)
#single 41.23% <32.63%> (?)
Impacted Files Coverage Δ
pandas/tseries/offsets.py 96.85% <100%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update deffee6...6b72cea. Read the comment docs.

@WillAyd
Copy link
Member

WillAyd commented Jun 3, 2019

Can you reopen the original PR and push this back there? Would be preferable to maintain comment history

@howsiwei
Copy link
Contributor Author

howsiwei commented Jun 4, 2019

Unfortunately I don't have the permission to reopen PR.

@WillAyd
Copy link
Member

WillAyd commented Jun 4, 2019

Hmm OK. Doesn't look like I can reopen either. Not sure entirely what happened but I do see it was pushed to your master there - would be best practice going forward to not push to master as an FYI

@gfyoung gfyoung added Enhancement Datetime Datetime data dtype labels Jun 5, 2019
@howsiwei
Copy link
Contributor Author

howsiwei commented Jun 5, 2019

@WillAyd thanks for the advice. Any comment on the code changes?

@WillAyd
Copy link
Member

WillAyd commented Jun 5, 2019

cc @gfyoung and @mroeschke who were already looking at original PR

@pep8speaks
Copy link

pep8speaks commented Jun 7, 2019

Hello @howsiwei! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2019-06-28 12:36:49 UTC

@howsiwei howsiwei force-pushed the businesshour branch 2 times, most recently from e3a849e to ec062e0 Compare June 7, 2019 14:13
Copy link
Member

@mroeschke mroeschke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small testing comment otherwise looks pretty good to me.

@@ -82,7 +82,7 @@ Other Enhancements
- :meth:`DataFrame.query` and :meth:`DataFrame.eval` now supports quoting column names with backticks to refer to names with spaces (:issue:`6508`)
- :func:`merge_asof` now gives a more clear error message when merge keys are categoricals that are not equal (:issue:`26136`)
- :meth:`pandas.core.window.Rolling` supports exponential (or Poisson) window type (:issue:`21303`)
-
- :class: `pandas.offsets.BusinessHour` supports multiple opening hours intervals
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No space between :class: and pandas.offsets.BusinessHour. Also can you include the issue number this PR closes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

@@ -579,9 +580,46 @@ class BusinessHourMixin(BusinessMixin):

def __init__(self, start='09:00', end='17:00', offset=timedelta(0)):
# must be validated here to equality check
start = liboffsets._validate_business_time(start)
if _iterable_not_string(start):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use is_list_like

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

raise ValueError('Must include at least 1 start time')
else:
start = np.array([start])
if _iterable_not_string(end):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

blank line before the if

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@@ -579,9 +580,46 @@ class BusinessHourMixin(BusinessMixin):

def __init__(self, start='09:00', end='17:00', offset=timedelta(0)):
# must be validated here to equality check
start = liboffsets._validate_business_time(start)
if _iterable_not_string(start):
start = np.asarray(start)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would do this like

if not is_like_like(start):
    start = [start]
if not len(start):
   raise....

the np.asarray can be done when you validate

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

return True
else:
return False
def _get_daytime_flag(self, start, end):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a doc-string

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this function as it's only use once and I think its clearer to just use start < end.

"""
Return business hours in a day by seconds.
"""
if self._get_daytime_flag:
if self._get_daytime_flag(start, end):
# create dummy datetime to calculate businesshours in a day
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do same as above, only define hour, minute in the clauses

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

bday_remain = result - bday_edge
result = self._next_opening_time(other)
result += bday_remain
while rem != timedelta(0):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add some comments on what you are doing.

can you use more meaningful variable names

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@jreback
Copy link
Contributor

jreback commented Jun 8, 2019

we need to split test_offsets.py as its getting huge (can be after this PR).

cc @pandas-dev/pandas-core

@codecov-io
Copy link

codecov-io commented Jun 11, 2019

Codecov Report

❗ No coverage uploaded for pull request base (master@de22a48). Click here to learn what that means.
The diff coverage is 98.92%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master   #26628   +/-   ##
=========================================
  Coverage          ?   92.04%           
=========================================
  Files             ?      180           
  Lines             ?    50741           
  Branches          ?        0           
=========================================
  Hits              ?    46704           
  Misses            ?     4037           
  Partials          ?        0
Flag Coverage Δ
#multiple 90.68% <98.92%> (?)
#single 41.88% <30.1%> (?)
Impacted Files Coverage Δ
pandas/tseries/offsets.py 96.45% <98.92%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update de22a48...71f82c3. Read the comment docs.

@@ -576,12 +577,50 @@ def onOffset(self, dt):


class BusinessHourMixin(BusinessMixin):
start: List[dt_time]
end: List[dt_time]
n: int
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to suppress the mypy errors:

"BusinessHourMixin" has no attribute "start"
"BusinessHourMixin" has no attribute "end"
"BusinessHourMixin" has no attribute "n"

However this syntax is not compatible with python 3.5...
Any advice?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of typing stuff only compatible with 3.5.2 onwards. It's an issue we need to address but orthogonal to this PR - is this causing some sort of error here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's causing SyntaxError: invalid syntax in python 3.5.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WillAyd any work around for this problem? Or should I just remove the type hintings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WillAyd any suggestions?

Copy link
Member

@WillAyd WillAyd Jun 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to use the “# type: ...” syntax. The way you have it now is unfortunately only available for parameters in function signatures in Python 3.5

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. I have removed the function signatures and it's green now.

@simonjayhawkins simonjayhawkins mentioned this pull request Jun 12, 2019
6 tasks
Copy link
Member

@mroeschke mroeschke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jreback jreback added this to the 0.25.0 milestone Jun 27, 2019
if not len(end):
raise ValueError('Must include at least 1 end time')

vliboffsets = np.vectorize(liboffsets._validate_business_time)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is equivalent to start = np.array([liboffsets._validate_business_time(x) for x in start])? Does the vectorize really make a difference?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes they are equivalent. Is there a preference to use either way?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, @jbrockmendel is more idiomatic here.


Parameters
----------
other : datetime
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this specifically not Timestamp?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it may not be Timestamp.

if st.hour == dt.hour and st.minute == dt.minute:
return dt + timedelta(
seconds=self._get_business_hours_by_sec(st, self.end[i]))
assert False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably this shouldn't be reachable? ValueError?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is not reachable. Previously I raise ValueError here but later removed it following @mroeschke's suggestion #26400 (comment). assert False was added later to prevent mypy error.

@jbrockmendel
Copy link
Member

Minor comments, generally looks good.

@jreback
Copy link
Contributor

jreback commented Jun 28, 2019

@howsiwei small change and can you merge master; ping on green.

@jreback jreback merged commit 7137938 into pandas-dev:master Jun 28, 2019
@jreback
Copy link
Contributor

jreback commented Jun 28, 2019

thanks @howsiwei nice patch!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Datetime Datetime data dtype Enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ENH: BusinessHour to support multiple opening and closing times per day
8 participants