77import pandas as pd
88import xarray as xr
99from packaging .version import Version
10+ from xarray .core .duck_array_ops import _datetime_nanmin
1011
1112from .aggregations import Aggregation , Dim , _atleast_1d , quantile_new_dims_func
1213from .core import (
1718)
1819from .core import rechunk_for_blockwise as rechunk_array_for_blockwise
1920from .core import rechunk_for_cohorts as rechunk_array_for_cohorts
21+ from .xrutils import _contains_cftime_datetimes , _to_pytimedelta , datetime_to_numeric
2022
2123if TYPE_CHECKING :
2224 from xarray .core .types import T_DataArray , T_Dataset
@@ -364,6 +366,22 @@ def wrapper(array, *by, func, skipna, core_dims, **kwargs):
364366 if "nan" not in func and func not in ["all" , "any" , "count" ]:
365367 func = f"nan{ func } "
366368
369+ # Flox's count works with non-numeric and its faster than converting.
370+ requires_numeric = func not in ["count" , "any" , "all" ] or (
371+ func == "count" and kwargs ["engine" ] != "flox"
372+ )
373+ if requires_numeric :
374+ is_npdatetime = array .dtype .kind in "Mm"
375+ is_cftime = _contains_cftime_datetimes (array )
376+ if is_npdatetime :
377+ offset = _datetime_nanmin (array )
378+ # xarray always uses np.datetime64[ns] for np.datetime64 data
379+ dtype = "timedelta64[ns]"
380+ array = datetime_to_numeric (array , offset )
381+ elif is_cftime :
382+ offset = array .min ()
383+ array = datetime_to_numeric (array , offset , datetime_unit = "us" )
384+
367385 result , * groups = groupby_reduce (array , * by , func = func , ** kwargs )
368386
369387 # Transpose the new quantile dimension to the end. This is ugly.
@@ -377,6 +395,13 @@ def wrapper(array, *by, func, skipna, core_dims, **kwargs):
377395 # output dim order: (*broadcast_dims, *group_dims, quantile_dim)
378396 result = np .moveaxis (result , 0 , - 1 )
379397
398+ # Output of count has an int dtype.
399+ if requires_numeric and func != "count" :
400+ if is_npdatetime :
401+ return result .astype (dtype ) + offset
402+ elif is_cftime :
403+ return _to_pytimedelta (result , unit = "us" ) + offset
404+
380405 return result
381406
382407 # These data variables do not have any of the core dimension,
0 commit comments