Skip to content
Merged
2 changes: 2 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ New Features
Bug fixes
~~~~~~~~~

- Fix bug where datetime64 times are silently changed to incorrect values if they are outside the valid date range for ns precision when provided in some other units (:issue:`4427`, :pull:`4454`).
By `Andrew Pauling <https://github.com/andrewpauling>`_
- Fix silently overwriting the `engine` key when passing :py:func:`open_dataset` a file object
to an incompatible netCDF (:issue:`4457`). Now incompatible combinations of files and engines raise
an exception instead. By `Alessandro Amici <https://github.com/alexamici>`_.
Expand Down
4 changes: 3 additions & 1 deletion xarray/core/parallel.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ def map_blocks(
to the function being applied in ``xr.map_blocks()``:

>>> array.map_blocks(
... calculate_anomaly, kwargs={"groupby_type": "time.year"}, template=array,
... calculate_anomaly,
... kwargs={"groupby_type": "time.year"},
... template=array,
... ) # doctest: +ELLIPSIS
<xarray.DataArray (time: 24)>
dask.array<calculate_anomaly-...-<this, shape=(24,), dtype=float64, chunksize=(24,), chunktype=numpy.ndarray>
Expand Down
10 changes: 6 additions & 4 deletions xarray/core/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ def _maybe_wrap_data(data):

def _possibly_convert_objects(values):
"""Convert arrays of datetime.datetime and datetime.timedelta objects into
datetime64 and timedelta64, according to the pandas convention.
datetime64 and timedelta64, according to the pandas convention. Also used for
validating that datetime64 and timedelta64 objects are within the valid date
range for ns precision, as pandas will raise an error if they are not.
"""
return np.asarray(pd.Series(values.ravel())).reshape(values.shape)

Expand Down Expand Up @@ -238,16 +240,16 @@ def as_compatible_data(data, fastpath=False):
'"1"'
)

# validate whether the data is valid data types
# validate whether the data is valid data types.
data = np.asarray(data)

if isinstance(data, np.ndarray):
if data.dtype.kind == "O":
data = _possibly_convert_objects(data)
elif data.dtype.kind == "M":
data = np.asarray(data, "datetime64[ns]")
data = _possibly_convert_objects(data)
elif data.dtype.kind == "m":
data = np.asarray(data, "timedelta64[ns]")
data = _possibly_convert_objects(data)

return _maybe_wrap_data(data)

Expand Down
13 changes: 13 additions & 0 deletions xarray/tests/test_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,19 @@ def test_object_conversion(self):
actual = self.cls("x", data)
assert actual.dtype == data.dtype

def test_datetime64_valid_range(self):
data = np.datetime64("1250-01-01", "us")
pderror = pd.errors.OutOfBoundsDatetime
with raises_regex(pderror, "Out of bounds nanosecond"):
self.cls(["t"], [data])

@pytest.mark.xfail(reason="pandas issue 36615")
def test_timedelta64_valid_range(self):
data = np.timedelta64("200000", "D")
pderror = pd.errors.OutOfBoundsTimedelta
with raises_regex(pderror, "Out of bounds nanosecond"):
self.cls(["t"], [data])

def test_pandas_data(self):
v = self.cls(["x"], pd.Series([0, 1, 2], index=[3, 2, 1]))
assert_identical(v, v[[0, 1, 2]])
Expand Down