Skip to content

Raise error when datetime64 or timedelta64 values that are outside the valid range for ns precision are converted to ns precision #4454

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Sep 30, 2020
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