Repository: modin-project/modin

Issue:
REFACTOR: pass tz_convert and tz_localize directly to query compiler
this is porting commit https://github.com/ponder-org/modin-public/commit/844d6a146fbe8d952f20bbea6725005f4f00b791

modin API layer shouldn’t assume that it’s cheap to create pandas.Series or to do operations on the index. that should be a choice of the particular engine.


Discussion:

Resolving patch:
diff --git a/modin/core/storage_formats/base/query_compiler.py b/modin/core/storage_formats/base/query_compiler.py
--- a/modin/core/storage_formats/base/query_compiler.py
+++ b/modin/core/storage_formats/base/query_compiler.py
@@ -4206,6 +4206,94 @@ def set_index_names(self, names, axis=0):
 
     # DateTime methods
 
+    def tz_convert(
+        self,
+        tz,
+        axis=0,
+        level=None,
+        copy=True,
+    ):
+        """
+        Convert tz-aware axis to target time zone.
+
+        Parameters
+        ----------
+        tz : str or tzinfo object or None
+            Target time zone. Passing None will convert to UTC
+            and remove the timezone information.
+        axis : int, default: 0
+            The axis to localize.
+        level : int, str, default: None
+            If axis is a MultiIndex, convert a specific level. Otherwise must be None.
+        copy : bool, default: True
+            Also make a copy of the underlying data.
+
+        Returns
+        -------
+        BaseQueryCompiler
+            A new query compiler with the converted axis.
+        """
+        if level is not None:
+            new_labels = (
+                pandas.Series(index=self.get_axis(axis))
+                .tz_convert(tz, level=level)
+                .index
+            )
+        else:
+            new_labels = self.get_axis(axis).tz_convert(tz)
+        obj = self.copy() if copy else self
+        if axis == 0:
+            obj.index = new_labels
+        else:
+            obj.columns = new_labels
+        return obj
+
+    def tz_localize(
+        self, tz, axis=0, level=None, copy=True, ambiguous="raise", nonexistent="raise"
+    ):
+        """
+        Localize tz-naive index of a Series or DataFrame to target time zone.
+
+        Parameters
+        ----------
+        tz : tzstr or tzinfo or None
+            Time zone to localize. Passing None will remove the time zone
+            information and preserve local time.
+        axis : int, default: 0
+            The axis to localize.
+        level : int, str, default: None
+            If axis is a MultiIndex, localize a specific level. Otherwise must be None.
+        copy : bool, default: True
+            Also make a copy of the underlying data.
+        ambiguous : str, bool-ndarray, NaT, default: "raise"
+            Behaviour on ambiguous times.
+        nonexistent : str, default: "raise"
+            What to do with nonexistent times.
+
+        Returns
+        -------
+        BaseQueryCompiler
+            A new query compiler with the localized axis.
+        """
+        new_labels = (
+            pandas.Series(index=self.get_axis(axis))
+            .tz_localize(
+                tz,
+                axis=axis,
+                level=level,
+                copy=False,
+                ambiguous=ambiguous,
+                nonexistent=nonexistent,
+            )
+            .index
+        )
+        obj = self.copy() if copy else self
+        if axis == 0:
+            obj.index = new_labels
+        else:
+            obj.columns = new_labels
+        return obj
+
     @doc_utils.doc_dt_round(refer_to="ceil")
     def dt_ceil(self, freq, ambiguous="raise", nonexistent="raise"):
         return DateTimeDefault.register(pandas.Series.dt.ceil)(
diff --git a/modin/pandas/base.py b/modin/pandas/base.py
--- a/modin/pandas/base.py
+++ b/modin/pandas/base.py
@@ -3461,15 +3461,12 @@ def tz_convert(self, tz, axis=0, level=None, copy=True):  # noqa: PR01, RT01, D2
         """
         Convert tz-aware axis to target time zone.
         """
-        axis = self._get_axis_number(axis)
-        if level is not None:
-            new_labels = (
-                pandas.Series(index=self.axes[axis]).tz_convert(tz, level=level).index
-            )
-        else:
-            new_labels = self.axes[axis].tz_convert(tz)
-        obj = self.copy() if copy else self
-        return obj.set_axis(new_labels, axis, copy=copy)
+        return self._create_or_update_from_compiler(
+            self._query_compiler.tz_convert(
+                tz, axis=self._get_axis_number(axis), level=level, copy=True
+            ),
+            inplace=(not copy),
+        )
 
     def tz_localize(
         self, tz, axis=0, level=None, copy=True, ambiguous="raise", nonexistent="raise"
@@ -3477,20 +3474,17 @@ def tz_localize(
         """
         Localize tz-naive index of a `BasePandasDataset` to target time zone.
         """
-        axis = self._get_axis_number(axis)
-        new_labels = (
-            pandas.Series(index=self.axes[axis])
-            .tz_localize(
+        return self._create_or_update_from_compiler(
+            self._query_compiler.tz_localize(
                 tz,
-                axis=axis,
+                axis=self._get_axis_number(axis),
                 level=level,
-                copy=False,
+                copy=True,
                 ambiguous=ambiguous,
                 nonexistent=nonexistent,
-            )
-            .index
+            ),
+            inplace=(not copy),
         )
-        return self.set_axis(new_labels, axis, copy=copy)
 
     def interpolate(
         self,


Test patch: