From 172094312ced7d08ad3e247ec2bec51b7a25c902 Mon Sep 17 00:00:00 2001 From: Lars Buntemeyer Date: Mon, 18 Aug 2025 12:05:44 +0200 Subject: [PATCH 1/5] add cftime arithmetics limitation --- doc/user-guide/weather-climate.rst | 59 ++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/doc/user-guide/weather-climate.rst b/doc/user-guide/weather-climate.rst index 97513ef1175..0ba23edd3e6 100644 --- a/doc/user-guide/weather-climate.rst +++ b/doc/user-guide/weather-climate.rst @@ -279,3 +279,62 @@ For data indexed by a :py:class:`~xarray.CFTimeIndex` xarray currently supports: .. _precision range: https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timestamp-limitations .. _ISO 8601 standard: https://en.wikipedia.org/wiki/ISO_8601 .. _partial datetime string indexing: https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#partial-string-indexing + +.. _cftime_arithmetic_limitations: + +CFTime arithmetic limitations +----------------------------- + +A current limitation when working with non-standard calendars and :py:class:`cftime.datetime` +objects is that they support arithmetic with :py:class:`datetime.timedelta`, but **not** with :py:class:`numpy.timedelta64`. + +This means that certain xarray operations (such as :py:meth:`~xarray.DataArray.diff`) +may produce ``timedelta64`` results that cannot be directly combined with ``cftime`` coordinates. + +For example: + +.. code-block:: python + + import xarray as xr + import numpy as np + import pandas as pd + import cftime + + time = xr.DataArray( + xr.cftime_range("2000", periods=3, freq="MS", calendar="noleap"), + dims="time" + ) + + # Attempt to compute midpoints + time[:-1] + 0.5 * time.diff("time") + +results in + +.. code-block:: none + + UFuncTypeError: ufunc 'add' cannot use operands with types dtype('O') and dtype(' Date: Mon, 18 Aug 2025 13:36:25 +0200 Subject: [PATCH 2/5] update code examples --- doc/user-guide/weather-climate.rst | 54 ++++++++++++++++-------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/doc/user-guide/weather-climate.rst b/doc/user-guide/weather-climate.rst index 0ba23edd3e6..eb95f4175a9 100644 --- a/doc/user-guide/weather-climate.rst +++ b/doc/user-guide/weather-climate.rst @@ -282,8 +282,8 @@ For data indexed by a :py:class:`~xarray.CFTimeIndex` xarray currently supports: .. _cftime_arithmetic_limitations: -CFTime arithmetic limitations ------------------------------ +Arithmetic limitations with non-standard calendars +-------------------------------------------------- A current limitation when working with non-standard calendars and :py:class:`cftime.datetime` objects is that they support arithmetic with :py:class:`datetime.timedelta`, but **not** with :py:class:`numpy.timedelta64`. @@ -291,48 +291,52 @@ objects is that they support arithmetic with :py:class:`datetime.timedelta`, but This means that certain xarray operations (such as :py:meth:`~xarray.DataArray.diff`) may produce ``timedelta64`` results that cannot be directly combined with ``cftime`` coordinates. -For example: +For example, lets define a cftime DataArray with a no-leap calendar: -.. code-block:: python +.. jupyter-execute:: - import xarray as xr - import numpy as np - import pandas as pd - import cftime + import xarray as xr + import numpy as np + import pandas as pd + import cftime + + time = xr.DataArray( + xr.cftime_range("2000", periods=3, freq="MS", calendar="noleap"), + dims="time" + ) - time = xr.DataArray( - xr.cftime_range("2000", periods=3, freq="MS", calendar="noleap"), - dims="time" - ) +If you want to compute, e.g., midpoints in the time intervals, this will not work: - # Attempt to compute midpoints - time[:-1] + 0.5 * time.diff("time") +.. code-block:: python + + # Attempt to compute midpoints + time[:-1] + 0.5 * time.diff("time") -results in +and result in an error like this: .. code-block:: none UFuncTypeError: ufunc 'add' cannot use operands with types dtype('O') and dtype(' Date: Mon, 18 Aug 2025 11:41:00 +0000 Subject: [PATCH 3/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doc/user-guide/weather-climate.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/user-guide/weather-climate.rst b/doc/user-guide/weather-climate.rst index eb95f4175a9..2401c4cdfbd 100644 --- a/doc/user-guide/weather-climate.rst +++ b/doc/user-guide/weather-climate.rst @@ -285,7 +285,7 @@ For data indexed by a :py:class:`~xarray.CFTimeIndex` xarray currently supports: Arithmetic limitations with non-standard calendars -------------------------------------------------- -A current limitation when working with non-standard calendars and :py:class:`cftime.datetime` +A current limitation when working with non-standard calendars and :py:class:`cftime.datetime` objects is that they support arithmetic with :py:class:`datetime.timedelta`, but **not** with :py:class:`numpy.timedelta64`. This means that certain xarray operations (such as :py:meth:`~xarray.DataArray.diff`) @@ -299,7 +299,7 @@ For example, lets define a cftime DataArray with a no-leap calendar: import numpy as np import pandas as pd import cftime - + time = xr.DataArray( xr.cftime_range("2000", periods=3, freq="MS", calendar="noleap"), dims="time" @@ -340,5 +340,3 @@ for example via :py:meth:`pandas.to_timedelta`: These limitations stem from the ``cftime`` library itself; arithmetic between ``cftime.datetime`` and ``numpy.timedelta64`` is not implemented. - - From ce1af8a43baf205c8268ca8532848b8d7a49a56a Mon Sep 17 00:00:00 2001 From: Lars Buntemeyer Date: Mon, 18 Aug 2025 13:50:07 +0200 Subject: [PATCH 4/5] update whats-new --- doc/whats-new.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index bbe1abcc6aa..4c1f8ecb28d 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -33,6 +33,8 @@ Bug fixes Documentation ~~~~~~~~~~~~~ +- Added section on the `limitations of CFtime arithmetics `_ (:pull:`10653`). + By `Lars Buntemeyer `_ Internal Changes ~~~~~~~~~~~~~~~~ From fc7f529ed038d6fd9cc762aede81196d766dfb5c Mon Sep 17 00:00:00 2001 From: Lars Buntemeyer Date: Mon, 25 Aug 2025 10:14:21 +0200 Subject: [PATCH 5/5] Update doc/user-guide/weather-climate.rst Co-authored-by: Spencer Clark --- doc/user-guide/weather-climate.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user-guide/weather-climate.rst b/doc/user-guide/weather-climate.rst index 2401c4cdfbd..7ba72cccefc 100644 --- a/doc/user-guide/weather-climate.rst +++ b/doc/user-guide/weather-climate.rst @@ -301,7 +301,7 @@ For example, lets define a cftime DataArray with a no-leap calendar: import cftime time = xr.DataArray( - xr.cftime_range("2000", periods=3, freq="MS", calendar="noleap"), + xr.date_range("2000", periods=3, freq="MS", calendar="noleap"), dims="time" )