diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index a98b0b3bf35f9..72bc5c2209d04 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -595,9 +595,12 @@ def _time_shift(self, periods, freq=None): start = self[0] + periods * self.freq end = self[-1] + periods * self.freq - attribs = self._get_attributes_dict() + + # Note: in the DatetimeTZ case, _generate_range will infer the + # appropriate timezone from `start` and `end`, so tz does not need + # to be passed explicitly. return self._generate_range(start=start, end=end, periods=None, - **attribs) + freq=self.freq) @classmethod def _add_datetimelike_methods(cls): diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index 16fa9ccb43b4d..1426b9690f4df 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -176,11 +176,13 @@ def _from_ordinals(cls, values, freq=None, **kwargs): @classmethod def _generate_range(cls, start, end, periods, freq, fields): + periods = dtl.validate_periods(periods) + if freq is not None: freq = Period._maybe_convert_freq(freq) field_count = len(fields) - if com.count_not_none(start, end) > 0: + if start is not None or end is not None: if field_count > 0: raise ValueError('Can either instantiate from fields ' 'or endpoints, but not both') diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 4904a90ab7b2b..eb7dabdc03b0b 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -126,8 +126,7 @@ def _simple_new(cls, values, freq=None, **kwargs): result._freq = freq return result - def __new__(cls, values, freq=None, start=None, end=None, periods=None, - closed=None): + def __new__(cls, values, freq=None): freq, freq_infer = dtl.maybe_infer_freq(freq) @@ -140,8 +139,7 @@ def __new__(cls, values, freq=None, start=None, end=None, periods=None, return result @classmethod - def _generate_range(cls, start, end, periods, freq, closed=None, **kwargs): - # **kwargs are for compat with TimedeltaIndex, which includes `name` + def _generate_range(cls, start, end, periods, freq, closed=None): periods = dtl.validate_periods(periods) if freq is None and any(x is None for x in [periods, start, end]): @@ -167,10 +165,9 @@ def _generate_range(cls, start, end, periods, freq, closed=None, **kwargs): if freq is not None: index = _generate_regular_range(start, end, periods, freq) - index = cls._simple_new(index, freq=freq, **kwargs) + index = cls._simple_new(index, freq=freq) else: index = np.linspace(start.value, end.value, periods).astype('i8') - # TODO: shouldn't we pass `name` here? (via **kwargs) index = cls._simple_new(index, freq=freq) if not left_closed: diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index d9152c50309eb..53f8d42f46d55 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -703,6 +703,12 @@ def astype(self, dtype, copy=True): raise TypeError(msg.format(name=type(self).__name__, dtype=dtype)) return super(DatetimeIndexOpsMixin, self).astype(dtype, copy=copy) + @Appender(DatetimeLikeArrayMixin._time_shift.__doc__) + def _time_shift(self, periods, freq=None): + result = DatetimeLikeArrayMixin._time_shift(self, periods, freq=freq) + result.name = self.name + return result + def _ensure_datetimelike_to_i8(other, to_utc=False): """ diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index e0219acc115b5..c9107d6509848 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -241,9 +241,11 @@ def __new__(cls, data=None, if data is None: # TODO: Remove this block and associated kwargs; GH#20535 - return cls._generate_range(start, end, periods, name, freq, - tz=tz, normalize=normalize, - closed=closed, ambiguous=ambiguous) + result = cls._generate_range(start, end, periods, + freq=freq, tz=tz, normalize=normalize, + closed=closed, ambiguous=ambiguous) + result.name = name + return result if not isinstance(data, (np.ndarray, Index, ABCSeries, DatetimeArrayMixin)): @@ -315,17 +317,6 @@ def __new__(cls, data=None, return subarr._deepcopy_if_needed(ref_to_data, copy) - @classmethod - @Appender(DatetimeArrayMixin._generate_range.__doc__) - def _generate_range(cls, start, end, periods, name=None, freq=None, - tz=None, normalize=False, ambiguous='raise', - closed=None): - out = super(DatetimeIndex, cls)._generate_range( - start, end, periods, freq, - tz=tz, normalize=normalize, ambiguous=ambiguous, closed=closed) - out.name = name - return out - def _convert_for_op(self, value): """ Convert value to be insertable to ndarray """ if self._has_same_tz(value): diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index cbcd39317e17e..74768d7813501 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -165,8 +165,6 @@ def __new__(cls, data=None, ordinal=None, freq=None, start=None, end=None, raise TypeError('__new__() got an unexpected keyword argument {}'. format(list(set(fields) - valid_field_set)[0])) - periods = dtl.validate_periods(periods) - if name is None and hasattr(data, 'name'): name = data.name diff --git a/pandas/core/indexes/timedeltas.py b/pandas/core/indexes/timedeltas.py index 8c94ac2ea8256..1efa0a15d34d7 100644 --- a/pandas/core/indexes/timedeltas.py +++ b/pandas/core/indexes/timedeltas.py @@ -147,12 +147,10 @@ def __new__(cls, data=None, unit=None, freq=None, start=None, end=None, if data is None: # TODO: Remove this block and associated kwargs; GH#20535 - if freq is None and com._any_none(periods, start, end): - raise ValueError('Must provide freq argument if no data is ' - 'supplied') - periods = dtl.validate_periods(periods) - return cls._generate_range(start, end, periods, name, freq, - closed=closed) + result = cls._generate_range(start, end, periods, freq, + closed=closed) + result.name = name + return result if unit is not None: data = to_timedelta(data, unit=unit, box=False) @@ -181,16 +179,6 @@ def __new__(cls, data=None, unit=None, freq=None, start=None, end=None, return subarr - @classmethod - def _generate_range(cls, start, end, periods, - name=None, freq=None, closed=None): - # TimedeltaArray gets `name` via **kwargs, so we need to explicitly - # override it if name is passed as a positional argument - return super(TimedeltaIndex, cls)._generate_range(start, end, - periods, freq, - name=name, - closed=closed) - @classmethod def _simple_new(cls, values, name=None, freq=None, **kwargs): result = super(TimedeltaIndex, cls)._simple_new(values, freq, **kwargs)