Repository: dask/dask

Issue:
Error adding DateOffsets to datetime64
<!-- Please include a self-contained copy-pastable example that generates the issue if possible.

Please be concise with code posted. See guidelines below on how to provide a good bug report:

- Craft Minimal Bug Reports http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports
- Minimal Complete Verifiable Examples https://stackoverflow.com/help/mcve

Bug reports that follow these guidelines are easier to diagnose, and so are often handled much more quickly.
-->

**What happened**:

`UFuncTypeError: ufunc 'add' cannot use operands with types dtype('<M8[ns]') and dtype('O')` when adding `DateOffset` to `datetime64`

**What you expected to happen**:

An offset adjusted column, matching the pandas behavior. 

**Minimal Complete Verifiable Example**:

```python
import dask.dataframe as dd
import pandas as pd

base = pd.Series([1,2,3], dtype="datetime64[ns]")
offsets = pd.Series([pd.offsets.DateOffset(years=o) for o in range(3)])

base+offsets

# results in:
# 0   1970-01-01 00:00:00.000000001
# 1   1971-01-01 00:00:00.000000002
# 2   1972-01-01 00:00:00.000000003
# dtype: datetime64[ns]

dask_base = dd.from_pandas(base, npartitions=1)
dask_offsets = dd.from_pandas(offsets, npartitions=1)

# Triggers error
dask_base + dask_offsets
```

**Anything else we need to know?**:

I'm not entirely sure if this is supposed to be supported, but I didn't see anything in the docs so I figured I'd confirm the expected behavior. The `dtype` of `offsets` is indeed `object`, but I guess pandas handles this internally? 

**Environment**:

- Dask version: 2.30.0
- Python version: 3.8.5
- Operating System: Ubuntu 18.04
- Install method (conda, pip, source): conda



Discussion:
I feel like this is missing some context. Is this the description you intended to put on the dask issue tracker @gerrymanoim? 
Err - whoops - sorry! Mistaken copy/paste here. Will find the repo that I originally had here. 
@jsignell - Apologies - fixed the issue text now. 
Oh that is an interesting bug! It is kind of tough becuase I can't think of a way to pass a meta into the function, which would be the easiest way to workaround the issue. There are a couple other things going on though. One is that the default non_empty `_meta` for objects is a string. And the other is that even if you set the `_meta` on dask_offsets it is ignored. I'll open a PR to mull over some ideas.
I was trying to figure out how to override the meta guessing as well (or some other reasonable workaround), but couldn't figure out if there was a reasonable way to do that. Thanks for confirming. 

Resolving patch:
diff --git a/dask/dataframe/utils.py b/dask/dataframe/utils.py
--- a/dask/dataframe/utils.py
+++ b/dask/dataframe/utils.py
@@ -542,7 +542,10 @@ def _nonempty_series(s, idx=None):
     if idx is None:
         idx = _nonempty_index(s.index)
     dtype = s.dtype
-    if is_datetime64tz_dtype(dtype):
+    if len(s) > 0:
+        # use value from meta if provided
+        data = [s.iloc[0]] * 2
+    elif is_datetime64tz_dtype(dtype):
         entry = pd.Timestamp("1970-01-01", tz=dtype.tz)
         data = [entry, entry]
     elif is_categorical_dtype(dtype):


Test patch:
diff --git a/dask/dataframe/tests/test_dataframe.py b/dask/dataframe/tests/test_dataframe.py
--- a/dask/dataframe/tests/test_dataframe.py
+++ b/dask/dataframe/tests/test_dataframe.py
@@ -4152,6 +4152,20 @@ def test_meta_raises():
     assert "meta=" not in str(info.value)
 
 
+def test_meta_nonempty_uses_meta_value_if_provided():
+    # https://github.com/dask/dask/issues/6958
+    base = pd.Series([1, 2, 3], dtype="datetime64[ns]")
+    offsets = pd.Series([pd.offsets.DateOffset(years=o) for o in range(3)])
+    dask_base = dd.from_pandas(base, npartitions=1)
+    dask_offsets = dd.from_pandas(offsets, npartitions=1)
+    dask_offsets._meta = offsets.head()
+
+    with pytest.warns(None):  # not vectorized performance warning
+        expected = base + offsets
+        actual = dask_base + dask_offsets
+        assert_eq(expected, actual)
+
+
 def test_dask_dataframe_holds_scipy_sparse_containers():
     sparse = pytest.importorskip("scipy.sparse")
     da = pytest.importorskip("dask.array")