Skip to content

Commit a232bd4

Browse files
jschendelNo-Stream
authored andcommitted
Make *_range functions consistent (pandas-dev#17482)
1 parent b74f7bf commit a232bd4

14 files changed

+747
-130
lines changed

doc/source/api.rst

+9
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,19 @@ Top-level dealing with datetimelike
218218
to_timedelta
219219
date_range
220220
bdate_range
221+
cdate_range
221222
period_range
222223
timedelta_range
223224
infer_freq
224225

226+
Top-level dealing with intervals
227+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
228+
229+
.. autosummary::
230+
:toctree: generated/
231+
232+
interval_range
233+
225234
Top-level evaluation
226235
~~~~~~~~~~~~~~~~~~~~
227236

doc/source/timeseries.rst

+9
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,15 @@ has multiplied span.
17051705
17061706
pd.PeriodIndex(start='2014-01', freq='3M', periods=4)
17071707
1708+
If ``start`` or ``end`` are ``Period`` objects, they will be used as anchor
1709+
endpoints for a ``PeriodIndex`` with frequency matching that of the
1710+
``PeriodIndex`` constructor.
1711+
1712+
.. ipython:: python
1713+
1714+
pd.PeriodIndex(start=pd.Period('2017Q1', freq='Q'),
1715+
end=pd.Period('2017Q2', freq='Q'), freq='M')
1716+
17081717
Just like ``DatetimeIndex``, a ``PeriodIndex`` can also be used to index pandas
17091718
objects:
17101719

doc/source/whatsnew/v0.21.0.txt

+54-1
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ Furthermore this will now correctly box the results of iteration for :func:`Data
218218
.. ipython:: ipython
219219

220220
d = {'a':[1], 'b':['b']}
221-
df = pd,DataFrame(d)
221+
df = pd.DataFrame(d)
222222

223223
Previously:
224224

@@ -358,6 +358,59 @@ Previously, :func:`to_datetime` did not localize datetime ``Series`` data when `
358358

359359
Additionally, DataFrames with datetime columns that were parsed by :func:`read_sql_table` and :func:`read_sql_query` will also be localized to UTC only if the original SQL columns were timezone aware datetime columns.
360360

361+
.. _whatsnew_0210.api.consistency_of_range_functions:
362+
363+
Consistency of Range Functions
364+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
365+
366+
In previous versions, there were some inconsistencies between the various range functions: func:`date_range`, func:`bdate_range`, func:`cdate_range`, func:`period_range`, func:`timedelta_range`, and func:`interval_range`. (:issue:`17471`).
367+
368+
One of the inconsistent behaviors occurred when the ``start``, ``end`` and ``period`` parameters were all specified, potentially leading to ambiguous ranges. When all three parameters were passed, ``interval_range`` ignored the ``period`` parameter, ``period_range`` ignored the ``end`` parameter, and the other range functions raised. To promote consistency among the range functions, and avoid potentially ambiguous ranges, ``interval_range`` and ``period_range`` will now raise when all three parameters are passed.
369+
370+
Previous Behavior:
371+
372+
.. code-block:: ipython
373+
374+
In [2]: pd.interval_range(start=0, end=4, periods=6)
375+
Out[2]:
376+
IntervalIndex([(0, 1], (1, 2], (2, 3]]
377+
closed='right',
378+
dtype='interval[int64]')
379+
380+
In [3]: pd.period_range(start='2017Q1', end='2017Q4', periods=6, freq='Q')
381+
Out[3]: PeriodIndex(['2017Q1', '2017Q2', '2017Q3', '2017Q4', '2018Q1', '2018Q2'], dtype='period[Q-DEC]', freq='Q-DEC')
382+
383+
New Behavior:
384+
385+
.. code-block:: ipython
386+
387+
In [2]: pd.interval_range(start=0, end=4, periods=6)
388+
---------------------------------------------------------------------------
389+
ValueError: Of the three parameters: start, end, and periods, exactly two must be specified
390+
391+
In [3]: pd.period_range(start='2017Q1', end='2017Q4', periods=6, freq='Q')
392+
---------------------------------------------------------------------------
393+
ValueError: Of the three parameters: start, end, and periods, exactly two must be specified
394+
395+
Additionally, the endpoint parameter ``end`` was not included in the intervals produced by ``interval_range``. However, all other range functions include ``end`` in their output. To promote consistency among the range functions, ``interval_range`` will now include ``end`` as the right endpoint of the final interval, except if ``freq`` is specified in a way which skips ``end``.
396+
397+
Previous Behavior:
398+
399+
.. code-block:: ipython
400+
401+
In [4]: pd.interval_range(start=0, end=4)
402+
Out[4]:
403+
IntervalIndex([(0, 1], (1, 2], (2, 3]]
404+
closed='right',
405+
dtype='interval[int64]')
406+
407+
408+
New Behavior:
409+
410+
.. ipython:: python
411+
412+
pd.interval_range(start=0, end=4)
413+
361414
.. _whatsnew_0210.api:
362415

363416
Other API Changes

pandas/core/indexes/datetimes.py

+31-27
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,8 @@ def __new__(cls, data=None,
292292
if is_float(periods):
293293
periods = int(periods)
294294
elif not is_integer(periods):
295-
raise ValueError('Periods must be a number, got %s' %
296-
str(periods))
295+
msg = 'periods must be a number, got {periods}'
296+
raise TypeError(msg.format(periods=periods))
297297

298298
if data is None and freq is None:
299299
raise ValueError("Must provide freq argument if no data is "
@@ -412,7 +412,8 @@ def __new__(cls, data=None,
412412
def _generate(cls, start, end, periods, name, offset,
413413
tz=None, normalize=False, ambiguous='raise', closed=None):
414414
if com._count_not_none(start, end, periods) != 2:
415-
raise ValueError('Must specify two of start, end, or periods')
415+
raise ValueError('Of the three parameters: start, end, and '
416+
'periods, exactly two must be specified')
416417

417418
_normalized = True
418419

@@ -2004,7 +2005,7 @@ def _generate_regular_range(start, end, periods, offset):
20042005
def date_range(start=None, end=None, periods=None, freq='D', tz=None,
20052006
normalize=False, name=None, closed=None, **kwargs):
20062007
"""
2007-
Return a fixed frequency datetime index, with day (calendar) as the default
2008+
Return a fixed frequency DatetimeIndex, with day (calendar) as the default
20082009
frequency
20092010
20102011
Parameters
@@ -2013,24 +2014,25 @@ def date_range(start=None, end=None, periods=None, freq='D', tz=None,
20132014
Left bound for generating dates
20142015
end : string or datetime-like, default None
20152016
Right bound for generating dates
2016-
periods : integer or None, default None
2017-
If None, must specify start and end
2017+
periods : integer, default None
2018+
Number of periods to generate
20182019
freq : string or DateOffset, default 'D' (calendar daily)
20192020
Frequency strings can have multiples, e.g. '5H'
2020-
tz : string or None
2021+
tz : string, default None
20212022
Time zone name for returning localized DatetimeIndex, for example
20222023
Asia/Hong_Kong
20232024
normalize : bool, default False
20242025
Normalize start/end dates to midnight before generating date range
2025-
name : str, default None
2026-
Name of the resulting index
2027-
closed : string or None, default None
2026+
name : string, default None
2027+
Name of the resulting DatetimeIndex
2028+
closed : string, default None
20282029
Make the interval closed with respect to the given frequency to
20292030
the 'left', 'right', or both sides (None)
20302031
20312032
Notes
20322033
-----
2033-
2 of start, end, or periods must be specified
2034+
Of the three parameters: ``start``, ``end``, and ``periods``, exactly two
2035+
must be specified.
20342036
20352037
To learn more about the frequency strings, please see `this link
20362038
<http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases>`__.
@@ -2047,7 +2049,7 @@ def date_range(start=None, end=None, periods=None, freq='D', tz=None,
20472049
def bdate_range(start=None, end=None, periods=None, freq='B', tz=None,
20482050
normalize=True, name=None, closed=None, **kwargs):
20492051
"""
2050-
Return a fixed frequency datetime index, with business day as the default
2052+
Return a fixed frequency DatetimeIndex, with business day as the default
20512053
frequency
20522054
20532055
Parameters
@@ -2056,24 +2058,25 @@ def bdate_range(start=None, end=None, periods=None, freq='B', tz=None,
20562058
Left bound for generating dates
20572059
end : string or datetime-like, default None
20582060
Right bound for generating dates
2059-
periods : integer or None, default None
2060-
If None, must specify start and end
2061+
periods : integer, default None
2062+
Number of periods to generate
20612063
freq : string or DateOffset, default 'B' (business daily)
20622064
Frequency strings can have multiples, e.g. '5H'
20632065
tz : string or None
20642066
Time zone name for returning localized DatetimeIndex, for example
20652067
Asia/Beijing
20662068
normalize : bool, default False
20672069
Normalize start/end dates to midnight before generating date range
2068-
name : str, default None
2069-
Name for the resulting index
2070-
closed : string or None, default None
2070+
name : string, default None
2071+
Name of the resulting DatetimeIndex
2072+
closed : string, default None
20712073
Make the interval closed with respect to the given frequency to
20722074
the 'left', 'right', or both sides (None)
20732075
20742076
Notes
20752077
-----
2076-
2 of start, end, or periods must be specified
2078+
Of the three parameters: ``start``, ``end``, and ``periods``, exactly two
2079+
must be specified.
20772080
20782081
To learn more about the frequency strings, please see `this link
20792082
<http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases>`__.
@@ -2091,7 +2094,7 @@ def bdate_range(start=None, end=None, periods=None, freq='B', tz=None,
20912094
def cdate_range(start=None, end=None, periods=None, freq='C', tz=None,
20922095
normalize=True, name=None, closed=None, **kwargs):
20932096
"""
2094-
**EXPERIMENTAL** Return a fixed frequency datetime index, with
2097+
**EXPERIMENTAL** Return a fixed frequency DatetimeIndex, with
20952098
CustomBusinessDay as the default frequency
20962099
20972100
.. warning:: EXPERIMENTAL
@@ -2105,29 +2108,30 @@ def cdate_range(start=None, end=None, periods=None, freq='C', tz=None,
21052108
Left bound for generating dates
21062109
end : string or datetime-like, default None
21072110
Right bound for generating dates
2108-
periods : integer or None, default None
2109-
If None, must specify start and end
2111+
periods : integer, default None
2112+
Number of periods to generate
21102113
freq : string or DateOffset, default 'C' (CustomBusinessDay)
21112114
Frequency strings can have multiples, e.g. '5H'
2112-
tz : string or None
2115+
tz : string, default None
21132116
Time zone name for returning localized DatetimeIndex, for example
21142117
Asia/Beijing
21152118
normalize : bool, default False
21162119
Normalize start/end dates to midnight before generating date range
2117-
name : str, default None
2118-
Name for the resulting index
2119-
weekmask : str, Default 'Mon Tue Wed Thu Fri'
2120+
name : string, default None
2121+
Name of the resulting DatetimeIndex
2122+
weekmask : string, Default 'Mon Tue Wed Thu Fri'
21202123
weekmask of valid business days, passed to ``numpy.busdaycalendar``
21212124
holidays : list
21222125
list/array of dates to exclude from the set of valid business days,
21232126
passed to ``numpy.busdaycalendar``
2124-
closed : string or None, default None
2127+
closed : string, default None
21252128
Make the interval closed with respect to the given frequency to
21262129
the 'left', 'right', or both sides (None)
21272130
21282131
Notes
21292132
-----
2130-
2 of start, end, or periods must be specified
2133+
Of the three parameters: ``start``, ``end``, and ``periods``, exactly two
2134+
must be specified.
21312135
21322136
To learn more about the frequency strings, please see `this link
21332137
<http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases>`__.

0 commit comments

Comments
 (0)