We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Implement Interval arithmetic on one or more backends
After subtraction is in from #1489, we'll want to implement this on at least one backend.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ibis/pandas/execution/temporal.py`
Content:
```
1 import datetime
2 
3 import numpy as np
4 import pandas as pd
5 from pandas.core.groupby import SeriesGroupBy
6 
7 import ibis
8 import ibis.expr.datatypes as dt
9 import ibis.expr.operations as ops
10 from ibis.pandas.core import (
11     date_types,
12     integer_types,
13     numeric_types,
14     timedelta_types,
15     timestamp_types,
16 )
17 from ibis.pandas.dispatch import execute_node, pre_execute
18 
19 
20 @execute_node.register(ops.Strftime, pd.Timestamp, str)
21 def execute_strftime_timestamp_str(op, data, format_string, **kwargs):
22     return data.strftime(format_string)
23 
24 
25 @execute_node.register(ops.Strftime, pd.Series, str)
26 def execute_strftime_series_str(op, data, format_string, **kwargs):
27     return data.dt.strftime(format_string)
28 
29 
30 @execute_node.register(ops.ExtractTemporalField, pd.Timestamp)
31 def execute_extract_timestamp_field_timestamp(op, data, **kwargs):
32     field_name = type(op).__name__.lower().replace('extract', '')
33     return getattr(data, field_name)
34 
35 
36 @execute_node.register(ops.ExtractMillisecond, pd.Timestamp)
37 def execute_extract_millisecond_timestamp(op, data, **kwargs):
38     return int(data.microsecond // 1000.0)
39 
40 
41 @execute_node.register(ops.ExtractTemporalField, pd.Series)
42 def execute_extract_timestamp_field_series(op, data, **kwargs):
43     field_name = type(op).__name__.lower().replace('extract', '')
44     return getattr(data.dt, field_name).astype(np.int32)
45 
46 
47 @execute_node.register(
48     ops.BetweenTime,
49     pd.Series,
50     (pd.Series, str, datetime.time),
51     (pd.Series, str, datetime.time),
52 )
53 def execute_between_time(op, data, lower, upper, **kwargs):
54     indexer = pd.DatetimeIndex(data).indexer_between_time(lower, upper)
55     result = np.zeros(len(data), dtype=np.bool_)
56     result[indexer] = True
57     return pd.Series(result)
58 
59 
60 @execute_node.register(ops.Date, pd.Series)
61 def execute_timestamp_date(op, data, **kwargs):
62     return data.dt.floor('d')
63 
64 
65 @execute_node.register((ops.TimestampTruncate, ops.DateTruncate), pd.Series)
66 def execute_timestamp_truncate(op, data, **kwargs):
67     dtype = 'datetime64[{}]'.format(op.unit)
68     array = data.values.astype(dtype)
69     return pd.Series(array, name=data.name)
70 
71 
72 OFFSET_CLASS = {
73     "Y": pd.offsets.DateOffset,
74     "Q": pd.offsets.DateOffset,
75     "M": pd.offsets.DateOffset,
76     "W": pd.offsets.DateOffset,
77     # all other units are timedelta64s
78 }
79 
80 
81 @execute_node.register(ops.IntervalFromInteger, pd.Series)
82 def execute_interval_from_integer_series(op, data, **kwargs):
83     unit = op.unit
84     resolution = "{}s".format(op.resolution)
85     cls = OFFSET_CLASS.get(unit, None)
86 
87     # fast path for timedelta conversion
88     if cls is None:
89         return data.astype("timedelta64[{}]".format(unit))
90     return data.apply(
91         lambda n, cls=cls, resolution=resolution: cls(**{resolution: n})
92     )
93 
94 
95 @execute_node.register(ops.IntervalFromInteger, integer_types)
96 def execute_interval_from_integer_integer_types(op, data, **kwargs):
97     unit = op.unit
98     resolution = "{}s".format(op.resolution)
99     cls = OFFSET_CLASS.get(unit, None)
100 
101     if cls is None:
102         return pd.Timedelta(data, unit=unit)
103     return cls(**{resolution: data})
104 
105 
106 @execute_node.register(ops.Cast, pd.Series, dt.Interval)
107 def execute_cast_integer_to_interval_series(op, data, type, **kwargs):
108     to = op.to
109     unit = to.unit
110     resolution = "{}s".format(to.resolution)
111     cls = OFFSET_CLASS.get(unit, None)
112 
113     if cls is None:
114         return data.astype("timedelta64[{}]".format(unit))
115     return data.apply(
116         lambda n, cls=cls, resolution=resolution: cls(**{resolution: n})
117     )
118 
119 
120 @execute_node.register(ops.Cast, integer_types, dt.Interval)
121 def execute_cast_integer_to_interval_integer_types(op, data, type, **kwargs):
122     to = op.to
123     unit = to.unit
124     resolution = "{}s".format(to.resolution)
125     cls = OFFSET_CLASS.get(unit, None)
126 
127     if cls is None:
128         return pd.Timedelta(data, unit=unit)
129     return cls(**{resolution: data})
130 
131 
132 @execute_node.register(ops.TimestampAdd, timestamp_types, timedelta_types)
133 def execute_timestamp_add_datetime_timedelta(op, left, right, **kwargs):
134     return pd.Timestamp(left) + pd.Timedelta(right)
135 
136 
137 @execute_node.register(ops.TimestampAdd, timestamp_types, pd.Series)
138 def execute_timestamp_add_datetime_series(op, left, right, **kwargs):
139     return pd.Timestamp(left) + right
140 
141 
142 @execute_node.register(ops.IntervalAdd, timedelta_types, timedelta_types)
143 def execute_interval_add_delta_delta(op, left, right, **kwargs):
144     return op.op(pd.Timedelta(left), pd.Timedelta(right))
145 
146 
147 @execute_node.register(ops.IntervalAdd, timedelta_types, pd.Series)
148 @execute_node.register(
149     ops.IntervalMultiply, timedelta_types, numeric_types + (pd.Series,)
150 )
151 def execute_interval_add_multiply_delta_series(op, left, right, **kwargs):
152     return op.op(pd.Timedelta(left), right)
153 
154 
155 @execute_node.register(
156     (ops.TimestampAdd, ops.IntervalAdd), pd.Series, timedelta_types
157 )
158 def execute_timestamp_interval_add_series_delta(op, left, right, **kwargs):
159     return left + pd.Timedelta(right)
160 
161 
162 @execute_node.register(
163     (ops.TimestampAdd, ops.IntervalAdd), pd.Series, pd.Series
164 )
165 def execute_timestamp_interval_add_series_series(op, left, right, **kwargs):
166     return left + right
167 
168 
169 @execute_node.register(ops.TimestampSub, timestamp_types, timedelta_types)
170 def execute_timestamp_sub_datetime_timedelta(op, left, right, **kwargs):
171     return pd.Timestamp(left) - pd.Timedelta(right)
172 
173 
174 @execute_node.register(
175     (ops.TimestampDiff, ops.TimestampSub), timestamp_types, pd.Series
176 )
177 def execute_timestamp_diff_sub_datetime_series(op, left, right, **kwargs):
178     return pd.Timestamp(left) - right
179 
180 
181 @execute_node.register(ops.TimestampSub, pd.Series, timedelta_types)
182 def execute_timestamp_sub_series_timedelta(op, left, right, **kwargs):
183     return left - pd.Timedelta(right)
184 
185 
186 @execute_node.register(
187     (ops.TimestampDiff, ops.TimestampSub), pd.Series, pd.Series
188 )
189 def execute_timestamp_diff_sub_series_series(op, left, right, **kwargs):
190     return left - right
191 
192 
193 @execute_node.register(ops.TimestampDiff, timestamp_types, timestamp_types)
194 def execute_timestamp_diff_datetime_datetime(op, left, right, **kwargs):
195     return pd.Timestamp(left) - pd.Timestamp(right)
196 
197 
198 @execute_node.register(ops.TimestampDiff, pd.Series, timestamp_types)
199 def execute_timestamp_diff_series_datetime(op, left, right, **kwargs):
200     return left - pd.Timestamp(right)
201 
202 
203 @execute_node.register(
204     ops.IntervalMultiply, pd.Series, numeric_types + (pd.Series,)
205 )
206 @execute_node.register(
207     ops.IntervalFloorDivide,
208     (pd.Timedelta, pd.Series),
209     numeric_types + (pd.Series,),
210 )
211 def execute_interval_multiply_fdiv_series_numeric(op, left, right, **kwargs):
212     return op.op(left, right)
213 
214 
215 @execute_node.register(ops.TimestampFromUNIX, (pd.Series,) + integer_types)
216 def execute_timestamp_from_unix(op, data, **kwargs):
217     return pd.to_datetime(data, unit=op.unit)
218 
219 
220 @pre_execute.register(ops.TimestampNow)
221 @pre_execute.register(ops.TimestampNow, ibis.client.Client)
222 def pre_execute_timestamp_now(op, *args, **kwargs):
223     return {op: pd.Timestamp('now')}
224 
225 
226 @execute_node.register(ops.DayOfWeekIndex, (str, datetime.date))
227 def execute_day_of_week_index_any(op, value, **kwargs):
228     return pd.Timestamp(value).dayofweek
229 
230 
231 @execute_node.register(ops.DayOfWeekIndex, pd.Series)
232 def execute_day_of_week_index_series(op, data, **kwargs):
233     return data.dt.dayofweek.astype(np.int16)
234 
235 
236 @execute_node.register(ops.DayOfWeekIndex, SeriesGroupBy)
237 def execute_day_of_week_index_series_group_by(op, data, **kwargs):
238     groupings = data.grouper.groupings
239     return data.obj.dt.dayofweek.astype(np.int16).groupby(groupings)
240 
241 
242 def day_name(obj):
243     """Backwards compatible name of day getting function.
244 
245     Parameters
246     ----------
247     obj : Union[Series, pd.Timestamp]
248 
249     Returns
250     -------
251     str
252         The name of the day corresponding to `obj`
253     """
254     try:
255         return obj.day_name()
256     except AttributeError:
257         return obj.weekday_name
258 
259 
260 @execute_node.register(ops.DayOfWeekName, (str, datetime.date))
261 def execute_day_of_week_name_any(op, value, **kwargs):
262     return day_name(pd.Timestamp(value))
263 
264 
265 @execute_node.register(ops.DayOfWeekName, pd.Series)
266 def execute_day_of_week_name_series(op, data, **kwargs):
267     return day_name(data.dt)
268 
269 
270 @execute_node.register(ops.DayOfWeekName, SeriesGroupBy)
271 def execute_day_of_week_name_series_group_by(op, data, **kwargs):
272     return day_name(data.obj.dt).groupby(data.grouper.groupings)
273 
274 
275 @execute_node.register(ops.DateSub, date_types, timedelta_types)
276 @execute_node.register((ops.DateDiff, ops.DateSub), date_types, pd.Series)
277 @execute_node.register(ops.DateSub, pd.Series, timedelta_types)
278 @execute_node.register((ops.DateDiff, ops.DateSub), pd.Series, pd.Series)
279 @execute_node.register(ops.DateDiff, date_types, date_types)
280 @execute_node.register(ops.DateDiff, pd.Series, date_types)
281 def execute_date_sub_diff(op, left, right, **kwargs):
282     return left - right
283 
284 
285 @execute_node.register(ops.DateAdd, pd.Series, timedelta_types)
286 @execute_node.register(ops.DateAdd, timedelta_types, pd.Series)
287 @execute_node.register(ops.DateAdd, pd.Series, pd.Series)
288 @execute_node.register(ops.DateAdd, date_types, timedelta_types)
289 @execute_node.register(ops.DateAdd, timedelta_types, date_types)
290 @execute_node.register(ops.DateAdd, date_types, pd.Series)
291 @execute_node.register(ops.DateAdd, pd.Series, date_types)
292 def execute_date_add(op, left, right, **kwargs):
293     return left + right
294
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/ibis/pandas/execution/temporal.py b/ibis/pandas/execution/temporal.py
--- a/ibis/pandas/execution/temporal.py
+++ b/ibis/pandas/execution/temporal.py
@@ -184,7 +184,9 @@
 
 
 @execute_node.register(
-    (ops.TimestampDiff, ops.TimestampSub), pd.Series, pd.Series
+    (ops.TimestampDiff, ops.TimestampSub, ops.IntervalSubtract),
+    pd.Series,
+    pd.Series
 )
 def execute_timestamp_diff_sub_series_series(op, left, right, **kwargs):
     return left - right

{"golden_diff": "diff --git a/ibis/pandas/execution/temporal.py b/ibis/pandas/execution/temporal.py\n--- a/ibis/pandas/execution/temporal.py\n+++ b/ibis/pandas/execution/temporal.py\n@@ -184,7 +184,9 @@\n \n \n @execute_node.register(\n-    (ops.TimestampDiff, ops.TimestampSub), pd.Series, pd.Series\n+    (ops.TimestampDiff, ops.TimestampSub, ops.IntervalSubtract),\n+    pd.Series,\n+    pd.Series\n )\n def execute_timestamp_diff_sub_series_series(op, left, right, **kwargs):\n     return left - right\n", "issue": "Implement Interval arithmetic on one or more backends\nAfter subtraction is in from #1489, we'll want to implement this on at least one backend.\n", "before_files": [{"content": "import datetime\n\nimport numpy as np\nimport pandas as pd\nfrom pandas.core.groupby import SeriesGroupBy\n\nimport ibis\nimport ibis.expr.datatypes as dt\nimport ibis.expr.operations as ops\nfrom ibis.pandas.core import (\n    date_types,\n    integer_types,\n    numeric_types,\n    timedelta_types,\n    timestamp_types,\n)\nfrom ibis.pandas.dispatch import execute_node, pre_execute\n\n\n@execute_node.register(ops.Strftime, pd.Timestamp, str)\ndef execute_strftime_timestamp_str(op, data, format_string, **kwargs):\n    return data.strftime(format_string)\n\n\n@execute_node.register(ops.Strftime, pd.Series, str)\ndef execute_strftime_series_str(op, data, format_string, **kwargs):\n    return data.dt.strftime(format_string)\n\n\n@execute_node.register(ops.ExtractTemporalField, pd.Timestamp)\ndef execute_extract_timestamp_field_timestamp(op, data, **kwargs):\n    field_name = type(op).__name__.lower().replace('extract', '')\n    return getattr(data, field_name)\n\n\n@execute_node.register(ops.ExtractMillisecond, pd.Timestamp)\ndef execute_extract_millisecond_timestamp(op, data, **kwargs):\n    return int(data.microsecond // 1000.0)\n\n\n@execute_node.register(ops.ExtractTemporalField, pd.Series)\ndef execute_extract_timestamp_field_series(op, data, **kwargs):\n    field_name = type(op).__name__.lower().replace('extract', '')\n    return getattr(data.dt, field_name).astype(np.int32)\n\n\n@execute_node.register(\n    ops.BetweenTime,\n    pd.Series,\n    (pd.Series, str, datetime.time),\n    (pd.Series, str, datetime.time),\n)\ndef execute_between_time(op, data, lower, upper, **kwargs):\n    indexer = pd.DatetimeIndex(data).indexer_between_time(lower, upper)\n    result = np.zeros(len(data), dtype=np.bool_)\n    result[indexer] = True\n    return pd.Series(result)\n\n\n@execute_node.register(ops.Date, pd.Series)\ndef execute_timestamp_date(op, data, **kwargs):\n    return data.dt.floor('d')\n\n\n@execute_node.register((ops.TimestampTruncate, ops.DateTruncate), pd.Series)\ndef execute_timestamp_truncate(op, data, **kwargs):\n    dtype = 'datetime64[{}]'.format(op.unit)\n    array = data.values.astype(dtype)\n    return pd.Series(array, name=data.name)\n\n\nOFFSET_CLASS = {\n    \"Y\": pd.offsets.DateOffset,\n    \"Q\": pd.offsets.DateOffset,\n    \"M\": pd.offsets.DateOffset,\n    \"W\": pd.offsets.DateOffset,\n    # all other units are timedelta64s\n}\n\n\n@execute_node.register(ops.IntervalFromInteger, pd.Series)\ndef execute_interval_from_integer_series(op, data, **kwargs):\n    unit = op.unit\n    resolution = \"{}s\".format(op.resolution)\n    cls = OFFSET_CLASS.get(unit, None)\n\n    # fast path for timedelta conversion\n    if cls is None:\n        return data.astype(\"timedelta64[{}]\".format(unit))\n    return data.apply(\n        lambda n, cls=cls, resolution=resolution: cls(**{resolution: n})\n    )\n\n\n@execute_node.register(ops.IntervalFromInteger, integer_types)\ndef execute_interval_from_integer_integer_types(op, data, **kwargs):\n    unit = op.unit\n    resolution = \"{}s\".format(op.resolution)\n    cls = OFFSET_CLASS.get(unit, None)\n\n    if cls is None:\n        return pd.Timedelta(data, unit=unit)\n    return cls(**{resolution: data})\n\n\n@execute_node.register(ops.Cast, pd.Series, dt.Interval)\ndef execute_cast_integer_to_interval_series(op, data, type, **kwargs):\n    to = op.to\n    unit = to.unit\n    resolution = \"{}s\".format(to.resolution)\n    cls = OFFSET_CLASS.get(unit, None)\n\n    if cls is None:\n        return data.astype(\"timedelta64[{}]\".format(unit))\n    return data.apply(\n        lambda n, cls=cls, resolution=resolution: cls(**{resolution: n})\n    )\n\n\n@execute_node.register(ops.Cast, integer_types, dt.Interval)\ndef execute_cast_integer_to_interval_integer_types(op, data, type, **kwargs):\n    to = op.to\n    unit = to.unit\n    resolution = \"{}s\".format(to.resolution)\n    cls = OFFSET_CLASS.get(unit, None)\n\n    if cls is None:\n        return pd.Timedelta(data, unit=unit)\n    return cls(**{resolution: data})\n\n\n@execute_node.register(ops.TimestampAdd, timestamp_types, timedelta_types)\ndef execute_timestamp_add_datetime_timedelta(op, left, right, **kwargs):\n    return pd.Timestamp(left) + pd.Timedelta(right)\n\n\n@execute_node.register(ops.TimestampAdd, timestamp_types, pd.Series)\ndef execute_timestamp_add_datetime_series(op, left, right, **kwargs):\n    return pd.Timestamp(left) + right\n\n\n@execute_node.register(ops.IntervalAdd, timedelta_types, timedelta_types)\ndef execute_interval_add_delta_delta(op, left, right, **kwargs):\n    return op.op(pd.Timedelta(left), pd.Timedelta(right))\n\n\n@execute_node.register(ops.IntervalAdd, timedelta_types, pd.Series)\n@execute_node.register(\n    ops.IntervalMultiply, timedelta_types, numeric_types + (pd.Series,)\n)\ndef execute_interval_add_multiply_delta_series(op, left, right, **kwargs):\n    return op.op(pd.Timedelta(left), right)\n\n\n@execute_node.register(\n    (ops.TimestampAdd, ops.IntervalAdd), pd.Series, timedelta_types\n)\ndef execute_timestamp_interval_add_series_delta(op, left, right, **kwargs):\n    return left + pd.Timedelta(right)\n\n\n@execute_node.register(\n    (ops.TimestampAdd, ops.IntervalAdd), pd.Series, pd.Series\n)\ndef execute_timestamp_interval_add_series_series(op, left, right, **kwargs):\n    return left + right\n\n\n@execute_node.register(ops.TimestampSub, timestamp_types, timedelta_types)\ndef execute_timestamp_sub_datetime_timedelta(op, left, right, **kwargs):\n    return pd.Timestamp(left) - pd.Timedelta(right)\n\n\n@execute_node.register(\n    (ops.TimestampDiff, ops.TimestampSub), timestamp_types, pd.Series\n)\ndef execute_timestamp_diff_sub_datetime_series(op, left, right, **kwargs):\n    return pd.Timestamp(left) - right\n\n\n@execute_node.register(ops.TimestampSub, pd.Series, timedelta_types)\ndef execute_timestamp_sub_series_timedelta(op, left, right, **kwargs):\n    return left - pd.Timedelta(right)\n\n\n@execute_node.register(\n    (ops.TimestampDiff, ops.TimestampSub), pd.Series, pd.Series\n)\ndef execute_timestamp_diff_sub_series_series(op, left, right, **kwargs):\n    return left - right\n\n\n@execute_node.register(ops.TimestampDiff, timestamp_types, timestamp_types)\ndef execute_timestamp_diff_datetime_datetime(op, left, right, **kwargs):\n    return pd.Timestamp(left) - pd.Timestamp(right)\n\n\n@execute_node.register(ops.TimestampDiff, pd.Series, timestamp_types)\ndef execute_timestamp_diff_series_datetime(op, left, right, **kwargs):\n    return left - pd.Timestamp(right)\n\n\n@execute_node.register(\n    ops.IntervalMultiply, pd.Series, numeric_types + (pd.Series,)\n)\n@execute_node.register(\n    ops.IntervalFloorDivide,\n    (pd.Timedelta, pd.Series),\n    numeric_types + (pd.Series,),\n)\ndef execute_interval_multiply_fdiv_series_numeric(op, left, right, **kwargs):\n    return op.op(left, right)\n\n\n@execute_node.register(ops.TimestampFromUNIX, (pd.Series,) + integer_types)\ndef execute_timestamp_from_unix(op, data, **kwargs):\n    return pd.to_datetime(data, unit=op.unit)\n\n\n@pre_execute.register(ops.TimestampNow)\n@pre_execute.register(ops.TimestampNow, ibis.client.Client)\ndef pre_execute_timestamp_now(op, *args, **kwargs):\n    return {op: pd.Timestamp('now')}\n\n\n@execute_node.register(ops.DayOfWeekIndex, (str, datetime.date))\ndef execute_day_of_week_index_any(op, value, **kwargs):\n    return pd.Timestamp(value).dayofweek\n\n\n@execute_node.register(ops.DayOfWeekIndex, pd.Series)\ndef execute_day_of_week_index_series(op, data, **kwargs):\n    return data.dt.dayofweek.astype(np.int16)\n\n\n@execute_node.register(ops.DayOfWeekIndex, SeriesGroupBy)\ndef execute_day_of_week_index_series_group_by(op, data, **kwargs):\n    groupings = data.grouper.groupings\n    return data.obj.dt.dayofweek.astype(np.int16).groupby(groupings)\n\n\ndef day_name(obj):\n    \"\"\"Backwards compatible name of day getting function.\n\n    Parameters\n    ----------\n    obj : Union[Series, pd.Timestamp]\n\n    Returns\n    -------\n    str\n        The name of the day corresponding to `obj`\n    \"\"\"\n    try:\n        return obj.day_name()\n    except AttributeError:\n        return obj.weekday_name\n\n\n@execute_node.register(ops.DayOfWeekName, (str, datetime.date))\ndef execute_day_of_week_name_any(op, value, **kwargs):\n    return day_name(pd.Timestamp(value))\n\n\n@execute_node.register(ops.DayOfWeekName, pd.Series)\ndef execute_day_of_week_name_series(op, data, **kwargs):\n    return day_name(data.dt)\n\n\n@execute_node.register(ops.DayOfWeekName, SeriesGroupBy)\ndef execute_day_of_week_name_series_group_by(op, data, **kwargs):\n    return day_name(data.obj.dt).groupby(data.grouper.groupings)\n\n\n@execute_node.register(ops.DateSub, date_types, timedelta_types)\n@execute_node.register((ops.DateDiff, ops.DateSub), date_types, pd.Series)\n@execute_node.register(ops.DateSub, pd.Series, timedelta_types)\n@execute_node.register((ops.DateDiff, ops.DateSub), pd.Series, pd.Series)\n@execute_node.register(ops.DateDiff, date_types, date_types)\n@execute_node.register(ops.DateDiff, pd.Series, date_types)\ndef execute_date_sub_diff(op, left, right, **kwargs):\n    return left - right\n\n\n@execute_node.register(ops.DateAdd, pd.Series, timedelta_types)\n@execute_node.register(ops.DateAdd, timedelta_types, pd.Series)\n@execute_node.register(ops.DateAdd, pd.Series, pd.Series)\n@execute_node.register(ops.DateAdd, date_types, timedelta_types)\n@execute_node.register(ops.DateAdd, timedelta_types, date_types)\n@execute_node.register(ops.DateAdd, date_types, pd.Series)\n@execute_node.register(ops.DateAdd, pd.Series, date_types)\ndef execute_date_add(op, left, right, **kwargs):\n    return left + right\n", "path": "ibis/pandas/execution/temporal.py"}], "after_files": [{"content": "import datetime\n\nimport numpy as np\nimport pandas as pd\nfrom pandas.core.groupby import SeriesGroupBy\n\nimport ibis\nimport ibis.expr.datatypes as dt\nimport ibis.expr.operations as ops\nfrom ibis.pandas.core import (\n    date_types,\n    integer_types,\n    numeric_types,\n    timedelta_types,\n    timestamp_types,\n)\nfrom ibis.pandas.dispatch import execute_node, pre_execute\n\n\n@execute_node.register(ops.Strftime, pd.Timestamp, str)\ndef execute_strftime_timestamp_str(op, data, format_string, **kwargs):\n    return data.strftime(format_string)\n\n\n@execute_node.register(ops.Strftime, pd.Series, str)\ndef execute_strftime_series_str(op, data, format_string, **kwargs):\n    return data.dt.strftime(format_string)\n\n\n@execute_node.register(ops.ExtractTemporalField, pd.Timestamp)\ndef execute_extract_timestamp_field_timestamp(op, data, **kwargs):\n    field_name = type(op).__name__.lower().replace('extract', '')\n    return getattr(data, field_name)\n\n\n@execute_node.register(ops.ExtractMillisecond, pd.Timestamp)\ndef execute_extract_millisecond_timestamp(op, data, **kwargs):\n    return int(data.microsecond // 1000.0)\n\n\n@execute_node.register(ops.ExtractTemporalField, pd.Series)\ndef execute_extract_timestamp_field_series(op, data, **kwargs):\n    field_name = type(op).__name__.lower().replace('extract', '')\n    return getattr(data.dt, field_name).astype(np.int32)\n\n\n@execute_node.register(\n    ops.BetweenTime,\n    pd.Series,\n    (pd.Series, str, datetime.time),\n    (pd.Series, str, datetime.time),\n)\ndef execute_between_time(op, data, lower, upper, **kwargs):\n    indexer = pd.DatetimeIndex(data).indexer_between_time(lower, upper)\n    result = np.zeros(len(data), dtype=np.bool_)\n    result[indexer] = True\n    return pd.Series(result)\n\n\n@execute_node.register(ops.Date, pd.Series)\ndef execute_timestamp_date(op, data, **kwargs):\n    return data.dt.floor('d')\n\n\n@execute_node.register((ops.TimestampTruncate, ops.DateTruncate), pd.Series)\ndef execute_timestamp_truncate(op, data, **kwargs):\n    dtype = 'datetime64[{}]'.format(op.unit)\n    array = data.values.astype(dtype)\n    return pd.Series(array, name=data.name)\n\n\nOFFSET_CLASS = {\n    \"Y\": pd.offsets.DateOffset,\n    \"Q\": pd.offsets.DateOffset,\n    \"M\": pd.offsets.DateOffset,\n    \"W\": pd.offsets.DateOffset,\n    # all other units are timedelta64s\n}\n\n\n@execute_node.register(ops.IntervalFromInteger, pd.Series)\ndef execute_interval_from_integer_series(op, data, **kwargs):\n    unit = op.unit\n    resolution = \"{}s\".format(op.resolution)\n    cls = OFFSET_CLASS.get(unit, None)\n\n    # fast path for timedelta conversion\n    if cls is None:\n        return data.astype(\"timedelta64[{}]\".format(unit))\n    return data.apply(\n        lambda n, cls=cls, resolution=resolution: cls(**{resolution: n})\n    )\n\n\n@execute_node.register(ops.IntervalFromInteger, integer_types)\ndef execute_interval_from_integer_integer_types(op, data, **kwargs):\n    unit = op.unit\n    resolution = \"{}s\".format(op.resolution)\n    cls = OFFSET_CLASS.get(unit, None)\n\n    if cls is None:\n        return pd.Timedelta(data, unit=unit)\n    return cls(**{resolution: data})\n\n\n@execute_node.register(ops.Cast, pd.Series, dt.Interval)\ndef execute_cast_integer_to_interval_series(op, data, type, **kwargs):\n    to = op.to\n    unit = to.unit\n    resolution = \"{}s\".format(to.resolution)\n    cls = OFFSET_CLASS.get(unit, None)\n\n    if cls is None:\n        return data.astype(\"timedelta64[{}]\".format(unit))\n    return data.apply(\n        lambda n, cls=cls, resolution=resolution: cls(**{resolution: n})\n    )\n\n\n@execute_node.register(ops.Cast, integer_types, dt.Interval)\ndef execute_cast_integer_to_interval_integer_types(op, data, type, **kwargs):\n    to = op.to\n    unit = to.unit\n    resolution = \"{}s\".format(to.resolution)\n    cls = OFFSET_CLASS.get(unit, None)\n\n    if cls is None:\n        return pd.Timedelta(data, unit=unit)\n    return cls(**{resolution: data})\n\n\n@execute_node.register(ops.TimestampAdd, timestamp_types, timedelta_types)\ndef execute_timestamp_add_datetime_timedelta(op, left, right, **kwargs):\n    return pd.Timestamp(left) + pd.Timedelta(right)\n\n\n@execute_node.register(ops.TimestampAdd, timestamp_types, pd.Series)\ndef execute_timestamp_add_datetime_series(op, left, right, **kwargs):\n    return pd.Timestamp(left) + right\n\n\n@execute_node.register(ops.IntervalAdd, timedelta_types, timedelta_types)\ndef execute_interval_add_delta_delta(op, left, right, **kwargs):\n    return op.op(pd.Timedelta(left), pd.Timedelta(right))\n\n\n@execute_node.register(ops.IntervalAdd, timedelta_types, pd.Series)\n@execute_node.register(\n    ops.IntervalMultiply, timedelta_types, numeric_types + (pd.Series,)\n)\ndef execute_interval_add_multiply_delta_series(op, left, right, **kwargs):\n    return op.op(pd.Timedelta(left), right)\n\n\n@execute_node.register(\n    (ops.TimestampAdd, ops.IntervalAdd), pd.Series, timedelta_types\n)\ndef execute_timestamp_interval_add_series_delta(op, left, right, **kwargs):\n    return left + pd.Timedelta(right)\n\n\n@execute_node.register(\n    (ops.TimestampAdd, ops.IntervalAdd), pd.Series, pd.Series\n)\ndef execute_timestamp_interval_add_series_series(op, left, right, **kwargs):\n    return left + right\n\n\n@execute_node.register(ops.TimestampSub, timestamp_types, timedelta_types)\ndef execute_timestamp_sub_datetime_timedelta(op, left, right, **kwargs):\n    return pd.Timestamp(left) - pd.Timedelta(right)\n\n\n@execute_node.register(\n    (ops.TimestampDiff, ops.TimestampSub), timestamp_types, pd.Series\n)\ndef execute_timestamp_diff_sub_datetime_series(op, left, right, **kwargs):\n    return pd.Timestamp(left) - right\n\n\n@execute_node.register(ops.TimestampSub, pd.Series, timedelta_types)\ndef execute_timestamp_sub_series_timedelta(op, left, right, **kwargs):\n    return left - pd.Timedelta(right)\n\n\n@execute_node.register(\n    (ops.TimestampDiff, ops.TimestampSub, ops.IntervalSubtract),\n    pd.Series,\n    pd.Series\n)\ndef execute_timestamp_diff_sub_series_series(op, left, right, **kwargs):\n    return left - right\n\n\n@execute_node.register(ops.TimestampDiff, timestamp_types, timestamp_types)\ndef execute_timestamp_diff_datetime_datetime(op, left, right, **kwargs):\n    return pd.Timestamp(left) - pd.Timestamp(right)\n\n\n@execute_node.register(ops.TimestampDiff, pd.Series, timestamp_types)\ndef execute_timestamp_diff_series_datetime(op, left, right, **kwargs):\n    return left - pd.Timestamp(right)\n\n\n@execute_node.register(\n    ops.IntervalMultiply, pd.Series, numeric_types + (pd.Series,)\n)\n@execute_node.register(\n    ops.IntervalFloorDivide,\n    (pd.Timedelta, pd.Series),\n    numeric_types + (pd.Series,),\n)\ndef execute_interval_multiply_fdiv_series_numeric(op, left, right, **kwargs):\n    return op.op(left, right)\n\n\n@execute_node.register(ops.TimestampFromUNIX, (pd.Series,) + integer_types)\ndef execute_timestamp_from_unix(op, data, **kwargs):\n    return pd.to_datetime(data, unit=op.unit)\n\n\n@pre_execute.register(ops.TimestampNow)\n@pre_execute.register(ops.TimestampNow, ibis.client.Client)\ndef pre_execute_timestamp_now(op, *args, **kwargs):\n    return {op: pd.Timestamp('now')}\n\n\n@execute_node.register(ops.DayOfWeekIndex, (str, datetime.date))\ndef execute_day_of_week_index_any(op, value, **kwargs):\n    return pd.Timestamp(value).dayofweek\n\n\n@execute_node.register(ops.DayOfWeekIndex, pd.Series)\ndef execute_day_of_week_index_series(op, data, **kwargs):\n    return data.dt.dayofweek.astype(np.int16)\n\n\n@execute_node.register(ops.DayOfWeekIndex, SeriesGroupBy)\ndef execute_day_of_week_index_series_group_by(op, data, **kwargs):\n    groupings = data.grouper.groupings\n    return data.obj.dt.dayofweek.astype(np.int16).groupby(groupings)\n\n\ndef day_name(obj):\n    \"\"\"Backwards compatible name of day getting function.\n\n    Parameters\n    ----------\n    obj : Union[Series, pd.Timestamp]\n\n    Returns\n    -------\n    str\n        The name of the day corresponding to `obj`\n    \"\"\"\n    try:\n        return obj.day_name()\n    except AttributeError:\n        return obj.weekday_name\n\n\n@execute_node.register(ops.DayOfWeekName, (str, datetime.date))\ndef execute_day_of_week_name_any(op, value, **kwargs):\n    return day_name(pd.Timestamp(value))\n\n\n@execute_node.register(ops.DayOfWeekName, pd.Series)\ndef execute_day_of_week_name_series(op, data, **kwargs):\n    return day_name(data.dt)\n\n\n@execute_node.register(ops.DayOfWeekName, SeriesGroupBy)\ndef execute_day_of_week_name_series_group_by(op, data, **kwargs):\n    return day_name(data.obj.dt).groupby(data.grouper.groupings)\n\n\n@execute_node.register(ops.DateSub, date_types, timedelta_types)\n@execute_node.register((ops.DateDiff, ops.DateSub), date_types, pd.Series)\n@execute_node.register(ops.DateSub, pd.Series, timedelta_types)\n@execute_node.register((ops.DateDiff, ops.DateSub), pd.Series, pd.Series)\n@execute_node.register(ops.DateDiff, date_types, date_types)\n@execute_node.register(ops.DateDiff, pd.Series, date_types)\ndef execute_date_sub_diff(op, left, right, **kwargs):\n    return left - right\n\n\n@execute_node.register(ops.DateAdd, pd.Series, timedelta_types)\n@execute_node.register(ops.DateAdd, timedelta_types, pd.Series)\n@execute_node.register(ops.DateAdd, pd.Series, pd.Series)\n@execute_node.register(ops.DateAdd, date_types, timedelta_types)\n@execute_node.register(ops.DateAdd, timedelta_types, date_types)\n@execute_node.register(ops.DateAdd, date_types, pd.Series)\n@execute_node.register(ops.DateAdd, pd.Series, date_types)\ndef execute_date_add(op, left, right, **kwargs):\n    return left + right\n", "path": "ibis/pandas/execution/temporal.py"}]}