Skip to content

Commit c31e541

Browse files
committed
DEPR: Deprecate generic timestamp dtypes
We only use the nanosecond frequency, and numpy doesn't even handle generic timestamp dtypes well. xref gh-15524 (comment).
1 parent cd35d22 commit c31e541

File tree

4 files changed

+80
-2
lines changed

4 files changed

+80
-2
lines changed

doc/source/whatsnew/v0.20.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,7 @@ Deprecations
12041204
- ``SparseArray.to_dense()`` has deprecated the ``fill`` parameter, as that parameter was not being respected (:issue:`14647`)
12051205
- ``SparseSeries.to_dense()`` has deprecated the ``sparse_only`` parameter (:issue:`14647`)
12061206
- ``Series.repeat()`` has deprecated the ``reps`` parameter in favor of ``repeats`` (:issue:`12662`)
1207+
- The ``Series`` constructor and ``.astype`` method have deprecated accepting timestamp dtypes without a frequency (e.g. ``np.datetime64``) for the ``dtype`` parameter (:issue:`15524`)
12071208
- ``Index.repeat()`` and ``MultiIndex.repeat()`` have deprecated the ``n`` parameter in favor of ``repeats`` (:issue:`12662`)
12081209
- ``Categorical.searchsorted()`` and ``Series.searchsorted()`` have deprecated the ``v`` parameter in favor of ``value`` (:issue:`12662`)
12091210
- ``TimedeltaIndex.searchsorted()``, ``DatetimeIndex.searchsorted()``, and ``PeriodIndex.searchsorted()`` have deprecated the ``key`` parameter in favor of ``value`` (:issue:`12662`)

pandas/tests/series/test_constructors.py

+24
Original file line numberDiff line numberDiff line change
@@ -839,3 +839,27 @@ def test_constructor_cast_object(self):
839839
s = Series(date_range('1/1/2000', periods=10), dtype=object)
840840
exp = Series(date_range('1/1/2000', periods=10))
841841
tm.assert_series_equal(s, exp)
842+
843+
def test_constructor_generic_timestamp(self):
844+
# see gh-15524
845+
dtype = np.timedelta64
846+
s = Series([], dtype=dtype)
847+
848+
assert s.empty
849+
assert s.dtype == 'm8[ns]'
850+
851+
dtype = np.datetime64
852+
s = Series([], dtype=dtype)
853+
854+
assert s.empty
855+
assert s.dtype == 'M8[ns]'
856+
857+
# These timestamps have the wrong frequencies,
858+
# so an Exception should be raised now.
859+
msg = "cannot convert timedeltalike"
860+
with tm.assertRaisesRegexp(TypeError, msg):
861+
Series([], dtype='m8[ps]')
862+
863+
msg = "cannot convert datetimelike"
864+
with tm.assertRaisesRegexp(TypeError, msg):
865+
Series([], dtype='M8[ps]')

pandas/tests/series/test_dtypes.py

+32
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,38 @@ def test_astype_dict(self):
153153
self.assertRaises(KeyError, s.astype, {'abc': str, 'def': str})
154154
self.assertRaises(KeyError, s.astype, {0: str})
155155

156+
def test_astype_generic_timestamp(self):
157+
# see gh-15524
158+
data = [1]
159+
160+
s = Series(data)
161+
dtype = np.datetime64
162+
result = s.astype(dtype)
163+
expected = Series(data, dtype=dtype)
164+
assert_series_equal(result, expected)
165+
166+
s = Series(data)
167+
dtype = np.timedelta64
168+
result = s.astype(dtype)
169+
expected = Series(data, dtype=dtype)
170+
assert_series_equal(result, expected)
171+
172+
def test_astype_empty_constructor_equality(self):
173+
# see gh-15524
174+
175+
for dtype in np.typecodes['All']:
176+
if dtype not in ('S', 'V'): # poor support (if any) currently
177+
init_empty = Series([], dtype=dtype)
178+
astype_empty = Series([]).astype(dtype)
179+
180+
try:
181+
assert_series_equal(init_empty, astype_empty)
182+
except AssertionError as e:
183+
name = np.dtype(dtype).name
184+
msg = "{dtype} failed: ".format(dtype=name) + str(e)
185+
186+
raise AssertionError(msg)
187+
156188
def test_complexx(self):
157189
# GH4819
158190
# complex access for ndarray compat

pandas/types/cast.py

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
""" routings for casting """
22

33
from datetime import datetime, timedelta
4+
45
import numpy as np
6+
import warnings
7+
58
from pandas._libs import tslib, lib
69
from pandas._libs.tslib import iNaT
710
from pandas.compat import string_types, text_type, PY3
@@ -620,6 +623,14 @@ def astype_nansafe(arr, dtype, copy=True):
620623
# work around NumPy brokenness, #1987
621624
return lib.astype_intsafe(arr.ravel(), dtype).reshape(arr.shape)
622625

626+
if dtype.name in ("datetime64", "timedelta64"):
627+
msg = ("Passing in '{dtype}' dtype with no frequency is "
628+
"deprecated and will raise in a future version. "
629+
"Please pass in '{dtype}[ns]' instead.")
630+
warnings.warn(msg.format(dtype=dtype.name),
631+
FutureWarning, stacklevel=2)
632+
dtype = np.dtype(dtype.name + "[ns]")
633+
623634
if copy:
624635
return arr.astype(dtype)
625636
return arr.view(dtype)
@@ -871,8 +882,15 @@ def maybe_cast_to_datetime(value, dtype, errors='raise'):
871882
if is_datetime64 or is_datetime64tz or is_timedelta64:
872883

873884
# force the dtype if needed
885+
msg = ("Passing in '{dtype}' dtype with no frequency is "
886+
"deprecated and will raise in a future version. "
887+
"Please pass in '{dtype}[ns]' instead.")
888+
874889
if is_datetime64 and not is_dtype_equal(dtype, _NS_DTYPE):
875-
if dtype.name == 'datetime64[ns]':
890+
if dtype.name in ('datetime64', 'datetime64[ns]'):
891+
if dtype.name == 'datetime64':
892+
warnings.warn(msg.format(dtype=dtype.name),
893+
FutureWarning, stacklevel=2)
876894
dtype = _NS_DTYPE
877895
else:
878896
raise TypeError("cannot convert datetimelike to "
@@ -886,7 +904,10 @@ def maybe_cast_to_datetime(value, dtype, errors='raise'):
886904
value = [value]
887905

888906
elif is_timedelta64 and not is_dtype_equal(dtype, _TD_DTYPE):
889-
if dtype.name == 'timedelta64[ns]':
907+
if dtype.name in ('timedelta64', 'timedelta64[ns]'):
908+
if dtype.name == 'timedelta64':
909+
warnings.warn(msg.format(dtype=dtype.name),
910+
FutureWarning, stacklevel=2)
890911
dtype = _TD_DTYPE
891912
else:
892913
raise TypeError("cannot convert timedeltalike to "

0 commit comments

Comments
 (0)