@@ -2152,7 +2152,6 @@ def convert(
2152
2152
2153
2153
val_kind = _ensure_decoded (self .kind )
2154
2154
values = _maybe_convert (values , val_kind , encoding , errors )
2155
-
2156
2155
kwargs = {}
2157
2156
kwargs ["name" ] = _ensure_decoded (self .index_name )
2158
2157
@@ -2577,7 +2576,7 @@ def convert(self, values: np.ndarray, nan_rep, encoding: str, errors: str):
2577
2576
dtype = _ensure_decoded (dtype_name )
2578
2577
2579
2578
# reverse converts
2580
- if dtype == "datetime64" :
2579
+ if dtype . startswith ( "datetime64" ) :
2581
2580
# recreate with tz if indicated
2582
2581
converted = _set_tz (converted , tz , coerce = True )
2583
2582
@@ -2870,7 +2869,9 @@ def _get_index_factory(self, attrs):
2870
2869
2871
2870
def f (values , freq = None , tz = None ):
2872
2871
# data are already in UTC, localize and convert if tz present
2873
- dta = DatetimeArray ._simple_new (values .values , freq = freq )
2872
+ dta = DatetimeArray ._simple_new (
2873
+ values .values , dtype = values .dtype , freq = freq
2874
+ )
2874
2875
result = DatetimeIndex ._simple_new (dta , name = None )
2875
2876
if tz is not None :
2876
2877
result = result .tz_localize ("UTC" ).tz_convert (tz )
@@ -2961,7 +2962,7 @@ def read_array(self, key: str, start: int | None = None, stop: int | None = None
2961
2962
else :
2962
2963
ret = node [start :stop ]
2963
2964
2964
- if dtype == "datetime64" :
2965
+ if dtype and dtype . startswith ( "datetime64" ) :
2965
2966
# reconstruct a timezone if indicated
2966
2967
tz = getattr (attrs , "tz" , None )
2967
2968
ret = _set_tz (ret , tz , coerce = True )
@@ -3170,7 +3171,7 @@ def write_array(
3170
3171
3171
3172
elif lib .is_np_dtype (value .dtype , "M" ):
3172
3173
self ._handle .create_array (self .group , key , value .view ("i8" ))
3173
- getattr (self .group , key )._v_attrs .value_type = "datetime64"
3174
+ getattr (self .group , key )._v_attrs .value_type = str ( value . dtype )
3174
3175
elif isinstance (value .dtype , DatetimeTZDtype ):
3175
3176
# store as UTC
3176
3177
# with a zone
@@ -3185,7 +3186,7 @@ def write_array(
3185
3186
# error: Item "ExtensionArray" of "Union[Any, ExtensionArray]" has no
3186
3187
# attribute "tz"
3187
3188
node ._v_attrs .tz = _get_tz (value .tz ) # type: ignore[union-attr]
3188
- node ._v_attrs .value_type = "datetime64"
3189
+ node ._v_attrs .value_type = f "datetime64[ { value . dtype . unit } ] "
3189
3190
elif lib .is_np_dtype (value .dtype , "m" ):
3190
3191
self ._handle .create_array (self .group , key , value .view ("i8" ))
3191
3192
getattr (self .group , key )._v_attrs .value_type = "timedelta64"
@@ -4689,7 +4690,6 @@ def read(
4689
4690
selection = Selection (self , where = where , start = start , stop = stop )
4690
4691
# apply the selection filters & axis orderings
4691
4692
df = self .process_axes (df , selection = selection , columns = columns )
4692
-
4693
4693
return df
4694
4694
4695
4695
@@ -4932,11 +4932,12 @@ def _set_tz(
4932
4932
# call below (which returns an ndarray). So we are only non-lossy
4933
4933
# if `tz` matches `values.tz`.
4934
4934
assert values .tz is None or values .tz == tz
4935
+ if values .tz is not None :
4936
+ return values
4935
4937
4936
4938
if tz is not None :
4937
4939
if isinstance (values , DatetimeIndex ):
4938
4940
name = values .name
4939
- values = values .asi8
4940
4941
else :
4941
4942
name = None
4942
4943
values = values .ravel ()
@@ -5019,8 +5020,12 @@ def _convert_index(name: str, index: Index, encoding: str, errors: str) -> Index
5019
5020
def _unconvert_index (data , kind : str , encoding : str , errors : str ) -> np .ndarray | Index :
5020
5021
index : Index | np .ndarray
5021
5022
5022
- if kind == "datetime64" :
5023
- index = DatetimeIndex (data )
5023
+ if kind .startswith ("datetime64" ):
5024
+ if kind == "datetime64" :
5025
+ # created before we stored resolution information
5026
+ index = DatetimeIndex (data )
5027
+ else :
5028
+ index = DatetimeIndex (data .view (kind ))
5024
5029
elif kind == "timedelta64" :
5025
5030
index = TimedeltaIndex (data )
5026
5031
elif kind == "date" :
@@ -5194,6 +5199,8 @@ def _maybe_convert(values: np.ndarray, val_kind: str, encoding: str, errors: str
5194
5199
def _get_converter (kind : str , encoding : str , errors : str ):
5195
5200
if kind == "datetime64" :
5196
5201
return lambda x : np .asarray (x , dtype = "M8[ns]" )
5202
+ elif "datetime64" in kind :
5203
+ return lambda x : np .asarray (x , dtype = kind )
5197
5204
elif kind == "string" :
5198
5205
return lambda x : _unconvert_string_array (
5199
5206
x , nan_rep = None , encoding = encoding , errors = errors
@@ -5203,7 +5210,7 @@ def _get_converter(kind: str, encoding: str, errors: str):
5203
5210
5204
5211
5205
5212
def _need_convert (kind : str ) -> bool :
5206
- if kind in ("datetime64" , "string" ):
5213
+ if kind in ("datetime64" , "string" ) or "datetime64" in kind :
5207
5214
return True
5208
5215
return False
5209
5216
@@ -5248,7 +5255,7 @@ def _dtype_to_kind(dtype_str: str) -> str:
5248
5255
elif dtype_str .startswith (("int" , "uint" )):
5249
5256
kind = "integer"
5250
5257
elif dtype_str .startswith ("datetime64" ):
5251
- kind = "datetime64"
5258
+ kind = dtype_str
5252
5259
elif dtype_str .startswith ("timedelta" ):
5253
5260
kind = "timedelta64"
5254
5261
elif dtype_str .startswith ("bool" ):
@@ -5273,8 +5280,11 @@ def _get_data_and_dtype_name(data: ArrayLike):
5273
5280
if isinstance (data , Categorical ):
5274
5281
data = data .codes
5275
5282
5276
- # For datetime64tz we need to drop the TZ in tests TODO: why?
5277
- dtype_name = data .dtype .name .split ("[" )[0 ]
5283
+ if isinstance (data .dtype , DatetimeTZDtype ):
5284
+ # For datetime64tz we need to drop the TZ in tests TODO: why?
5285
+ dtype_name = f"datetime64[{ data .dtype .unit } ]"
5286
+ else :
5287
+ dtype_name = data .dtype .name
5278
5288
5279
5289
if data .dtype .kind in "mM" :
5280
5290
data = np .asarray (data .view ("i8" ))
0 commit comments