diff --git a/cf_xarray/helpers.py b/cf_xarray/helpers.py index 436f5ebc..d6120847 100644 --- a/cf_xarray/helpers.py +++ b/cf_xarray/helpers.py @@ -1,5 +1,6 @@ from __future__ import annotations +import datetime from collections.abc import Hashable, Sequence import numpy as np @@ -230,6 +231,10 @@ def _get_core_dim_orders(core_dim_coords: dict[str, np.ndarray]) -> dict[str, st # Cast to float64 for safe comparison diffs_float = diffs.astype("float64") nonzero_diffs = diffs_float[diffs_float != 0] + elif isinstance(diffs[0], datetime.timedelta): + # For datetime timedelta, we use the total_seconds method + diffs_float = np.array([x.total_seconds() for x in diffs]) + nonzero_diffs = diffs_float[diffs_float != 0] else: zero = 0 nonzero_diffs = diffs[diffs != zero] @@ -360,9 +365,17 @@ def _is_bounds_monotonic(bounds: np.ndarray) -> bool: # Cannot cast ufunc 'greater' input 0 from dtype(' None: # 2D case lon_b = cfxr.vertices_to_bounds(mollwds.lon_vertices, out_dims=("bounds", "x", "y")) assert_array_equal(mollwds.lon_bounds, lon_b) + + +@requires_cftime +def test_bounds_to_vertices_cftime() -> None: + import cftime + + # Create cftime objects for monthly bounds + periods = 3 + # start = cftime.DatetimeGregorian(2000, 1, 1) + edges = [cftime.DatetimeGregorian(2000, m, 1) for m in range(1, periods + 2)] + + # Bounds as [start, end) for each month + bnds = np.array([[edges[i], edges[i + 1]] for i in range(periods)]) + mid = np.array([edges[i] + (edges[i + 1] - edges[i]) / 2 for i in range(periods)]) + + # Sample data + values = xr.DataArray( + np.arange(periods, dtype=float), dims=("time",), coords={"time": mid} + ) + + # Build dataset with CF-style bounds + ds = xr.Dataset( + {"foo": values}, + coords={ + "time": ("time", mid, {"bounds": "time_bounds"}), + "time_bounds": (("time", "bounds"), bnds), + "bounds": ("bounds", [0, 1]), + }, + ) + + time_c = cfxr.bounds_to_vertices(ds.time_bounds, "bounds") + time_b = cfxr.vertices_to_bounds(time_c, out_dims=("bounds", "time")) + assert_array_equal(ds.time_bounds, time_b)