Skip to content

Commit afafe3b

Browse files
committed
update docs / tests
1 parent ba78fe8 commit afafe3b

File tree

4 files changed

+121
-76
lines changed

4 files changed

+121
-76
lines changed

doc/source/timeseries.rst

+18
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,24 @@ These *work*, but the results may be unexpected.
276276

277277
Epoch times will be rounded to the nearest nanosecond.
278278

279+
Using the Origin Parameter
280+
~~~~~~~~~~~~~~~~~~~~~~~~~~
281+
282+
.. versionadded:: 0.20.0
283+
284+
Using the ``origin`` parameter, one can specify an alternative starting point for creation
285+
of a ``DatetimeIndex``.
286+
287+
.. ipython:: python
288+
289+
pd.to_datetime([1, 2, 3], unit='D', origin=pd.Timestamp('1960-01-01'))
290+
291+
The default is set at ``origin='epoch'``, which defaults to ``1970-01-01 00:00:00``.
292+
293+
.. ipython:: python
294+
295+
pd.to_datetime([1, 2, 3], unit='D')
296+
279297
.. _timeseries.daterange:
280298

281299
Generating Ranges of Timestamps

doc/source/whatsnew/v0.20.0.txt

+9-4
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,21 @@ fixed-width text files, and :func:`read_excel` for parsing Excel files.
5656

5757
.. _whatsnew_0120.enhancements.datetime_origin:
5858

59-
to_datetime can be used with Offset
60-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
59+
to_datetime has gained an origin parameter
60+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
61+
6162
``pd.to_datetime`` has gained a new parameter, ``origin``, to define an offset
6263
from where to compute the resulting ``DatetimeIndex``. (:issue:`11276`, :issue:`11745`)
6364

6465
.. ipython:: python
6566

66-
to_datetime([1,2,3], unit='D', origin=pd.Timestamp('1960-01-01'))
67+
pd.to_datetime([1, 2, 3], unit='D', origin=pd.Timestamp('1960-01-01'))
68+
69+
The default is set at ``origin='epoch'``, which defaults to ``1970-01-01 00:00:00``.
70+
71+
.. ipython:: python
6772

68-
The above code would return days with offset from origin as defined by timestamp set by origin.
73+
pd.to_datetime([1, 2, 3], unit='D')
6974

7075
.. _whatsnew_0200.enhancements.groupby_access:
7176

pandas/tests/indexes/datetimes/test_tools.py

+61-38
Original file line numberDiff line numberDiff line change
@@ -1517,45 +1517,68 @@ def test_normalize_date():
15171517
assert (result == datetime(2012, 9, 7))
15181518

15191519

1520-
def test_to_datetime_origin():
1521-
units = ['D', 's', 'ms', 'us', 'ns']
1522-
# gh-11276, gh-11745
1523-
# for origin as julian
1524-
1525-
julian_dates = pd.date_range(
1526-
'2014-1-1', periods=10).to_julian_date().values
1527-
result = Series(pd.to_datetime(
1528-
julian_dates, unit='D', origin='julian'))
1529-
expected = Series(pd.to_datetime(
1530-
julian_dates - pd.Timestamp(0).to_julian_date(), unit='D'))
1531-
assert_series_equal(result, expected)
1532-
1533-
# checking for invalid combination of origin='julian' and unit != D
1534-
for unit in units:
1535-
if unit == 'D':
1536-
continue
1537-
with pytest.raises(ValueError):
1538-
pd.to_datetime(julian_dates, unit=unit, origin='julian')
1520+
@pytest.fixture(params=['D', 's', 'ms', 'us', 'ns'])
1521+
def units(request):
1522+
return request.param
1523+
15391524

1525+
@pytest.fixture
1526+
def epoch_1960():
15401527
# for origin as 1960-01-01
1541-
epoch_1960 = pd.Timestamp('1960-01-01')
1542-
epoch_timestamp_convertible = [epoch_1960, epoch_1960.to_datetime(),
1543-
epoch_1960.to_datetime64(),
1544-
str(epoch_1960)]
1545-
invalid_origins = ['random_string', '13-24-1990', '0001-01-01']
1546-
units_from_epoch = [0, 1, 2, 3, 4]
1547-
1548-
for unit in units:
1549-
for epoch in epoch_timestamp_convertible:
1550-
expected = Series(
1551-
[pd.Timedelta(x, unit=unit) +
1552-
epoch_1960 for x in units_from_epoch])
1553-
result = Series(pd.to_datetime(
1554-
units_from_epoch, unit=unit, origin=epoch))
1555-
assert_series_equal(result, expected)
1528+
return Timestamp('1960-01-01')
1529+
1530+
1531+
@pytest.fixture
1532+
def units_from_epochs():
1533+
return list(range(5))
1534+
1535+
1536+
@pytest.fixture(params=[epoch_1960(), epoch_1960().to_datetime(),
1537+
epoch_1960().to_datetime64(),
1538+
str(epoch_1960())])
1539+
def epochs(request):
1540+
return request.param
1541+
1542+
1543+
@pytest.fixture
1544+
def julian_dates():
1545+
return pd.date_range('2014-1-1', periods=10).to_julian_date().values
1546+
1547+
1548+
class TestOrigin(object):
15561549

1557-
# check for invalid origins
1558-
for origin in invalid_origins:
1550+
def test_to_basic(self, julian_dates):
1551+
# gh-11276, gh-11745
1552+
# for origin as julian
1553+
1554+
result = Series(pd.to_datetime(
1555+
julian_dates, unit='D', origin='julian'))
1556+
expected = Series(pd.to_datetime(
1557+
julian_dates - pd.Timestamp(0).to_julian_date(), unit='D'))
1558+
assert_series_equal(result, expected)
1559+
1560+
def test_invalid_unit(self, units, julian_dates):
1561+
1562+
# checking for invalid combination of origin='julian' and unit != D
1563+
if units != 'D':
15591564
with pytest.raises(ValueError):
1560-
pd.to_datetime(units_from_epoch, unit=unit,
1561-
origin=origin)
1565+
pd.to_datetime(julian_dates, unit=units, origin='julian')
1566+
1567+
def test_epoch(self, units, epochs, epoch_1960, units_from_epochs):
1568+
1569+
expected = Series(
1570+
[pd.Timedelta(x, unit=units) +
1571+
epoch_1960 for x in units_from_epochs])
1572+
result = Series(pd.to_datetime(
1573+
units_from_epochs, unit=units, origin=epochs))
1574+
assert_series_equal(result, expected)
1575+
1576+
@pytest.mark.parametrize("origin",
1577+
['random_string',
1578+
'13-24-1990',
1579+
'0001-01-01'])
1580+
def test_invalid_origins(self, origin, units, units_from_epochs):
1581+
1582+
with pytest.raises(ValueError):
1583+
pd.to_datetime(units_from_epochs, unit=units,
1584+
origin=origin)

pandas/tseries/tools.py

+33-34
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def _guess_datetime_format_for_array(arr, **kwargs):
176176

177177

178178
def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False,
179-
utc=None, box=True, format=None, exact=True, coerce=None,
179+
utc=None, box=True, format=None, exact=True,
180180
unit=None, infer_datetime_format=False, origin='epoch'):
181181
"""
182182
Convert argument to datetime.
@@ -248,7 +248,7 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False,
248248
- If Timestamp convertible, origin is set to Timestamp identified by
249249
origin.
250250
251-
.. versionadded: 0.19.0
251+
.. versionadded: 0.20.0
252252
253253
Returns
254254
-------
@@ -311,7 +311,6 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False,
311311
1 loop, best of 3: 471 ms per loop
312312
313313
Using non-epoch origins to parse date
314-
315314
>>> pd.to_datetime([1,2,3], unit='D', origin=pd.Timestamp('1960-01-01'))
316315
0 1960-01-02
317316
1 1960-01-03
@@ -428,42 +427,42 @@ def _convert_listlike(arg, box, format, name=None, tz=tz):
428427
except (ValueError, TypeError):
429428
raise e
430429

431-
def intermediate_result(arg):
432-
if origin == 'julian':
433-
if unit != 'D':
434-
raise ValueError("unit must be 'D' for origin='julian'")
435-
try:
436-
arg = arg - tslib.Timestamp(0).to_julian_date()
437-
except:
438-
raise ValueError("incompatible 'arg' type for given "
439-
"'origin'='julian'")
440-
if arg is None:
441-
return arg
442-
elif isinstance(arg, tslib.Timestamp):
443-
return arg
444-
elif isinstance(arg, ABCSeries):
445-
from pandas import Series
446-
values = _convert_listlike(arg._values, False, format)
447-
return Series(values, index=arg.index, name=arg.name)
448-
elif isinstance(arg, (ABCDataFrame, MutableMapping)):
449-
return _assemble_from_unit_mappings(arg, errors=errors)
450-
elif isinstance(arg, ABCIndexClass):
451-
return _convert_listlike(arg, box, format, name=arg.name)
452-
elif is_list_like(arg):
453-
return _convert_listlike(arg, box, format)
454-
return _convert_listlike(np.array([arg]), box, format)[0]
455-
456-
result = intermediate_result(arg)
457-
458-
offset = None
430+
# perform the conversion
431+
if origin == 'julian':
432+
if unit != 'D':
433+
raise ValueError("unit must be 'D' for origin='julian'")
434+
try:
435+
arg = arg - tslib.Timestamp(0).to_julian_date()
436+
except:
437+
raise ValueError("incompatible 'arg' type for given "
438+
"'origin'='julian'")
439+
if arg is None:
440+
result = arg
441+
elif isinstance(arg, tslib.Timestamp):
442+
result = arg
443+
elif isinstance(arg, ABCSeries):
444+
from pandas import Series
445+
values = _convert_listlike(arg._values, False, format)
446+
result = Series(values, index=arg.index, name=arg.name)
447+
elif isinstance(arg, (ABCDataFrame, MutableMapping)):
448+
result = _assemble_from_unit_mappings(arg, errors=errors)
449+
elif isinstance(arg, ABCIndexClass):
450+
result = _convert_listlike(arg, box, format, name=arg.name)
451+
elif is_list_like(arg):
452+
result = _convert_listlike(arg, box, format)
453+
else:
454+
result = _convert_listlike(np.array([arg]), box, format)[0]
455+
456+
# handle origin
459457
if origin not in ['epoch', 'julian']:
460458
try:
461459
offset = tslib.Timestamp(origin) - tslib.Timestamp(0)
462460
except ValueError:
463-
raise ValueError("Invalid 'origin' or 'origin' Out of Bound")
461+
raise ValueError("Invalid 'origin' or 'origin' Out of Bounds")
462+
463+
if offset is not None:
464+
result = result + offset
464465

465-
if offset is not None:
466-
result = result + offset
467466
return result
468467

469468

0 commit comments

Comments
 (0)