diff --git a/doc/source/whatsnew/v0.19.0.txt b/doc/source/whatsnew/v0.19.0.txt index 411b2b0abaf5a..72767ba5c4ffd 100644 --- a/doc/source/whatsnew/v0.19.0.txt +++ b/doc/source/whatsnew/v0.19.0.txt @@ -952,6 +952,7 @@ Bug Fixes - Bug in ``DatetimeIndex`` with nanosecond frequency does not include timestamp specified with ``end`` (:issue:`13672`) - Bug in ``Index`` raises ``OutOfBoundsDatetime`` if ``datetime`` exceeds ``datetime64[ns]`` bounds, rather than coercing to ``object`` dtype (:issue:`13663`) +- Bug in ``Index`` may ignores specified ``datetime64`` or ``timedelta64`` ``dtype`` (:issue:`13981`) - Bug in ``RangeIndex`` can be created without no arguments rather than raises ``TypeError`` (:issue:`13793`) - Bug in ``.value_counts`` raises ``OutOfBoundsDatetime`` if data exceeds ``datetime64[ns]`` bounds (:issue:`13663`) - Bug in ``DatetimeIndex`` may raise ``OutOfBoundsDatetime`` if input ``np.datetime64`` has other unit than ``ns`` (:issue:`9114`) diff --git a/pandas/indexes/base.py b/pandas/indexes/base.py index de7780d25b1e5..b638e61d8eebe 100644 --- a/pandas/indexes/base.py +++ b/pandas/indexes/base.py @@ -19,7 +19,6 @@ from pandas.types.missing import isnull, array_equivalent from pandas.types.common import (_ensure_int64, _ensure_object, _ensure_platform_int, - is_datetimetz, is_integer, is_float, is_dtype_equal, @@ -27,6 +26,8 @@ is_categorical_dtype, is_bool_dtype, is_integer_dtype, is_float_dtype, + is_datetime64_any_dtype, + is_timedelta64_dtype, needs_i8_conversion, is_iterator, is_list_like, is_scalar) @@ -162,16 +163,19 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None, # index-like elif isinstance(data, (np.ndarray, Index, ABCSeries)): - if (issubclass(data.dtype.type, np.datetime64) or - is_datetimetz(data)): + if (is_datetime64_any_dtype(data) or + (dtype is not None and is_datetime64_any_dtype(dtype)) or + 'tz' in kwargs): from pandas.tseries.index import DatetimeIndex - result = DatetimeIndex(data, copy=copy, name=name, **kwargs) - if dtype is not None and _o_dtype == dtype: + result = DatetimeIndex(data, copy=copy, name=name, + dtype=dtype, **kwargs) + if dtype is not None and is_dtype_equal(_o_dtype, dtype): return Index(result.to_pydatetime(), dtype=_o_dtype) else: return result - elif issubclass(data.dtype.type, np.timedelta64): + elif (is_timedelta64_dtype(data) or + (dtype is not None and is_timedelta64_dtype(dtype))): from pandas.tseries.tdi import TimedeltaIndex result = TimedeltaIndex(data, copy=copy, name=name, **kwargs) if dtype is not None and _o_dtype == dtype: diff --git a/pandas/indexes/multi.py b/pandas/indexes/multi.py index 95ef18d23a037..cc279076f7a5e 100644 --- a/pandas/indexes/multi.py +++ b/pandas/indexes/multi.py @@ -687,10 +687,7 @@ def get_level_values(self, level): labels = self.labels[num] filled = algos.take_1d(unique.values, labels, fill_value=unique._na_value) - _simple_new = unique._simple_new - values = _simple_new(filled, name=self.names[num], - freq=getattr(unique, 'freq', None), - tz=getattr(unique, 'tz', None)) + values = unique._shallow_copy(filled) return values def format(self, space=2, sparsify=None, adjoin=True, names=False, diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 88e49c4b55c8a..3c9040021fdbf 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -323,6 +323,45 @@ def test_constructor_dtypes(self): self.assertIsInstance(idx, Index) self.assertEqual(idx.dtype, object) + def test_constructor_dtypes_datetime(self): + + for tz in [None, 'UTC', 'US/Eastern', 'Asia/Tokyo']: + idx = pd.date_range('2011-01-01', periods=5, tz=tz) + dtype = idx.dtype + + # pass values without timezone, as DatetimeIndex localizes it + for values in [pd.date_range('2011-01-01', periods=5).values, + pd.date_range('2011-01-01', periods=5).asi8]: + + for res in [pd.Index(values, tz=tz), + pd.Index(values, dtype=dtype), + pd.Index(list(values), tz=tz), + pd.Index(list(values), dtype=dtype)]: + tm.assert_index_equal(res, idx) + + # check compat with DatetimeIndex + for res in [pd.DatetimeIndex(values, tz=tz), + pd.DatetimeIndex(values, dtype=dtype), + pd.DatetimeIndex(list(values), tz=tz), + pd.DatetimeIndex(list(values), dtype=dtype)]: + tm.assert_index_equal(res, idx) + + def test_constructor_dtypes_timedelta(self): + + idx = pd.timedelta_range('1 days', periods=5) + dtype = idx.dtype + + for values in [idx.values, idx.asi8]: + + for res in [pd.Index(values, dtype=dtype), + pd.Index(list(values), dtype=dtype)]: + tm.assert_index_equal(res, idx) + + # check compat with TimedeltaIndex + for res in [pd.TimedeltaIndex(values, dtype=dtype), + pd.TimedeltaIndex(list(values), dtype=dtype)]: + tm.assert_index_equal(res, idx) + def test_view_with_args(self): restricted = ['unicodeIndex', 'strIndex', 'catIndex', 'boolIndex', diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index 809e1ab05ef6e..bdca91253e37b 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -632,6 +632,30 @@ def test_from_arrays_index_series_period(self): tm.assert_index_equal(result, result2) + def test_from_arrays_index_datetimelike_mixed(self): + idx1 = pd.date_range('2015-01-01 10:00', freq='D', periods=3, + tz='US/Eastern') + idx2 = pd.date_range('2015-01-01 10:00', freq='H', periods=3) + idx3 = pd.timedelta_range('1 days', freq='D', periods=3) + idx4 = pd.period_range('2011-01-01', freq='D', periods=3) + + result = pd.MultiIndex.from_arrays([idx1, idx2, idx3, idx4]) + tm.assert_index_equal(result.get_level_values(0), idx1) + tm.assert_index_equal(result.get_level_values(1), idx2) + tm.assert_index_equal(result.get_level_values(2), idx3) + tm.assert_index_equal(result.get_level_values(3), idx4) + + result2 = pd.MultiIndex.from_arrays([pd.Series(idx1), + pd.Series(idx2), + pd.Series(idx3), + pd.Series(idx4)]) + tm.assert_index_equal(result2.get_level_values(0), idx1) + tm.assert_index_equal(result2.get_level_values(1), idx2) + tm.assert_index_equal(result2.get_level_values(2), idx3) + tm.assert_index_equal(result2.get_level_values(3), idx4) + + tm.assert_index_equal(result, result2) + def test_from_arrays_different_lengths(self): # GH13599 idx1 = [1, 2, 3] diff --git a/pandas/util/testing.py b/pandas/util/testing.py index e95808ddc8225..2d1d88b69941b 100644 --- a/pandas/util/testing.py +++ b/pandas/util/testing.py @@ -749,10 +749,7 @@ def _get_ilevel_values(index, level): unique = index.levels[level] labels = index.labels[level] filled = take_1d(unique.values, labels, fill_value=unique._na_value) - values = unique._simple_new(filled, - name=index.names[level], - freq=getattr(unique, 'freq', None), - tz=getattr(unique, 'tz', None)) + values = unique._shallow_copy(filled, name=index.names[level]) return values # instance validation