29
29
astype_overflowsafe ,
30
30
fields ,
31
31
get_resolution ,
32
+ get_supported_reso ,
32
33
get_unit_from_dtype ,
33
34
ints_to_pydatetime ,
34
35
is_date_array_normalized ,
35
36
is_supported_unit ,
36
37
is_unitless ,
37
38
normalize_i8_timestamps ,
39
+ npy_unit_to_abbrev ,
38
40
timezones ,
39
41
to_offset ,
40
42
tz_convert_from_utc ,
@@ -321,6 +323,14 @@ def _from_sequence_not_strict(
321
323
# if dtype has an embedded tz, capture it
322
324
tz = validate_tz_from_dtype (dtype , tz , explicit_tz_none )
323
325
326
+ unit = None
327
+ if dtype is not None :
328
+ if isinstance (dtype , np .dtype ):
329
+ unit = np .datetime_data (dtype )[0 ]
330
+ else :
331
+ # DatetimeTZDtype
332
+ unit = dtype .unit
333
+
324
334
subarr , tz , inferred_freq = _sequence_to_dt64ns (
325
335
data ,
326
336
copy = copy ,
@@ -341,8 +351,12 @@ def _from_sequence_not_strict(
341
351
if explicit_none :
342
352
freq = None
343
353
344
- dtype = tz_to_dtype (tz )
345
- result = cls ._simple_new (subarr , freq = freq , dtype = dtype )
354
+ data_unit = np .datetime_data (subarr .dtype )[0 ]
355
+ data_dtype = tz_to_dtype (tz , data_unit )
356
+ result = cls ._simple_new (subarr , freq = freq , dtype = data_dtype )
357
+ if unit is not None and unit != result ._unit :
358
+ # If unit was specified in user-passed dtype, cast to it here
359
+ result = result ._as_unit (unit )
346
360
347
361
if inferred_freq is None and freq is not None :
348
362
# this condition precludes `freq_infer`
@@ -2004,7 +2018,8 @@ def sequence_to_datetimes(data, require_iso8601: bool = False) -> DatetimeArray:
2004
2018
require_iso8601 = require_iso8601 ,
2005
2019
)
2006
2020
2007
- dtype = tz_to_dtype (tz )
2021
+ unit = np .datetime_data (result .dtype )[0 ]
2022
+ dtype = tz_to_dtype (tz , unit )
2008
2023
dta = DatetimeArray ._simple_new (result , freq = freq , dtype = dtype )
2009
2024
return dta
2010
2025
@@ -2110,20 +2125,33 @@ def _sequence_to_dt64ns(
2110
2125
elif is_datetime64_dtype (data_dtype ):
2111
2126
# tz-naive DatetimeArray or ndarray[datetime64]
2112
2127
data = getattr (data , "_ndarray" , data )
2113
- if data .dtype != DT64NS_DTYPE :
2114
- data = astype_overflowsafe (data , dtype = DT64NS_DTYPE )
2128
+ new_dtype = data .dtype
2129
+ data_unit = get_unit_from_dtype (new_dtype )
2130
+ if not is_supported_unit (data_unit ):
2131
+ # Cast to the nearest supported unit, generally "s"
2132
+ new_reso = get_supported_reso (data_unit )
2133
+ new_unit = npy_unit_to_abbrev (new_reso )
2134
+ new_dtype = np .dtype (f"M8[{ new_unit } ]" )
2135
+ data = astype_overflowsafe (data , dtype = new_dtype , copy = False )
2136
+ copy = False
2137
+
2138
+ if data .dtype .byteorder == ">" :
2139
+ # TODO: better way to handle this? non-copying alternative?
2140
+ # without this, test_constructor_datetime64_bigendian fails
2141
+ data = data .astype (data .dtype .newbyteorder ("<" ))
2142
+ new_dtype = data .dtype
2115
2143
copy = False
2116
2144
2117
2145
if tz is not None :
2118
2146
# Convert tz-naive to UTC
2119
2147
# TODO: if tz is UTC, are there situations where we *don't* want a
2120
2148
# copy? tz_localize_to_utc always makes one.
2121
2149
data = tzconversion .tz_localize_to_utc (
2122
- data .view ("i8" ), tz , ambiguous = ambiguous
2150
+ data .view ("i8" ), tz , ambiguous = ambiguous , reso = data_unit
2123
2151
)
2124
- data = data .view (DT64NS_DTYPE )
2152
+ data = data .view (new_dtype )
2125
2153
2126
- assert data .dtype == DT64NS_DTYPE , data .dtype
2154
+ assert data .dtype == new_dtype , data .dtype
2127
2155
result = data
2128
2156
2129
2157
else :
@@ -2137,7 +2165,9 @@ def _sequence_to_dt64ns(
2137
2165
result = result .copy ()
2138
2166
2139
2167
assert isinstance (result , np .ndarray ), type (result )
2140
- assert result .dtype == "M8[ns]" , result .dtype
2168
+ assert result .dtype .kind == "M"
2169
+ assert result .dtype != "M8"
2170
+ assert is_supported_unit (get_unit_from_dtype (result .dtype ))
2141
2171
return result , tz , inferred_freq
2142
2172
2143
2173
@@ -2358,12 +2388,14 @@ def _validate_dt64_dtype(dtype):
2358
2388
)
2359
2389
raise ValueError (msg )
2360
2390
2361
- if (isinstance (dtype , np .dtype ) and dtype != DT64NS_DTYPE ) or not isinstance (
2362
- dtype , (np .dtype , DatetimeTZDtype )
2363
- ):
2391
+ if (
2392
+ isinstance (dtype , np .dtype )
2393
+ and (dtype .kind != "M" or not is_supported_unit (get_unit_from_dtype (dtype )))
2394
+ ) or not isinstance (dtype , (np .dtype , DatetimeTZDtype )):
2364
2395
raise ValueError (
2365
2396
f"Unexpected value for 'dtype': '{ dtype } '. "
2366
- "Must be 'datetime64[ns]' or DatetimeTZDtype'."
2397
+ "Must be 'datetime64[s]', 'datetime64[ms]', 'datetime64[us]', "
2398
+ "'datetime64[ns]' or DatetimeTZDtype'."
2367
2399
)
2368
2400
2369
2401
if getattr (dtype , "tz" , None ):
0 commit comments