Repository: ibis-project/ibis

Issue:
refactor: simplify convert_datetime64_to_timestamp in pandas/dask backends
https://github.com/ibis-project/ibis/pull/2541#discussion_r533426767

We go out of our way to support object typed datetimes (https://github.com/ibis-project/ibis/pull/2541#discussion_r533426767) 


Discussion:

Resolving patch:
diff --git a/ibis/backends/dask/client.py b/ibis/backends/dask/client.py
--- a/ibis/backends/dask/client.py
+++ b/ibis/backends/dask/client.py
@@ -1,8 +1,6 @@
 """The dask client implementation."""
-from functools import partial
 
 import dask.dataframe as dd
-import dateutil.parser
 import numpy as np
 import pandas as pd
 from pandas.api.types import DatetimeTZDtype
@@ -15,7 +13,6 @@
     PANDAS_DATE_TYPES,
     PANDAS_STRING_TYPES,
     _inferable_pandas_dtypes,
-    convert_timezone,
     ibis_dtype_to_pandas,
     ibis_schema_to_pandas,
 )
@@ -84,33 +81,6 @@ def convert_datetimetz_to_timestamp(in_dtype, out_dtype, column):
 DASK_DATE_TYPES = PANDAS_DATE_TYPES
 
 
-@sch.convert.register(np.dtype, dt.Timestamp, dd.Series)
-def convert_datetime64_to_timestamp(in_dtype, out_dtype, column):
-    if in_dtype.type == np.datetime64:
-        return column.astype(out_dtype.to_dask())
-    try:
-        # TODO - check this?
-        series = pd.to_datetime(column, utc=True)
-    except pd.errors.OutOfBoundsDatetime:
-        inferred_dtype = infer_dask_dtype(column, skipna=True)
-        if inferred_dtype in DASK_DATE_TYPES:
-            # not great, but not really any other option
-            return column.map(
-                partial(convert_timezone, timezone=out_dtype.timezone)
-            )
-        if inferred_dtype not in DASK_STRING_TYPES:
-            raise TypeError(
-                (
-                    'Conversion to timestamp not supported for Series of type '
-                    '{!r}'
-                ).format(inferred_dtype)
-            )
-        return column.map(dateutil.parser.parse)
-    else:
-        utc_dtype = DatetimeTZDtype('ns', 'UTC')
-        return series.astype(utc_dtype).dt.tz_convert(out_dtype.timezone)
-
-
 @sch.convert.register(np.dtype, dt.Interval, dd.Series)
 def convert_any_to_interval(_, out_dtype, column):
     return column.values.astype(out_dtype.to_dask())
diff --git a/ibis/backends/pandas/client.py b/ibis/backends/pandas/client.py
--- a/ibis/backends/pandas/client.py
+++ b/ibis/backends/pandas/client.py
@@ -1,10 +1,7 @@
 """The pandas client implementation."""
-from functools import partial
 
-import dateutil.parser
 import numpy as np
 import pandas as pd
-import pytz
 import toolz
 from pandas.api.types import CategoricalDtype, DatetimeTZDtype
 
@@ -248,52 +245,10 @@ def convert_datetimetz_to_timestamp(in_dtype, out_dtype, column):
     return column.astype(out_dtype.to_pandas(), errors='ignore')
 
 
-def convert_timezone(obj, timezone):
-    """Convert `obj` to the timezone `timezone`.
-
-    Parameters
-    ----------
-    obj : datetime.date or datetime.datetime
-
-    Returns
-    -------
-    type(obj)
-    """
-    if timezone is None:
-        return obj.replace(tzinfo=None)
-    return pytz.timezone(timezone).localize(obj)
-
-
 PANDAS_STRING_TYPES = {'string', 'unicode', 'bytes'}
 PANDAS_DATE_TYPES = {'datetime', 'datetime64', 'date'}
 
 
-@sch.convert.register(np.dtype, dt.Timestamp, pd.Series)
-def convert_datetime64_to_timestamp(in_dtype, out_dtype, column):
-    if in_dtype.type == np.datetime64:
-        return column.astype(out_dtype.to_pandas(), errors='ignore')
-    try:
-        series = pd.to_datetime(column, utc=True)
-    except pd.errors.OutOfBoundsDatetime:
-        inferred_dtype = infer_pandas_dtype(column, skipna=True)
-        if inferred_dtype in PANDAS_DATE_TYPES:
-            # not great, but not really any other option
-            return column.map(
-                partial(convert_timezone, timezone=out_dtype.timezone)
-            )
-        if inferred_dtype not in PANDAS_STRING_TYPES:
-            raise TypeError(
-                (
-                    'Conversion to timestamp not supported for Series of type '
-                    '{!r}'
-                ).format(inferred_dtype)
-            )
-        return column.map(dateutil.parser.parse)
-    else:
-        utc_dtype = DatetimeTZDtype('ns', 'UTC')
-        return series.astype(utc_dtype).dt.tz_convert(out_dtype.timezone)
-
-
 @sch.convert.register(np.dtype, dt.Interval, pd.Series)
 def convert_any_to_interval(_, out_dtype, column):
     return column.values.astype(out_dtype.to_pandas())
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -57,7 +57,6 @@
     "numpy>=1,<2",
     "pandas>=1.2.5,<2",
     "parsy>=1.3.0,<2",
-    "pytz>=2021.1,<2022.0",
     "regex>=2021.7.6,<2022.0.0",
     "toolz>=0.11,<0.12",
 ]


Test patch: