@@ -310,6 +310,13 @@ def _parse_structured_fill_value(fill_value: Any, dtype: np.dtype[Any]) -> Any:
310310 raise ValueError (f"Fill_value { fill_value } is not valid for dtype { dtype } ." ) from e
311311
312312
313+ def _parse_timedelta (td : dict [str , Any ]) -> np .timedelta64 :
314+ if td ["value" ] is None :
315+ return np .timedelta64 ("NaT" )
316+ else :
317+ return np .timedelta64 (int (td ["value" ]), td ["unit" ])
318+
319+
313320def parse_fill_value (fill_value : Any , dtype : np .dtype [Any ]) -> Any :
314321 """
315322 Parse a potential fill value into a value that is compatible with the provided dtype.
@@ -329,13 +336,18 @@ def parse_fill_value(fill_value: Any, dtype: np.dtype[Any]) -> Any:
329336 if fill_value is None or dtype .hasobject :
330337 # Pass through None or if dtype is object
331338 pass
332- elif dtype .kind in "M" :
339+ elif dtype .kind == "M" : # datetime
333340 # Check for both string "NaT" and the int64 representation of NaT
334341 if fill_value == "NaT" or fill_value == np .iinfo (np .int64 ).min :
335342 fill_value = dtype .type ("NaT" )
336343 else :
337344 fill_value = np .array (fill_value , dtype = dtype )[()]
338345 # Fall through for non-NaT datetime/timedelta values (handled below)
346+ elif dtype .kind == "m" : # timedelta
347+ if isinstance (fill_value , dict ):
348+ return _parse_timedelta (fill_value )
349+ else : # if raw value is passed rather than unit-based serialization
350+ return np .timedelta64 (fill_value )
339351 elif dtype .fields is not None :
340352 # the dtype is structured (has multiple fields), so the fill_value might be a
341353 # compound value (e.g., a tuple or dict) that needs field-wise processing.
@@ -373,6 +385,14 @@ def parse_fill_value(fill_value: Any, dtype: np.dtype[Any]) -> Any:
373385 return fill_value
374386
375387
388+ def _serialize_timedelta (td : np .timedelta64 ) -> JSON :
389+ if np .isnat (td ):
390+ return {"value" : None , "unit" : None }
391+ else :
392+ val , unit = int (td .astype (int )), td .dtype .name .split ("[" )[- 1 ][:- 1 ]
393+ return {"value" : val , "unit" : unit }
394+
395+
376396def _serialize_fill_value (fill_value : Any , dtype : np .dtype [Any ]) -> JSON :
377397 serialized : JSON
378398
@@ -383,7 +403,9 @@ def _serialize_fill_value(fill_value: Any, dtype: np.dtype[Any]) -> JSON:
383403 # that mypy isn't aware of. The fact that we have S or V dtype here
384404 # means we should have a bytes-type fill_value.
385405 serialized = base64 .standard_b64encode (cast (bytes , fill_value )).decode ("ascii" )
386- elif isinstance (fill_value , np .datetime64 ):
406+ elif dtype .kind == "m" :
407+ serialized = _serialize_timedelta (fill_value )
408+ elif dtype .kind == "M" :
387409 serialized = np .datetime_as_string (fill_value )
388410 elif isinstance (fill_value , numbers .Integral ):
389411 serialized = int (fill_value )
@@ -423,7 +445,9 @@ def _default_fill_value(dtype: np.dtype[Any]) -> Any:
423445 return b""
424446 elif dtype .kind in "UO" :
425447 return ""
426- elif dtype .kind in "Mm" :
448+ elif dtype .kind in "m" : # timedelta64
449+ return np .timedelta64 ("NaT" )
450+ elif dtype .kind in "M" : # datetime64
427451 return dtype .type ("nat" )
428452 elif dtype .kind == "V" :
429453 if dtype .fields is not None :
0 commit comments