@@ -177,16 +177,14 @@ def _simple_new(cls, values, freq=None, tz=None, **kwargs):
177177 we require the we have a dtype compat for the values
178178 if we are passed a non-dtype compat, then coerce using the constructor
179179 """
180+ assert isinstance (values , np .ndarray ), type (values )
181+ if values .dtype == 'i8' :
182+ # for compat with datetime/timedelta/period shared methods,
183+ # we can sometimes get here with int64 values. These represent
184+ # nanosecond UTC (or tz-naive) unix timestamps
185+ values = values .view ('M8[ns]' )
180186
181- if getattr (values , 'dtype' , None ) is None :
182- # empty, but with dtype compat
183- if values is None :
184- values = np .empty (0 , dtype = _NS_DTYPE )
185- return cls (values , freq = freq , tz = tz , ** kwargs )
186- values = np .array (values , copy = False )
187-
188- if not is_datetime64_dtype (values ):
189- values = ensure_int64 (values ).view (_NS_DTYPE )
187+ assert values .dtype == 'M8[ns]' , values .dtype
190188
191189 result = object .__new__ (cls )
192190 result ._data = values
@@ -209,6 +207,16 @@ def __new__(cls, values, freq=None, tz=None, dtype=None):
209207 # if dtype has an embedded tz, capture it
210208 tz = dtl .validate_tz_from_dtype (dtype , tz )
211209
210+ if isinstance (values , DatetimeArrayMixin ):
211+ # extract nanosecond unix timestamps
212+ values = values .asi8
213+ if values .dtype == 'i8' :
214+ values = values .view ('M8[ns]' )
215+
216+ assert isinstance (values , np .ndarray ), type (values )
217+ assert is_datetime64_dtype (values ) # not yet assured nanosecond
218+ values = conversion .ensure_datetime64ns (values , copy = False )
219+
212220 result = cls ._simple_new (values , freq = freq , tz = tz )
213221 if freq_infer :
214222 inferred = result .inferred_freq
@@ -271,7 +279,7 @@ def _generate_range(cls, start, end, periods, freq, tz=None,
271279 # TODO: consider re-implementing _cached_range; GH#17914
272280 index = _generate_regular_range (cls , start , end , periods , freq )
273281
274- if tz is not None and getattr ( index , 'tz' , None ) is None :
282+ if tz is not None and index . tz is None :
275283 arr = conversion .tz_localize_to_utc (
276284 ensure_int64 (index .values ),
277285 tz , ambiguous = ambiguous )
@@ -843,7 +851,8 @@ def to_perioddelta(self, freq):
843851 # TODO: consider privatizing (discussion in GH#23113)
844852 from pandas .core .arrays .timedeltas import TimedeltaArrayMixin
845853 i8delta = self .asi8 - self .to_period (freq ).to_timestamp ().asi8
846- return TimedeltaArrayMixin (i8delta )
854+ m8delta = i8delta .view ('m8[ns]' )
855+ return TimedeltaArrayMixin (m8delta )
847856
848857 # -----------------------------------------------------------------
849858 # Properties - Vectorized Timestamp Properties/Methods
@@ -1320,6 +1329,27 @@ def to_julian_date(self):
13201329
13211330
13221331def _generate_regular_range (cls , start , end , periods , freq ):
1332+ """
1333+ Generate a range of dates with the spans between dates described by
1334+ the given `freq` DateOffset.
1335+
1336+ Parameters
1337+ ----------
1338+ cls : class
1339+ start : Timestamp or None
1340+ first point of produced date range
1341+ end : Timestamp or None
1342+ last point of produced date range
1343+ periods : int
1344+ number of periods in produced date range
1345+ freq : DateOffset
1346+ describes space between dates in produced date range
1347+
1348+ Returns
1349+ -------
1350+ ndarray[np.int64] representing nanosecond unix timestamps
1351+
1352+ """
13231353 if isinstance (freq , Tick ):
13241354 stride = freq .nanos
13251355 if periods is None :
@@ -1342,22 +1372,22 @@ def _generate_regular_range(cls, start, end, periods, freq):
13421372 raise ValueError ("at least 'start' or 'end' should be specified "
13431373 "if a 'period' is given." )
13441374
1345- data = np .arange (b , e , stride , dtype = np .int64 )
1346- data = cls . _simple_new ( data . view ( _NS_DTYPE ), None , tz = tz )
1375+ values = np .arange (b , e , stride , dtype = np .int64 )
1376+
13471377 else :
13481378 tz = None
13491379 # start and end should have the same timezone by this point
1350- if isinstance ( start , Timestamp ) :
1380+ if start is not None :
13511381 tz = start .tz
1352- elif isinstance ( end , Timestamp ) :
1382+ elif end is not None :
13531383 tz = end .tz
13541384
13551385 xdr = generate_range (start = start , end = end ,
13561386 periods = periods , offset = freq )
13571387
1358- values = np .array ([x .value for x in xdr ])
1359- data = cls ._simple_new (values , freq = freq , tz = tz )
1388+ values = np .array ([x .value for x in xdr ], dtype = np .int64 )
13601389
1390+ data = cls ._simple_new (values , freq = freq , tz = tz )
13611391 return data
13621392
13631393
0 commit comments