Skip to content

Commit

Permalink
Raise error when datetime64 values that are outside the valid range f…
Browse files Browse the repository at this point in the history
…or ns precision are converted to ns precision (#4454)

timedelta64 values outside the valid range will not currently raise an error, but will if pandas eventually makes that so.  See pandas issue 36615.

Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com>
  • Loading branch information
andrewpauling and max-sixty committed Sep 30, 2020
1 parent f821fe2 commit 5296ed1
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 5 deletions.
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

0 comments on commit 5296ed1

Please sign in to comment.