diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index a9cf0301747b0..118516192e4ed 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -18,7 +18,37 @@ from pandas.core.algorithms import checked_add_with_arr -class DatetimeLikeArrayMixin(object): +class AttributesMixin(object): + + @property + def _attributes(self): + # Inheriting subclass should implement _attributes as a list of strings + from pandas.errors import AbstractMethodError + raise AbstractMethodError(self) + + @classmethod + def _simple_new(cls, values, **kwargs): + from pandas.errors import AbstractMethodError + raise AbstractMethodError(cls) + + def _get_attributes_dict(self): + """return an attributes dict for my class""" + return {k: getattr(self, k, None) for k in self._attributes} + + def _shallow_copy(self, values=None, **kwargs): + if values is None: + # Note: slightly different from Index implementation which defaults + # to self.values + values = self._ndarray_values + + attributes = self._get_attributes_dict() + attributes.update(kwargs) + if not len(values) and 'dtype' not in kwargs: + attributes['dtype'] = self.dtype + return self._simple_new(values, **attributes) + + +class DatetimeLikeArrayMixin(AttributesMixin): """ Shared Base/Mixin class for DatetimeArray, TimedeltaArray, PeriodArray @@ -56,9 +86,61 @@ def asi8(self): # do not cache or you'll create a memory leak return self.values.view('i8') + # ------------------------------------------------------------------ + # Array-like Methods + def __len__(self): return len(self._data) + def __getitem__(self, key): + """ + This getitem defers to the underlying array, which by-definition can + only handle list-likes, slices, and integer scalars + """ + + is_int = lib.is_integer(key) + if lib.is_scalar(key) and not is_int: + raise IndexError("only integers, slices (`:`), ellipsis (`...`), " + "numpy.newaxis (`None`) and integer or boolean " + "arrays are valid indices") + + getitem = self._data.__getitem__ + if is_int: + val = getitem(key) + return self._box_func(val) + else: + if com.is_bool_indexer(key): + key = np.asarray(key) + if key.all(): + key = slice(0, None, None) + else: + key = lib.maybe_booleans_to_slice(key.view(np.uint8)) + + attribs = self._get_attributes_dict() + + is_period = is_period_dtype(self) + if is_period: + freq = self.freq + else: + freq = None + if isinstance(key, slice): + if self.freq is not None and key.step is not None: + freq = key.step * self.freq + else: + freq = self.freq + + attribs['freq'] = freq + + result = getitem(key) + if result.ndim > 1: + # To support MPL which performs slicing with 2 dim + # even though it only has 1 dim by definition + if is_period: + return self._simple_new(result, **attribs) + return result + + return self._simple_new(result, **attribs) + # ------------------------------------------------------------------ # Null Handling @@ -97,6 +179,27 @@ def _maybe_mask_results(self, result, fill_value=None, convert=None): result[self._isnan] = fill_value return result + def _nat_new(self, box=True): + """ + Return Array/Index or ndarray filled with NaT which has the same + length as the caller. + + Parameters + ---------- + box : boolean, default True + - If True returns a Array/Index as the same as caller. + - If False returns ndarray of np.int64. + """ + result = np.zeros(len(self), dtype=np.int64) + result.fill(iNaT) + if not box: + return result + + attribs = self._get_attributes_dict() + if not is_period_dtype(self): + attribs['freq'] = None + return self._simple_new(result, **attribs) + # ------------------------------------------------------------------ # Frequency Properties/Methods @@ -195,6 +298,17 @@ def _add_delta_tdi(self, other): new_values[mask] = iNaT return new_values.view('i8') + def _add_nat(self): + """Add pd.NaT to self""" + if is_period_dtype(self): + raise TypeError('Cannot add {cls} and {typ}' + .format(cls=type(self).__name__, + typ=type(NaT).__name__)) + + # GH#19124 pd.NaT is treated like a timedelta for both timedelta + # and datetime dtypes + return self._nat_new(box=True) + def _sub_nat(self): """Subtract pd.NaT from self""" # GH#19124 Timedelta - datetime is not in general well-defined. diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index cbdbc021cfd72..e6e0544bfa22b 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -6,13 +6,21 @@ from pandas._libs import tslib from pandas._libs.tslib import Timestamp, NaT, iNaT -from pandas._libs.tslibs import conversion, fields, timezones +from pandas._libs.tslibs import ( + conversion, fields, timezones, + resolution as libresolution) from pandas.util._decorators import cache_readonly -from pandas.core.dtypes.common import _NS_DTYPE, is_datetime64tz_dtype +from pandas.core.dtypes.common import ( + _NS_DTYPE, + is_datetime64tz_dtype, + is_datetime64_dtype, + _ensure_int64) from pandas.core.dtypes.dtypes import DatetimeTZDtype +from pandas.tseries.frequencies import to_offset, DateOffset + from .datetimelike import DatetimeLikeArrayMixin @@ -66,6 +74,50 @@ class DatetimeArrayMixin(DatetimeLikeArrayMixin): 'is_year_end', 'is_leap_year'] _object_ops = ['weekday_name', 'freq', 'tz'] + # ----------------------------------------------------------------- + # Constructors + + _attributes = ["freq", "tz"] + + @classmethod + def _simple_new(cls, values, freq=None, tz=None, **kwargs): + """ + we require the we have a dtype compat for the values + if we are passed a non-dtype compat, then coerce using the constructor + """ + + if getattr(values, 'dtype', None) is None: + # empty, but with dtype compat + if values is None: + values = np.empty(0, dtype=_NS_DTYPE) + return cls(values, freq=freq, tz=tz, **kwargs) + values = np.array(values, copy=False) + + if not is_datetime64_dtype(values): + values = _ensure_int64(values).view(_NS_DTYPE) + + result = object.__new__(cls) + result._data = values + result._freq = freq + tz = timezones.maybe_get_tz(tz) + result._tz = timezones.tz_standardize(tz) + return result + + def __new__(cls, values, freq=None, tz=None): + if (freq is not None and not isinstance(freq, DateOffset) and + freq != 'infer'): + freq = to_offset(freq) + + result = cls._simple_new(values, freq=freq, tz=tz) + if freq == 'infer': + inferred = result.inferred_freq + if inferred: + result.freq = to_offset(inferred) + + # NB: Among other things not yet ported from the DatetimeIndex + # constructor, this does not call _deepcopy_if_needed + return result + # ----------------------------------------------------------------- # Descriptive Properties @@ -116,6 +168,10 @@ def is_normalized(self): """ return conversion.is_date_array_normalized(self.asi8, self.tz) + @property # NB: override with cache_readonly in immutable subclasses + def _resolution(self): + return libresolution.resolution(self.asi8, self.tz) + # ---------------------------------------------------------------- # Array-like Methods @@ -207,6 +263,173 @@ def _local_timestamps(self): reverse.put(indexer, np.arange(n)) return result.take(reverse) + def tz_convert(self, tz): + """ + Convert tz-aware Datetime Array/Index from one time zone to another. + + Parameters + ---------- + tz : string, pytz.timezone, dateutil.tz.tzfile or None + Time zone for time. Corresponding timestamps would be converted + to this time zone of the Datetime Array/Index. A `tz` of None will + convert to UTC and remove the timezone information. + + Returns + ------- + normalized : same type as self + + Raises + ------ + TypeError + If Datetime Array/Index is tz-naive. + + See Also + -------- + DatetimeIndex.tz : A timezone that has a variable offset from UTC + DatetimeIndex.tz_localize : Localize tz-naive DatetimeIndex to a + given time zone, or remove timezone from a tz-aware DatetimeIndex. + + Examples + -------- + With the `tz` parameter, we can change the DatetimeIndex + to other time zones: + + >>> dti = pd.DatetimeIndex(start='2014-08-01 09:00', + ... freq='H', periods=3, tz='Europe/Berlin') + + >>> dti + DatetimeIndex(['2014-08-01 09:00:00+02:00', + '2014-08-01 10:00:00+02:00', + '2014-08-01 11:00:00+02:00'], + dtype='datetime64[ns, Europe/Berlin]', freq='H') + + >>> dti.tz_convert('US/Central') + DatetimeIndex(['2014-08-01 02:00:00-05:00', + '2014-08-01 03:00:00-05:00', + '2014-08-01 04:00:00-05:00'], + dtype='datetime64[ns, US/Central]', freq='H') + + With the ``tz=None``, we can remove the timezone (after converting + to UTC if necessary): + + >>> dti = pd.DatetimeIndex(start='2014-08-01 09:00',freq='H', + ... periods=3, tz='Europe/Berlin') + + >>> dti + DatetimeIndex(['2014-08-01 09:00:00+02:00', + '2014-08-01 10:00:00+02:00', + '2014-08-01 11:00:00+02:00'], + dtype='datetime64[ns, Europe/Berlin]', freq='H') + + >>> dti.tz_convert(None) + DatetimeIndex(['2014-08-01 07:00:00', + '2014-08-01 08:00:00', + '2014-08-01 09:00:00'], + dtype='datetime64[ns]', freq='H') + """ + tz = timezones.maybe_get_tz(tz) + + if self.tz is None: + # tz naive, use tz_localize + raise TypeError('Cannot convert tz-naive timestamps, use ' + 'tz_localize to localize') + + # No conversion since timestamps are all UTC to begin with + return self._shallow_copy(tz=tz) + + def tz_localize(self, tz, ambiguous='raise', errors='raise'): + """ + Localize tz-naive Datetime Array/Index to tz-aware + Datetime Array/Index. + + This method takes a time zone (tz) naive Datetime Array/Index object + and makes this time zone aware. It does not move the time to another + time zone. + Time zone localization helps to switch from time zone aware to time + zone unaware objects. + + Parameters + ---------- + tz : string, pytz.timezone, dateutil.tz.tzfile or None + Time zone to convert timestamps to. Passing ``None`` will + remove the time zone information preserving local time. + ambiguous : str {'infer', 'NaT', 'raise'} or bool array, + default 'raise' + + - 'infer' will attempt to infer fall dst-transition hours based on + order + - bool-ndarray where True signifies a DST time, False signifies a + non-DST time (note that this flag is only applicable for + ambiguous times) + - 'NaT' will return NaT where there are ambiguous times + - 'raise' will raise an AmbiguousTimeError if there are ambiguous + times + + errors : {'raise', 'coerce'}, default 'raise' + + - 'raise' will raise a NonExistentTimeError if a timestamp is not + valid in the specified time zone (e.g. due to a transition from + or to DST time) + - 'coerce' will return NaT if the timestamp can not be converted + to the specified time zone + + .. versionadded:: 0.19.0 + + Returns + ------- + result : same type as self + Array/Index converted to the specified time zone. + + Raises + ------ + TypeError + If the Datetime Array/Index is tz-aware and tz is not None. + + See Also + -------- + DatetimeIndex.tz_convert : Convert tz-aware DatetimeIndex from + one time zone to another. + + Examples + -------- + >>> tz_naive = pd.date_range('2018-03-01 09:00', periods=3) + >>> tz_naive + DatetimeIndex(['2018-03-01 09:00:00', '2018-03-02 09:00:00', + '2018-03-03 09:00:00'], + dtype='datetime64[ns]', freq='D') + + Localize DatetimeIndex in US/Eastern time zone: + + >>> tz_aware = tz_naive.tz_localize(tz='US/Eastern') + >>> tz_aware + DatetimeIndex(['2018-03-01 09:00:00-05:00', + '2018-03-02 09:00:00-05:00', + '2018-03-03 09:00:00-05:00'], + dtype='datetime64[ns, US/Eastern]', freq='D') + + With the ``tz=None``, we can remove the time zone information + while keeping the local time (not converted to UTC): + + >>> tz_aware.tz_localize(None) + DatetimeIndex(['2018-03-01 09:00:00', '2018-03-02 09:00:00', + '2018-03-03 09:00:00'], + dtype='datetime64[ns]', freq='D') + """ + if self.tz is not None: + if tz is None: + new_dates = conversion.tz_convert(self.asi8, 'UTC', self.tz) + else: + raise TypeError("Already tz-aware, use tz_convert to convert.") + else: + tz = timezones.maybe_get_tz(tz) + # Convert to UTC + + new_dates = conversion.tz_localize_to_utc(self.asi8, tz, + ambiguous=ambiguous, + errors=errors) + new_dates = new_dates.view(_NS_DTYPE) + return self._shallow_copy(new_dates, tz=tz) + # ---------------------------------------------------------------- # Conversion Methods - Vectorized analogues of Timestamp methods diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index 08e894ce6c31c..fa416e30493e9 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -113,20 +113,8 @@ def freq(self, value): _attributes = ["freq"] - def _get_attributes_dict(self): - """return an attributes dict for my class""" - return {k: getattr(self, k, None) for k in self._attributes} - - # TODO: share docstring? - def _shallow_copy(self, values=None, **kwargs): - if values is None: - values = self._ndarray_values - attributes = self._get_attributes_dict() - attributes.update(kwargs) - return self._simple_new(values, **attributes) - @classmethod - def _simple_new(cls, values, freq=None): + def _simple_new(cls, values, freq=None, **kwargs): """ Values can be any type that can be coerced to Periods. Ordinals in an ndarray are fastpath-ed to `_from_ordinals` diff --git a/pandas/core/arrays/timedelta.py b/pandas/core/arrays/timedelta.py index 4258679e1ddc5..af0fa2c3477f4 100644 --- a/pandas/core/arrays/timedelta.py +++ b/pandas/core/arrays/timedelta.py @@ -6,14 +6,16 @@ from pandas._libs import tslib from pandas._libs.tslib import Timedelta, NaT from pandas._libs.tslibs.fields import get_timedelta_field +from pandas._libs.tslibs.timedeltas import array_to_timedelta64 from pandas import compat -from pandas.core.dtypes.common import _TD_DTYPE +from pandas.core.dtypes.common import _TD_DTYPE, _ensure_int64 from pandas.core.dtypes.generic import ABCSeries from pandas.core.dtypes.missing import isna -from pandas.tseries.offsets import Tick +from pandas.tseries.offsets import Tick, DateOffset +from pandas.tseries.frequencies import to_offset from .datetimelike import DatetimeLikeArrayMixin @@ -46,6 +48,36 @@ def _box_func(self): def dtype(self): return _TD_DTYPE + # ---------------------------------------------------------------- + # Constructors + _attributes = ["freq"] + + @classmethod + def _simple_new(cls, values, freq=None, **kwargs): + values = np.array(values, copy=False) + if values.dtype == np.object_: + values = array_to_timedelta64(values) + if values.dtype != _TD_DTYPE: + values = _ensure_int64(values).view(_TD_DTYPE) + + result = object.__new__(cls) + result._data = values + result._freq = freq + return result + + def __new__(cls, values, freq=None): + if (freq is not None and not isinstance(freq, DateOffset) and + freq != 'infer'): + freq = to_offset(freq) + + result = cls._simple_new(values, freq=freq) + if freq == 'infer': + inferred = result.inferred_freq + if inferred: + result._freq = to_offset(inferred) + + return result + # ---------------------------------------------------------------- # Arithmetic Methods diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 5d0cc27979ee5..daaa40addf6c0 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -367,76 +367,6 @@ def __contains__(self, key): contains = __contains__ - def __getitem__(self, key): - """ - This getitem defers to the underlying array, which by-definition can - only handle list-likes, slices, and integer scalars - """ - - is_int = is_integer(key) - if is_scalar(key) and not is_int: - raise IndexError("only integers, slices (`:`), ellipsis (`...`), " - "numpy.newaxis (`None`) and integer or boolean " - "arrays are valid indices") - - getitem = self._data.__getitem__ - if is_int: - val = getitem(key) - return self._box_func(val) - else: - if com.is_bool_indexer(key): - key = np.asarray(key) - if key.all(): - key = slice(0, None, None) - else: - key = lib.maybe_booleans_to_slice(key.view(np.uint8)) - - attribs = self._get_attributes_dict() - - is_period = isinstance(self, ABCPeriodIndex) - if is_period: - freq = self.freq - else: - freq = None - if isinstance(key, slice): - if self.freq is not None and key.step is not None: - freq = key.step * self.freq - else: - freq = self.freq - - attribs['freq'] = freq - - result = getitem(key) - if result.ndim > 1: - # To support MPL which performs slicing with 2 dim - # even though it only has 1 dim by definition - if is_period: - return self._simple_new(result, **attribs) - return result - - return self._simple_new(result, **attribs) - - def _nat_new(self, box=True): - """ - Return Index or ndarray filled with NaT which has the same - length as the caller. - - Parameters - ---------- - box : boolean, default True - - If True returns a Index as the same as caller. - - If False returns ndarray of np.int64. - """ - result = np.zeros(len(self), dtype=np.int64) - result.fill(iNaT) - if not box: - return result - - attribs = self._get_attributes_dict() - if not is_period_dtype(self): - attribs['freq'] = None - return self._simple_new(result, **attribs) - # Try to run function on index first, and then on elements of index # Especially important for group-by functionality def map(self, f): @@ -669,17 +599,6 @@ def _convert_scalar_indexer(self, key, kind=None): return (super(DatetimeIndexOpsMixin, self) ._convert_scalar_indexer(key, kind=kind)) - def _add_nat(self): - """Add pd.NaT to self""" - if is_period_dtype(self): - raise TypeError('Cannot add {cls} and {typ}' - .format(cls=type(self).__name__, - typ=type(NaT).__name__)) - - # GH#19124 pd.NaT is treated like a timedelta for both timedelta - # and datetime dtypes - return self._nat_new(box=True) - def _addsub_offset_array(self, other, op): """ Add or subtract array-like of DateOffset objects @@ -706,7 +625,7 @@ def _addsub_offset_array(self, other, op): kwargs = {} if not is_period_dtype(self): kwargs['freq'] = 'infer' - return self._constructor(res_values, **kwargs) + return type(self)(res_values, **kwargs) @classmethod def _add_datetimelike_methods(cls): diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index a1e9a9a6e561d..53b1186b37a90 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -56,8 +56,7 @@ from pandas._libs import (lib, index as libindex, tslib as libts, join as libjoin, Timestamp) from pandas._libs.tslibs import (timezones, conversion, fields, parsing, - ccalendar, - resolution as libresolution) + ccalendar) # -------- some conversion wrapper functions @@ -266,6 +265,7 @@ class DatetimeIndex(DatetimeArrayMixin, DatelikeOps, TimelikeOps, PeriodIndex : Index of Period data pandas.to_datetime : Convert argument to datetime """ + _resolution = cache_readonly(DatetimeArrayMixin._resolution.fget) _typ = 'datetimeindex' _join_precedence = 10 @@ -614,12 +614,9 @@ def _simple_new(cls, values, name=None, freq=None, tz=None, elif not is_datetime64_dtype(values): values = _ensure_int64(values).view(_NS_DTYPE) - result = object.__new__(cls) - result._data = values + result = super(DatetimeIndex, cls)._simple_new(values, freq, tz, + **kwargs) result.name = name - result._freq = freq - result._tz = timezones.maybe_get_tz(tz) - result._tz = timezones.tz_standardize(result._tz) result._reset_identity() return result @@ -1707,10 +1704,6 @@ def inferred_type(self): def is_all_dates(self): return True - @cache_readonly - def _resolution(self): - return libresolution.resolution(self.asi8, self.tz) - def insert(self, loc, item): """ Make new Index inserting new item at location @@ -1788,172 +1781,6 @@ def delete(self, loc): return DatetimeIndex(new_dates, name=self.name, freq=freq, tz=self.tz) - def tz_convert(self, tz): - """ - Convert tz-aware DatetimeIndex from one time zone to another. - - Parameters - ---------- - tz : string, pytz.timezone, dateutil.tz.tzfile or None - Time zone for time. Corresponding timestamps would be converted - to this time zone of the DatetimeIndex. A `tz` of None will - convert to UTC and remove the timezone information. - - Returns - ------- - normalized : DatetimeIndex - - Raises - ------ - TypeError - If DatetimeIndex is tz-naive. - - See Also - -------- - DatetimeIndex.tz : A timezone that has a variable offset from UTC - DatetimeIndex.tz_localize : Localize tz-naive DatetimeIndex to a - given time zone, or remove timezone from a tz-aware DatetimeIndex. - - Examples - -------- - With the `tz` parameter, we can change the DatetimeIndex - to other time zones: - - >>> dti = pd.DatetimeIndex(start='2014-08-01 09:00', - ... freq='H', periods=3, tz='Europe/Berlin') - - >>> dti - DatetimeIndex(['2014-08-01 09:00:00+02:00', - '2014-08-01 10:00:00+02:00', - '2014-08-01 11:00:00+02:00'], - dtype='datetime64[ns, Europe/Berlin]', freq='H') - - >>> dti.tz_convert('US/Central') - DatetimeIndex(['2014-08-01 02:00:00-05:00', - '2014-08-01 03:00:00-05:00', - '2014-08-01 04:00:00-05:00'], - dtype='datetime64[ns, US/Central]', freq='H') - - With the ``tz=None``, we can remove the timezone (after converting - to UTC if necessary): - - >>> dti = pd.DatetimeIndex(start='2014-08-01 09:00',freq='H', - ... periods=3, tz='Europe/Berlin') - - >>> dti - DatetimeIndex(['2014-08-01 09:00:00+02:00', - '2014-08-01 10:00:00+02:00', - '2014-08-01 11:00:00+02:00'], - dtype='datetime64[ns, Europe/Berlin]', freq='H') - - >>> dti.tz_convert(None) - DatetimeIndex(['2014-08-01 07:00:00', - '2014-08-01 08:00:00', - '2014-08-01 09:00:00'], - dtype='datetime64[ns]', freq='H') - """ - tz = timezones.maybe_get_tz(tz) - - if self.tz is None: - # tz naive, use tz_localize - raise TypeError('Cannot convert tz-naive timestamps, use ' - 'tz_localize to localize') - - # No conversion since timestamps are all UTC to begin with - return self._shallow_copy(tz=tz) - - def tz_localize(self, tz, ambiguous='raise', errors='raise'): - """ - Localize tz-naive DatetimeIndex to tz-aware DatetimeIndex. - - This method takes a time zone (tz) naive DatetimeIndex object and - makes this time zone aware. It does not move the time to another - time zone. - Time zone localization helps to switch from time zone aware to time - zone unaware objects. - - Parameters - ---------- - tz : string, pytz.timezone, dateutil.tz.tzfile or None - Time zone to convert timestamps to. Passing ``None`` will - remove the time zone information preserving local time. - ambiguous : str {'infer', 'NaT', 'raise'} or bool array, - default 'raise' - - - 'infer' will attempt to infer fall dst-transition hours based on - order - - bool-ndarray where True signifies a DST time, False signifies a - non-DST time (note that this flag is only applicable for - ambiguous times) - - 'NaT' will return NaT where there are ambiguous times - - 'raise' will raise an AmbiguousTimeError if there are ambiguous - times - - errors : {'raise', 'coerce'}, default 'raise' - - - 'raise' will raise a NonExistentTimeError if a timestamp is not - valid in the specified time zone (e.g. due to a transition from - or to DST time) - - 'coerce' will return NaT if the timestamp can not be converted - to the specified time zone - - .. versionadded:: 0.19.0 - - Returns - ------- - DatetimeIndex - Index converted to the specified time zone. - - Raises - ------ - TypeError - If the DatetimeIndex is tz-aware and tz is not None. - - See Also - -------- - DatetimeIndex.tz_convert : Convert tz-aware DatetimeIndex from - one time zone to another. - - Examples - -------- - >>> tz_naive = pd.date_range('2018-03-01 09:00', periods=3) - >>> tz_naive - DatetimeIndex(['2018-03-01 09:00:00', '2018-03-02 09:00:00', - '2018-03-03 09:00:00'], - dtype='datetime64[ns]', freq='D') - - Localize DatetimeIndex in US/Eastern time zone: - - >>> tz_aware = tz_naive.tz_localize(tz='US/Eastern') - >>> tz_aware - DatetimeIndex(['2018-03-01 09:00:00-05:00', - '2018-03-02 09:00:00-05:00', - '2018-03-03 09:00:00-05:00'], - dtype='datetime64[ns, US/Eastern]', freq='D') - - With the ``tz=None``, we can remove the time zone information - while keeping the local time (not converted to UTC): - - >>> tz_aware.tz_localize(None) - DatetimeIndex(['2018-03-01 09:00:00', '2018-03-02 09:00:00', - '2018-03-03 09:00:00'], - dtype='datetime64[ns]', freq='D') - """ - if self.tz is not None: - if tz is None: - new_dates = conversion.tz_convert(self.asi8, 'UTC', self.tz) - else: - raise TypeError("Already tz-aware, use tz_convert to convert.") - else: - tz = timezones.maybe_get_tz(tz) - # Convert to UTC - - new_dates = conversion.tz_localize_to_utc(self.asi8, tz, - ambiguous=ambiguous, - errors=errors) - new_dates = new_dates.view(_NS_DTYPE) - return self._shallow_copy(new_dates, tz=tz) - def indexer_at_time(self, time, asof=False): """ Returns index locations of index values at particular time of day diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index e6c2094defb2d..3fa525b8617c5 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -597,14 +597,6 @@ def to_timestamp(self, freq=None, how='start'): new_data = period.periodarr_to_dt64arr(new_data._ndarray_values, base) return DatetimeIndex(new_data, freq='infer', name=self.name) - def _sub_period(self, other): - # If the operation is well-defined, we return an object-Index - # of DateOffsets. Null entries are filled with pd.NaT - new_data = PeriodArrayMixin._sub_period(self, other) - - # TODO: Should name=self.name be passed here? - return Index(new_data) - @property def inferred_type(self): # b/c data is represented as ints make sure we can't have ambiguous diff --git a/pandas/core/indexes/timedeltas.py b/pandas/core/indexes/timedeltas.py index 25f72d38eeb9b..b1dc6e6286b98 100644 --- a/pandas/core/indexes/timedeltas.py +++ b/pandas/core/indexes/timedeltas.py @@ -36,7 +36,6 @@ from pandas.tseries.offsets import Tick, DateOffset from pandas._libs import (lib, index as libindex, join as libjoin, Timedelta, NaT, iNaT) -from pandas._libs.tslibs.timedeltas import array_to_timedelta64 def _wrap_field_accessor(name): @@ -312,16 +311,8 @@ def _generate(cls, start, end, periods, name, freq, closed=None): @classmethod def _simple_new(cls, values, name=None, freq=None, **kwargs): - values = np.array(values, copy=False) - if values.dtype == np.object_: - values = array_to_timedelta64(values) - if values.dtype != _TD_DTYPE: - values = _ensure_int64(values).view(_TD_DTYPE) - - result = object.__new__(cls) - result._data = values + result = super(TimedeltaIndex, cls)._simple_new(values, freq, **kwargs) result.name = name - result._freq = freq result._reset_identity() return result