diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 33f71bcb2fef2..39b6a977f87fa 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -6,7 +6,6 @@ import numpy as np from pandas._libs import NaT, iNaT, lib -from pandas._libs.tslibs import timezones from pandas._libs.tslibs.period import ( DIFFERENT_FREQ_INDEX, IncompatibleFrequency, Period) from pandas._libs.tslibs.timedeltas import Timedelta, delta_to_nanoseconds @@ -21,8 +20,7 @@ is_bool_dtype, is_datetime64_any_dtype, is_datetime64_dtype, is_datetime64tz_dtype, is_extension_array_dtype, is_float_dtype, is_integer_dtype, is_list_like, is_object_dtype, is_offsetlike, - is_period_dtype, is_timedelta64_dtype, needs_i8_conversion, pandas_dtype) -from pandas.core.dtypes.dtypes import DatetimeTZDtype + is_period_dtype, is_timedelta64_dtype, needs_i8_conversion) from pandas.core.dtypes.generic import ABCDataFrame, ABCIndexClass, ABCSeries from pandas.core.dtypes.missing import isna @@ -1127,6 +1125,41 @@ def validate_endpoints(closed): return left_closed, right_closed +def validate_inferred_freq(freq, inferred_freq, freq_infer): + """ + If the user passes a freq and another freq is inferred from passed data, + require that they match. + + Parameters + ---------- + freq : DateOffset or None + inferred_freq : DateOffset or None + freq_infer : bool + + Returns + ------- + freq : DateOffset or None + freq_infer : bool + + Notes + ----- + We assume at this point that `maybe_infer_freq` has been called, so + `freq` is either a DateOffset object or None. + """ + if inferred_freq is not None: + if freq is not None and freq != inferred_freq: + raise ValueError('Inferred frequency {inferred} from passed ' + 'values does not conform to passed frequency ' + '{passed}' + .format(inferred=inferred_freq, + passed=freq.freqstr)) + elif freq is None: + freq = inferred_freq + freq_infer = False + + return freq, freq_infer + + def maybe_infer_freq(freq): """ Comparing a DateOffset to the string "infer" raises, so we need to @@ -1154,78 +1187,6 @@ def maybe_infer_freq(freq): return freq, freq_infer -def validate_tz_from_dtype(dtype, tz): - """ - If the given dtype is a DatetimeTZDtype, extract the implied - tzinfo object from it and check that it does not conflict with the given - tz. - - Parameters - ---------- - dtype : dtype, str - tz : None, tzinfo - - Returns - ------- - tz : consensus tzinfo - - Raises - ------ - ValueError : on tzinfo mismatch - """ - if dtype is not None: - if isinstance(dtype, compat.string_types): - try: - dtype = DatetimeTZDtype.construct_from_string(dtype) - except TypeError: - # Things like `datetime64[ns]`, which is OK for the - # constructors, but also nonsense, which should be validated - # but not by us. We *do* allow non-existent tz errors to - # go through - pass - dtz = getattr(dtype, 'tz', None) - if dtz is not None: - if tz is not None and not timezones.tz_compare(tz, dtz): - raise ValueError("cannot supply both a tz and a dtype" - " with a tz") - tz = dtz - return tz - - -def validate_dtype_freq(dtype, freq): - """ - If both a dtype and a freq are available, ensure they match. If only - dtype is available, extract the implied freq. - - Parameters - ---------- - dtype : dtype - freq : DateOffset or None - - Returns - ------- - freq : DateOffset - - Raises - ------ - ValueError : non-period dtype - IncompatibleFrequency : mismatch between dtype and freq - """ - if freq is not None: - freq = frequencies.to_offset(freq) - - if dtype is not None: - dtype = pandas_dtype(dtype) - if not is_period_dtype(dtype): - raise ValueError('dtype must be PeriodDtype') - if freq is None: - freq = dtype.freq - elif freq != dtype.freq: - raise IncompatibleFrequency('specified freq and dtype ' - 'are different') - return freq - - def _ensure_datetimelike_to_i8(other, to_utc=False): """ Helper for coercing an input scalar or array to i8. diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index f453a9b734d17..1ae11c60f3b15 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -14,9 +14,9 @@ from pandas.util._decorators import Appender from pandas.core.dtypes.common import ( - _NS_DTYPE, is_datetime64_dtype, is_datetime64tz_dtype, is_extension_type, - is_float_dtype, is_int64_dtype, is_object_dtype, is_period_dtype, - is_timedelta64_dtype) + _INT64_DTYPE, _NS_DTYPE, is_datetime64_dtype, is_datetime64tz_dtype, + is_extension_type, is_float_dtype, is_int64_dtype, is_object_dtype, + is_period_dtype, is_string_dtype, is_timedelta64_dtype) from pandas.core.dtypes.dtypes import DatetimeTZDtype from pandas.core.dtypes.generic import ABCIndexClass, ABCSeries from pandas.core.dtypes.missing import isna @@ -209,51 +209,35 @@ def _simple_new(cls, values, freq=None, tz=None): result._tz = timezones.tz_standardize(tz) return result - def __new__(cls, values, freq=None, tz=None, dtype=None): + def __new__(cls, values, freq=None, tz=None, dtype=None, copy=False, + dayfirst=False, yearfirst=False, ambiguous='raise'): + return cls._from_sequence( + values, freq=freq, tz=tz, dtype=dtype, copy=copy, + dayfirst=dayfirst, yearfirst=yearfirst, ambiguous=ambiguous) - if freq is None and hasattr(values, "freq"): - # i.e. DatetimeArray, DatetimeIndex - freq = values.freq + @classmethod + def _from_sequence(cls, data, dtype=None, copy=False, + tz=None, freq=None, + dayfirst=False, yearfirst=False, ambiguous='raise'): freq, freq_infer = dtl.maybe_infer_freq(freq) - # if dtype has an embedded tz, capture it - tz = dtl.validate_tz_from_dtype(dtype, tz) - - if not hasattr(values, "dtype"): - if np.ndim(values) == 0: - # i.e. iterator - values = list(values) - values = np.array(values) - - if is_object_dtype(values): - # kludge; dispatch until the DatetimeArray constructor is complete - from pandas import DatetimeIndex - values = DatetimeIndex(values, freq=freq, tz=tz) + subarr, tz, inferred_freq = sequence_to_dt64ns( + data, dtype=dtype, copy=copy, tz=tz, + dayfirst=dayfirst, yearfirst=yearfirst, ambiguous=ambiguous) - if isinstance(values, ABCSeries): - # extract to ndarray or DatetimeIndex - values = values._values + freq, freq_infer = dtl.validate_inferred_freq(freq, inferred_freq, + freq_infer) - if isinstance(values, DatetimeArrayMixin): - # extract nanosecond unix timestamps - if tz is None: - tz = values.tz - values = values.asi8 + result = cls._simple_new(subarr, freq=freq, tz=tz) - if values.dtype == 'i8': - values = values.view('M8[ns]') + if inferred_freq is None and freq is not None: + # this condition precludes `freq_infer` + cls._validate_frequency(result, freq, ambiguous=ambiguous) - assert isinstance(values, np.ndarray), type(values) - assert is_datetime64_dtype(values) # not yet assured nanosecond - values = conversion.ensure_datetime64ns(values, copy=False) - - result = cls._simple_new(values, freq=freq, tz=tz) - if freq_infer: + elif freq_infer: result.freq = to_offset(result.inferred_freq) - # NB: Among other things not yet ported from the DatetimeIndex - # constructor, this does not call _deepcopy_if_needed return result @classmethod @@ -1444,81 +1428,108 @@ def to_julian_date(self): # ------------------------------------------------------------------- # Constructor Helpers -def maybe_infer_tz(tz, inferred_tz): +def sequence_to_dt64ns(data, dtype=None, copy=False, + tz=None, + dayfirst=False, yearfirst=False, ambiguous='raise'): """ - If a timezone is inferred from data, check that it is compatible with - the user-provided timezone, if any. - Parameters ---------- - tz : tzinfo or None - inferred_tz : tzinfo or None + data : list-like + dtype : dtype, str, or None, default None + copy : bool, default False + tz : tzinfo, str, or None, default None + dayfirst : bool, default False + yearfirst : bool, default False + ambiguous : str, bool, or arraylike, default 'raise' + See pandas._libs.tslibs.conversion.tz_localize_to_utc Returns ------- + result : numpy.ndarray + The sequence converted to a numpy array with dtype ``datetime64[ns]``. tz : tzinfo or None + Either the user-provided tzinfo or one inferred from the data. + inferred_freq : Tick or None + The inferred frequency of the sequence. Raises ------ - TypeError : if both timezones are present but do not match + TypeError : PeriodDType data is passed """ - if tz is None: - tz = inferred_tz - elif inferred_tz is None: - pass - elif not timezones.tz_compare(tz, inferred_tz): - raise TypeError('data is already tz-aware {inferred_tz}, unable to ' - 'set specified tz: {tz}' - .format(inferred_tz=inferred_tz, tz=tz)) - return tz + inferred_freq = None -def maybe_convert_dtype(data, copy): - """ - Convert data based on dtype conventions, issuing deprecation warnings - or errors where appropriate. + if not hasattr(data, "dtype"): + # e.g. list, tuple + if np.ndim(data) == 0: + # i.e. generator + data = list(data) + data = np.asarray(data) + copy = False + elif isinstance(data, ABCSeries): + data = data._values - Parameters - ---------- - data : np.ndarray or pd.Index - copy : bool + if hasattr(data, "freq"): + # i.e. DatetimeArray/Index + inferred_freq = data.freq - Returns - ------- - data : np.ndarray or pd.Index - copy : bool + # if dtype has an embedded tz, capture it + tz = validate_tz_from_dtype(dtype, tz) - Raises - ------ - TypeError : PeriodDType data is passed - """ - if is_float_dtype(data): - # Note: we must cast to datetime64[ns] here in order to treat these - # as wall-times instead of UTC timestamps. - data = data.astype(_NS_DTYPE) + # By this point we are assured to have either a numpy array or Index + data, copy = maybe_convert_dtype(data, copy) + + if is_object_dtype(data) or is_string_dtype(data): + # TODO: We do not have tests specific to string-dtypes, + # also complex or categorical or other extension copy = False - # TODO: deprecate this behavior to instead treat symmetrically - # with integer dtypes. See discussion in GH#23675 + if lib.infer_dtype(data) == 'integer': + data = data.astype(np.int64) + else: + # data comes back here as either i8 to denote UTC timestamps + # or M8[ns] to denote wall times + data, inferred_tz = objects_to_datetime64ns( + data, dayfirst=dayfirst, yearfirst=yearfirst) + tz = maybe_infer_tz(tz, inferred_tz) + + if is_datetime64tz_dtype(data): + tz = maybe_infer_tz(tz, data.tz) + result = data._data + + elif is_datetime64_dtype(data): + # tz-naive DatetimeArray/Index or ndarray[datetime64] + data = getattr(data, "_data", data) + if data.dtype != _NS_DTYPE: + data = conversion.ensure_datetime64ns(data) - elif is_timedelta64_dtype(data): - warnings.warn("Passing timedelta64-dtype data is deprecated, will " - "raise a TypeError in a future version", - FutureWarning, stacklevel=3) - data = data.view(_NS_DTYPE) + if tz is not None: + # Convert tz-naive to UTC + tz = timezones.maybe_get_tz(tz) + data = conversion.tz_localize_to_utc(data.view('i8'), tz, + ambiguous=ambiguous) + data = data.view(_NS_DTYPE) - elif is_period_dtype(data): - # Note: without explicitly raising here, PeriondIndex - # test_setops.test_join_does_not_recur fails - raise TypeError("Passing PeriodDtype data is invalid. " - "Use `data.to_timestamp()` instead") + assert data.dtype == _NS_DTYPE, data.dtype + result = data - elif is_extension_type(data) and not is_datetime64tz_dtype(data): - # Includes categorical - # TODO: We have no tests for these - data = np.array(data, dtype=np.object_) - copy = False + else: + # must be integer dtype otherwise + # assume this data are epoch timestamps + if data.dtype != _INT64_DTYPE: + data = data.astype(np.int64, copy=False) + result = data.view(_NS_DTYPE) - return data, copy + if copy: + # TODO: should this be deepcopy? + result = result.copy() + + assert isinstance(result, np.ndarray), type(result) + assert result.dtype == 'M8[ns]', result.dtype + + # We have to call this again after possibly inferring a tz above + validate_tz_from_dtype(dtype, tz) + + return result, tz, inferred_freq def objects_to_datetime64ns(data, dayfirst, yearfirst, @@ -1598,6 +1609,54 @@ def objects_to_datetime64ns(data, dayfirst, yearfirst, raise TypeError(result) +def maybe_convert_dtype(data, copy): + """ + Convert data based on dtype conventions, issuing deprecation warnings + or errors where appropriate. + + Parameters + ---------- + data : np.ndarray or pd.Index + copy : bool + + Returns + ------- + data : np.ndarray or pd.Index + copy : bool + + Raises + ------ + TypeError : PeriodDType data is passed + """ + if is_float_dtype(data): + # Note: we must cast to datetime64[ns] here in order to treat these + # as wall-times instead of UTC timestamps. + data = data.astype(_NS_DTYPE) + copy = False + # TODO: deprecate this behavior to instead treat symmetrically + # with integer dtypes. See discussion in GH#23675 + + elif is_timedelta64_dtype(data): + warnings.warn("Passing timedelta64-dtype data is deprecated, will " + "raise a TypeError in a future version", + FutureWarning, stacklevel=5) + data = data.view(_NS_DTYPE) + + elif is_period_dtype(data): + # Note: without explicitly raising here, PeriondIndex + # test_setops.test_join_does_not_recur fails + raise TypeError("Passing PeriodDtype data is invalid. " + "Use `data.to_timestamp()` instead") + + elif is_extension_type(data) and not is_datetime64tz_dtype(data): + # Includes categorical + # TODO: We have no tests for these + data = np.array(data, dtype=np.object_) + copy = False + + return data, copy + + def _generate_regular_range(cls, start, end, periods, freq): """ Generate a range of dates with the spans between dates described by @@ -1699,6 +1758,84 @@ def _generate_range_overflow_safe(endpoint, periods, stride, side='start'): return other_end +# ------------------------------------------------------------------- +# Validation and Inference + +def maybe_infer_tz(tz, inferred_tz): + """ + If a timezone is inferred from data, check that it is compatible with + the user-provided timezone, if any. + + Parameters + ---------- + tz : tzinfo or None + inferred_tz : tzinfo or None + + Returns + ------- + tz : tzinfo or None + + Raises + ------ + TypeError : if both timezones are present but do not match + """ + if tz is None: + tz = inferred_tz + elif inferred_tz is None: + pass + elif not timezones.tz_compare(tz, inferred_tz): + raise TypeError('data is already tz-aware {inferred_tz}, unable to ' + 'set specified tz: {tz}' + .format(inferred_tz=inferred_tz, tz=tz)) + return tz + + +def validate_tz_from_dtype(dtype, tz): + """ + If the given dtype is a DatetimeTZDtype, extract the implied + tzinfo object from it and check that it does not conflict with the given + tz. + + Parameters + ---------- + dtype : dtype, str + tz : None, tzinfo + + Returns + ------- + tz : consensus tzinfo + + Raises + ------ + ValueError : on tzinfo mismatch + """ + if dtype is not None: + if isinstance(dtype, compat.string_types): + try: + dtype = DatetimeTZDtype.construct_from_string(dtype) + except TypeError: + # Things like `datetime64[ns]`, which is OK for the + # constructors, but also nonsense, which should be validated + # but not by us. We *do* allow non-existent tz errors to + # go through + pass + dtz = getattr(dtype, 'tz', None) + if dtz is not None: + if tz is not None and not timezones.tz_compare(tz, dtz): + raise ValueError("cannot supply both a tz and a dtype" + " with a tz") + tz = dtz + + if tz is not None and is_datetime64_dtype(dtype): + # We also need to check for the case where the user passed a + # tz-naive dtype (i.e. datetime64[ns]) + if tz is not None and not timezones.tz_compare(tz, dtz): + raise ValueError("cannot supply both a tz and a " + "timezone-naive dtype (i.e. datetime64[ns]") + + return tz + + def _infer_tz_from_endpoints(start, end, tz): """ If a timezone is not explicitly given via `tz`, see if one can diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index 4d466ef7281b7..759bdf20eaae9 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -155,7 +155,7 @@ class PeriodArray(dtl.DatetimeLikeArrayMixin, ExtensionArray): # Constructors def __init__(self, values, freq=None, dtype=None, copy=False): - freq = dtl.validate_dtype_freq(dtype, freq) + freq = validate_dtype_freq(dtype, freq) if freq is not None: freq = Period._maybe_convert_freq(freq) @@ -915,6 +915,40 @@ def period_array(data, freq=None, copy=False): return PeriodArray._from_sequence(data, dtype=dtype) +def validate_dtype_freq(dtype, freq): + """ + If both a dtype and a freq are available, ensure they match. If only + dtype is available, extract the implied freq. + + Parameters + ---------- + dtype : dtype + freq : DateOffset or None + + Returns + ------- + freq : DateOffset + + Raises + ------ + ValueError : non-period dtype + IncompatibleFrequency : mismatch between dtype and freq + """ + if freq is not None: + freq = frequencies.to_offset(freq) + + if dtype is not None: + dtype = pandas_dtype(dtype) + if not is_period_dtype(dtype): + raise ValueError('dtype must be PeriodDtype') + if freq is None: + freq = dtype.freq + elif freq != dtype.freq: + raise IncompatibleFrequency('specified freq and dtype ' + 'are different') + return freq + + def dt64arr_to_periodarr(data, freq, tz=None): """ Convert an datetime-like array to values Period ordinals. diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index f803144e0a78f..bc7e49d90a9e3 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -146,27 +146,19 @@ def _simple_new(cls, values, freq=None, dtype=_TD_DTYPE): return result def __new__(cls, values, freq=None, dtype=_TD_DTYPE, copy=False): - return cls._from_sequence(values, freq=freq, dtype=dtype, copy=copy) + return cls._from_sequence(values, dtype=dtype, copy=copy, freq=freq) @classmethod - def _from_sequence(cls, data, freq=None, unit=None, - dtype=_TD_DTYPE, copy=False): + def _from_sequence(cls, data, dtype=_TD_DTYPE, copy=False, + freq=None, unit=None): if dtype != _TD_DTYPE: raise ValueError("Only timedelta64[ns] dtype is valid.") freq, freq_infer = dtl.maybe_infer_freq(freq) data, inferred_freq = sequence_to_td64ns(data, copy=copy, unit=unit) - if inferred_freq is not None: - if freq is not None and freq != inferred_freq: - raise ValueError('Inferred frequency {inferred} from passed ' - 'values does not conform to passed frequency ' - '{passed}' - .format(inferred=inferred_freq, - passed=freq.freqstr)) - elif freq is None: - freq = inferred_freq - freq_infer = False + freq, freq_infer = dtl.validate_inferred_freq(freq, inferred_freq, + freq_infer) result = cls._simple_new(data, freq=freq) diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index b778b2132cd96..fd4a1527c07b7 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -9,24 +9,19 @@ from pandas._libs import ( Timestamp, index as libindex, join as libjoin, lib, tslib as libts) -from pandas._libs.tslibs import ( - ccalendar, conversion, fields, parsing, timezones) +from pandas._libs.tslibs import ccalendar, fields, parsing, timezones import pandas.compat as compat from pandas.util._decorators import Appender, Substitution, cache_readonly from pandas.core.dtypes.common import ( - _INT64_DTYPE, _NS_DTYPE, ensure_int64, is_datetime64_dtype, - is_datetime64_ns_dtype, is_datetime64tz_dtype, is_dtype_equal, is_float, - is_integer, is_list_like, is_object_dtype, is_period_dtype, is_scalar, - is_string_dtype, is_string_like, pandas_dtype) + _NS_DTYPE, ensure_int64, is_datetime64_ns_dtype, is_dtype_equal, is_float, + is_integer, is_list_like, is_period_dtype, is_scalar, is_string_like, + pandas_dtype) import pandas.core.dtypes.concat as _concat -from pandas.core.dtypes.generic import ABCSeries from pandas.core.dtypes.missing import isna -from pandas.core.arrays import datetimelike as dtl from pandas.core.arrays.datetimes import ( - DatetimeArrayMixin as DatetimeArray, _to_m8, maybe_convert_dtype, - maybe_infer_tz, objects_to_datetime64ns) + DatetimeArrayMixin as DatetimeArray, _to_m8) from pandas.core.base import _shared_docs import pandas.core.common as com from pandas.core.indexes.base import Index, _index_shared_docs @@ -49,12 +44,17 @@ def _new_DatetimeIndex(cls, d): # so need to localize tz = d.pop('tz', None) - with warnings.catch_warnings(): - # we ignore warnings from passing verify_integrity=False - # TODO: If we knew what was going in to **d, we might be able to - # go through _simple_new instead - warnings.simplefilter("ignore") - result = cls.__new__(cls, verify_integrity=False, **d) + if "data" in d and not isinstance(d["data"], DatetimeIndex): + # Avoid need to verify integrity by calling simple_new directly + data = d.pop("data") + result = cls._simple_new(data, **d) + else: + with warnings.catch_warnings(): + # we ignore warnings from passing verify_integrity=False + # TODO: If we knew what was going in to **d, we might be able to + # go through _simple_new instead + warnings.simplefilter("ignore") + result = cls.__new__(cls, verify_integrity=False, **d) if tz is not None: result = result.tz_localize('UTC').tz_convert(tz) @@ -260,81 +260,12 @@ def __new__(cls, data=None, if name is None and hasattr(data, 'name'): name = data.name - freq, freq_infer = dtl.maybe_infer_freq(freq) - if freq is None and hasattr(data, "freq"): - # i.e. DatetimeArray/Index - freq = data.freq - verify_integrity = False - - # if dtype has an embedded tz, capture it - tz = dtl.validate_tz_from_dtype(dtype, tz) - - if not hasattr(data, "dtype"): - # e.g. list, tuple - if np.ndim(data) == 0: - # i.e. generator - data = list(data) - data = np.asarray(data) - copy = False - elif isinstance(data, ABCSeries): - data = data._values - - # By this point we are assured to have either a numpy array or Index - data, copy = maybe_convert_dtype(data, copy) - - if is_object_dtype(data) or is_string_dtype(data): - # TODO: We do not have tests specific to string-dtypes, - # also complex or categorical or other extension - copy = False - if lib.infer_dtype(data) == 'integer': - data = data.astype(np.int64) - else: - # data comes back here as either i8 to denote UTC timestamps - # or M8[ns] to denote wall times - data, inferred_tz = objects_to_datetime64ns( - data, dayfirst=dayfirst, yearfirst=yearfirst) - tz = maybe_infer_tz(tz, inferred_tz) - - if is_datetime64tz_dtype(data): - tz = maybe_infer_tz(tz, data.tz) - subarr = data._data - - elif is_datetime64_dtype(data): - # tz-naive DatetimeArray/Index or ndarray[datetime64] - data = getattr(data, "_data", data) - if data.dtype != _NS_DTYPE: - data = conversion.ensure_datetime64ns(data) - - if tz is not None: - # Convert tz-naive to UTC - tz = timezones.maybe_get_tz(tz) - data = conversion.tz_localize_to_utc(data.view('i8'), tz, - ambiguous=ambiguous) - subarr = data.view(_NS_DTYPE) + dtarr = DatetimeArray._from_sequence( + data, dtype=dtype, copy=copy, tz=tz, freq=freq, + dayfirst=dayfirst, yearfirst=yearfirst, ambiguous=ambiguous) - else: - # must be integer dtype otherwise - # assume this data are epoch timestamps - if data.dtype != _INT64_DTYPE: - data = data.astype(np.int64, copy=False) - subarr = data.view(_NS_DTYPE) - - assert isinstance(subarr, np.ndarray), type(subarr) - assert subarr.dtype == 'M8[ns]', subarr.dtype - - subarr = cls._simple_new(subarr, name=name, freq=freq, tz=tz) - if dtype is not None: - if not is_dtype_equal(subarr.dtype, dtype): - # dtype must be coerced to DatetimeTZDtype above - if subarr.tz is not None: - raise ValueError("cannot localize from non-UTC data") - - if verify_integrity and len(subarr) > 0: - if freq is not None and not freq_infer: - cls._validate_frequency(subarr, freq, ambiguous=ambiguous) - - if freq_infer: - subarr.freq = to_offset(subarr.inferred_freq) + subarr = cls._simple_new(dtarr._data, name=name, + freq=dtarr.freq, tz=dtarr.tz) return subarr._deepcopy_if_needed(ref_to_data, copy) diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index 26e51e4f63101..3d69a0a84f7ae 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -19,9 +19,9 @@ from pandas.core import common as com from pandas.core.accessor import delegate_names from pandas.core.algorithms import unique1d -import pandas.core.arrays.datetimelike as dtl from pandas.core.arrays.datetimelike import DatelikeOps -from pandas.core.arrays.period import PeriodArray, period_array +from pandas.core.arrays.period import ( + PeriodArray, period_array, validate_dtype_freq) from pandas.core.base import _shared_docs import pandas.core.indexes.base as ibase from pandas.core.indexes.base import _index_shared_docs, ensure_index @@ -185,7 +185,7 @@ def __new__(cls, data=None, ordinal=None, freq=None, start=None, end=None, freq, fields) data = PeriodArray(data, freq=freq) else: - freq = dtl.validate_dtype_freq(dtype, freq) + freq = validate_dtype_freq(dtype, freq) # PeriodIndex allow PeriodIndex(period_index, freq=different) # Let's not encourage that kind of behavior in PeriodArray.