Skip to content

Commit a4efa9f

Browse files
authored
BUG: first("2M") returning incorrect results (#38446)
1 parent d585a6c commit a4efa9f

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

doc/source/whatsnew/v1.3.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ Categorical
176176
Datetimelike
177177
^^^^^^^^^^^^
178178
- Bug in :class:`DataFrame` and :class:`Series` constructors sometimes dropping nanoseconds from :class:`Timestamp` (resp. :class:`Timedelta`) ``data``, with ``dtype=datetime64[ns]`` (resp. ``timedelta64[ns]``) (:issue:`38032`)
179-
-
179+
- Bug in :meth:`DataFrame.first` and :meth:`Series.first` returning two months for offset one month when first day is last calendar day (:issue:`29623`)
180180
-
181181

182182
Timedelta

pandas/core/generic.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -8424,7 +8424,12 @@ def first(self: FrameOrSeries, offset) -> FrameOrSeries:
84248424
return self
84258425

84268426
offset = to_offset(offset)
8427-
end_date = end = self.index[0] + offset
8427+
if not isinstance(offset, Tick) and offset.is_on_offset(self.index[0]):
8428+
# GH#29623 if first value is end of period, remove offset with n = 1
8429+
# before adding the real offset
8430+
end_date = end = self.index[0] - offset.base + offset
8431+
else:
8432+
end_date = end = self.index[0] + offset
84288433

84298434
# Tick-like, e.g. 3 weeks
84308435
if isinstance(offset, Tick):

pandas/tests/frame/methods/test_first_and_last.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44
import pytest
55

6-
from pandas import DataFrame
6+
from pandas import DataFrame, bdate_range
77
import pandas._testing as tm
88

99

@@ -69,3 +69,22 @@ def test_last_subset(self, frame_or_series):
6969

7070
result = ts[:0].last("3M")
7171
tm.assert_equal(result, ts[:0])
72+
73+
@pytest.mark.parametrize("start, periods", [("2010-03-31", 1), ("2010-03-30", 2)])
74+
def test_first_with_first_day_last_of_month(self, frame_or_series, start, periods):
75+
# GH#29623
76+
x = frame_or_series([1] * 100, index=bdate_range(start, periods=100))
77+
result = x.first("1M")
78+
expected = frame_or_series(
79+
[1] * periods, index=bdate_range(start, periods=periods)
80+
)
81+
tm.assert_equal(result, expected)
82+
83+
def test_first_with_first_day_end_of_frq_n_greater_one(self, frame_or_series):
84+
# GH#29623
85+
x = frame_or_series([1] * 100, index=bdate_range("2010-03-31", periods=100))
86+
result = x.first("2M")
87+
expected = frame_or_series(
88+
[1] * 23, index=bdate_range("2010-03-31", "2010-04-30")
89+
)
90+
tm.assert_equal(result, expected)

0 commit comments

Comments
 (0)