@@ -177,16 +177,14 @@ def _simple_new(cls, values, freq=None, tz=None, **kwargs):
177
177
we require the we have a dtype compat for the values
178
178
if we are passed a non-dtype compat, then coerce using the constructor
179
179
"""
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]' )
180
186
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
190
188
191
189
result = object .__new__ (cls )
192
190
result ._data = values
@@ -209,6 +207,16 @@ def __new__(cls, values, freq=None, tz=None, dtype=None):
209
207
# if dtype has an embedded tz, capture it
210
208
tz = dtl .validate_tz_from_dtype (dtype , tz )
211
209
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
+
212
220
result = cls ._simple_new (values , freq = freq , tz = tz )
213
221
if freq_infer :
214
222
inferred = result .inferred_freq
@@ -271,7 +279,7 @@ def _generate_range(cls, start, end, periods, freq, tz=None,
271
279
# TODO: consider re-implementing _cached_range; GH#17914
272
280
index = _generate_regular_range (cls , start , end , periods , freq )
273
281
274
- if tz is not None and getattr ( index , 'tz' , None ) is None :
282
+ if tz is not None and index . tz is None :
275
283
arr = conversion .tz_localize_to_utc (
276
284
ensure_int64 (index .values ),
277
285
tz , ambiguous = ambiguous )
@@ -843,7 +851,8 @@ def to_perioddelta(self, freq):
843
851
# TODO: consider privatizing (discussion in GH#23113)
844
852
from pandas .core .arrays .timedeltas import TimedeltaArrayMixin
845
853
i8delta = self .asi8 - self .to_period (freq ).to_timestamp ().asi8
846
- return TimedeltaArrayMixin (i8delta )
854
+ m8delta = i8delta .view ('m8[ns]' )
855
+ return TimedeltaArrayMixin (m8delta )
847
856
848
857
# -----------------------------------------------------------------
849
858
# Properties - Vectorized Timestamp Properties/Methods
@@ -1320,6 +1329,27 @@ def to_julian_date(self):
1320
1329
1321
1330
1322
1331
def _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
+ """
1323
1353
if isinstance (freq , Tick ):
1324
1354
stride = freq .nanos
1325
1355
if periods is None :
@@ -1342,22 +1372,22 @@ def _generate_regular_range(cls, start, end, periods, freq):
1342
1372
raise ValueError ("at least 'start' or 'end' should be specified "
1343
1373
"if a 'period' is given." )
1344
1374
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
+
1347
1377
else :
1348
1378
tz = None
1349
1379
# start and end should have the same timezone by this point
1350
- if isinstance ( start , Timestamp ) :
1380
+ if start is not None :
1351
1381
tz = start .tz
1352
- elif isinstance ( end , Timestamp ) :
1382
+ elif end is not None :
1353
1383
tz = end .tz
1354
1384
1355
1385
xdr = generate_range (start = start , end = end ,
1356
1386
periods = periods , offset = freq )
1357
1387
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 )
1360
1389
1390
+ data = cls ._simple_new (values , freq = freq , tz = tz )
1361
1391
return data
1362
1392
1363
1393
0 commit comments