Repository: pandas-dev/pandas
Pull request: BUG: Make sure correct values are passed to Rolling._on when axis=1
- [x] closes #28192
- [x] tests added / passed
- [x] passes `black pandas`
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry


Problem statement:
Rolling with offset and axis=1
#### Code Sample

Here I have a DataFrame with a DatetimeIndex for the columns:
```python
cols = pd.date_range('2019-8-01', '2019-08-07', freq='D')
data = np.ones((5, len(cols)))
df = pd.DataFrame(data, columns=cols)
df.rolling('1d', axis=1).sum()
```
The above gives 'ValueError: window must be an integer'

Here I have a DataFrame with a DatetimeIndex for the rows:
```python
df2 = df.transpose()
df2.rolling('2d', axis=0).sum()
```
However this works totally fine.

#### Problem description
I believe there may be a bug: If I have a DatetimeIndex in the columns, specifying an offset for df.rolling does not work but gives a value error (that the window must be an integer). It works however as expected if I transpose the dataframe.

#### Output of ``pd.show_versions()``

<details>

INSTALLED VERSIONS
------------------
commit           : None
python           : 3.7.4.final.0
python-bits      : 64
OS               : Windows
OS-release       : 10
machine          : AMD64
processor        : Intel64 Family 6 Model 158 Stepping 10, GenuineIntel
byteorder        : little
LC_ALL           : None
LANG             : None
LOCALE           : None.None

pandas           : 0.25.1
numpy            : 1.16.4
pytz             : 2019.2
dateutil         : 2.8.0
pip              : 19.2.2
setuptools       : 41.0.1
Cython           : None
pytest           : None
hypothesis       : None
sphinx           : None
blosc            : None
feather          : None
xlsxwriter       : None
lxml.etree       : None
html5lib         : None
pymysql          : None
psycopg2         : None
jinja2           : 2.10.1
IPython          : 7.7.0
pandas_datareader: None
bs4              : None
bottleneck       : None
fastparquet      : None
gcsfs            : None
lxml.etree       : None
matplotlib       : 3.1.0
numexpr          : None
odfpy            : None
openpyxl         : 2.6.2
pandas_gbq       : None
pyarrow          : None
pytables         : None
s3fs             : None
scipy            : 1.3.1
sqlalchemy       : None
tables           : None
xarray           : None
xlrd             : 1.2.0
xlwt             : None
xlsxwriter       : None

</details>

Hints from issue discussion:
Our support for rolling across axis=1 is less tested and feature complete than axis=0 so not terribly surprising. If you'd like to investigate and submit a PR would certainly be welcome
In your example with `axis=0`, then in `Rolling.validate` from `pandas/core/windows/rolling.py`, `self.is_datetimelike` returns True, while for `axis=1` it returns False. If you're not working on this, I'd be interested in giving it a go

Commit message: Make sure correct values are passed to Rolling._on when axis=1

Patch to review:
diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst
index cd0714838a3f1..f6b497486c324 100644
--- a/doc/source/whatsnew/v1.0.0.rst
+++ b/doc/source/whatsnew/v1.0.0.rst
@@ -177,7 +177,7 @@ Groupby/resample/rolling
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
 -
--
+- Bug in :meth:`DataFrame.rolling` not allowing for rolling over datetimes when ``axis=1`` (:issue: `28192`)
 - Bug in :meth:`DataFrame.groupby` not offering selection by column name when ``axis=1`` (:issue:`27614`)
 - Bug in :meth:`DataFrameGroupby.agg` not able to use lambda function with named aggregation (:issue:`27519`)
 
diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py
index a7e122fa3528f..08a8d66d980cf 100644
--- a/pandas/core/window/rolling.py
+++ b/pandas/core/window/rolling.py
@@ -1653,7 +1653,10 @@ def is_datetimelike(self):
     def _on(self):
 
         if self.on is None:
-            return self.obj.index
+            if self.axis == 0:
+                return self.obj.index
+            elif self.axis == 1:
+                return self.obj.transpose().index
         elif isinstance(self.obj, ABCDataFrame) and self.on in self.obj.columns:
             return Index(self.obj[self.on])
         else:
diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py
index b4787bf25e3bb..62aa222450d62 100644
--- a/pandas/tests/window/test_rolling.py
+++ b/pandas/tests/window/test_rolling.py
@@ -334,3 +334,26 @@ def test_readonly_array(self):
         result = pd.Series(arr).rolling(2).mean()
         expected = pd.Series([np.nan, 2, np.nan, np.nan, 4])
         tm.assert_series_equal(result, expected)
+
+    def test_rolling_datetime(self, axis_frame):
+        # GH-28192
+        df = pd.DataFrame(
+            {i: [1] * 2 for i in pd.date_range("2019-8-01", "2019-08-03", freq="D")}
+        )
+        if axis_frame in [0, "index"]:
+            result = df.T.rolling("2d", axis=axis_frame).sum().T
+        else:
+            result = df.rolling("2d", axis=axis_frame).sum()
+        expected = pd.DataFrame(
+            {
+                **{
+                    i: [1.0] * 2
+                    for i in pd.date_range("2019-8-01", periods=1, freq="D")
+                },
+                **{
+                    i: [2.0] * 2
+                    for i in pd.date_range("2019-8-02", "2019-8-03", freq="D")
+                },
+            }
+        )
+        tm.assert_frame_equal(result, expected)


Code review comments:
diff_hunk: @@ -1653,7 +1653,10 @@ def is_datetimelike(self):
     def _on(self):
 
         if self.on is None:
-            return self.obj.index
+            if self.axis == 0:
+                return self.obj.index
+            elif self.axis == 1:
+                return self.obj.transpose().index
path: pandas/core/window/rolling.py
text: @user1:
I think we can just call `self.obj.columns` instead of having to transpose.