Repository: dask/dask

Issue:
AttributeError on to_datetime
**What happened**:
Convert a string format date into datetime gets an error
See the example bellow:

import dask.dataframe as dd
dd.to_datetime('2021-08-03')

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-2-3e93e29fddd0> in <module>
----> 1 dd.to_datetime('2021-08-03')

~\Anaconda3\lib\site-packages\dask\dataframe\core.py in to_datetime(arg, meta, **kwargs)
   6240         else:
   6241             meta = pd.Series([pd.Timestamp("2000")])
-> 6242             meta.index = meta.index.astype(arg.index.dtype)
   6243             meta.index.name = arg.index.name
   6244     return map_partitions(pd.to_datetime, arg, meta=meta, **kwargs)

AttributeError: 'builtin_function_or_method' object has no attribute 'dtype'
---------------------------------------------------------------------------

**What you expected to happen**:
Like in pandas, I would like to see:

import pandas as pd
pd.to_datetime('2021-08-03')

Result:
Timestamp('2021-08-03 00:00:00')


**Environment**:

- Dask version: 2.30.0
- Python version: 3.8.5
- Operating System: Windows 10.0.18363.1621
- Install method (conda, pip, source): python -m pip install "dask[complete]"
However, I'm using Anaconda and dask was already installed before the pip command



Discussion:
I can reproduce. I'll try to take a look shortly.
Hey @jsignell I happened to be checking this out about at the same time. It looks if `meta` is not passed to `to_datetime` and the argument is not of type `Index`, then the arg is assumed to be a DataFrame or Series object (or something else with the `index` attr). Should str or int (any scalar for that matter) arguments get an additional branch in the function logic (since they lack an `index` attribute)? I struggle to see when Dask would be beneficial with scalar type inputs to `to_datetime`. @ohbtorres what kind of use case are you targeting here? Perhaps the `meta` argument may be helpful?
I expect that the issue is not that `dd.to_dataframe` is beneficial with scalars per-se, but rather that it is not always clear that the output of a particular function will be a scalar or something else and it can be confusing to get a random error. A valid solution here might be to raise a `NotImplementedError` for scalar input.
Agreed with raising a clear error message here. I think there's some ambiguity about the expected result type. I could see arguments for either a `pd.Timestamp` or a `delayed(pd.Timestamp)`. So let's just have the user choose by using those.

Resolving patch:
diff --git a/dask/dataframe/core.py b/dask/dataframe/core.py
--- a/dask/dataframe/core.py
+++ b/dask/dataframe/core.py
@@ -6811,6 +6811,11 @@ def to_datetime(arg, meta=None, **kwargs):
         if isinstance(arg, Index):
             meta = pd.DatetimeIndex([])
             meta.name = arg.name
+        elif not (is_dataframe_like(arg) or is_series_like(arg)):
+            raise NotImplementedError(
+                "dask.dataframe.to_datetime does not support "
+                "non-index-able arguments (like scalars)"
+            )
         else:
             meta = pd.Series([pd.Timestamp("2000")])
             meta.index = meta.index.astype(arg.index.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
@@ -3994,6 +3994,10 @@ def test_to_datetime():
         check_divisions=False,
     )
 
+    for arg in ("2021-08-03", 2021):
+        with pytest.raises(NotImplementedError, match="non-index-able arguments"):
+            dd.to_datetime(arg)
+
 
 def test_to_timedelta():
     s = pd.Series(range(10))