Skip to content

Commit 7fb453a

Browse files
committed
BUG: fix MS/BMS range generation / onOffset bugs causing #1483
1 parent ae56d6f commit 7fb453a

File tree

4 files changed

+41
-20
lines changed

4 files changed

+41
-20
lines changed

pandas/tseries/offsets.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,7 @@ def apply(self, other):
341341

342342
@classmethod
343343
def onOffset(cls, dt):
344-
firstDay, _ = lib.monthrange(dt.year, dt.month)
345-
return dt.day == (firstDay + 1)
344+
return dt.day == 1
346345

347346
@property
348347
def rule_code(self):
@@ -397,6 +396,16 @@ def apply(self, other):
397396
result = datetime(other.year, other.month, first)
398397
return result
399398

399+
@classmethod
400+
def onOffset(cls, dt):
401+
first_weekday, _ = lib.monthrange(dt.year, dt.month)
402+
if first_weekday == 5:
403+
return dt.day == 3
404+
elif first_weekday == 6:
405+
return dt.day == 2
406+
else:
407+
return dt.day == 1
408+
400409
@property
401410
def rule_code(self):
402411
return 'BMS'

pandas/tseries/resample.py

+20-14
Original file line numberDiff line numberDiff line change
@@ -105,20 +105,7 @@ def _get_time_bins(self, axis):
105105
trimmed = True
106106

107107
ax_values = axis.asi8
108-
bin_edges = binner.asi8
109-
110-
# Some hacks for > daily data, see #1471, #1458
111-
if self.freq != 'D' and is_superperiod(self.freq, 'D'):
112-
day_nanos = _delta_to_nanoseconds(timedelta(1))
113-
if self.closed == 'right':
114-
bin_edges = bin_edges + day_nanos - 1
115-
else:
116-
bin_edges = bin_edges + day_nanos
117-
118-
# intraday values on last day
119-
if bin_edges[-2] > ax_values[-1]:
120-
bin_edges = bin_edges[:-1]
121-
binner = binner[:-1]
108+
binner, bin_edges = self._adjust_bin_edges(binner, ax_values)
122109

123110
# general version, knowing nothing about relative frequencies
124111
bins = lib.generate_bins_dt64(ax_values, bin_edges, self.closed)
@@ -137,6 +124,25 @@ def _get_time_bins(self, axis):
137124

138125
return binner, bins, labels
139126

127+
def _adjust_bin_edges(self, binner, ax_values):
128+
# Some hacks for > daily data, see #1471, #1458, #1483
129+
130+
bin_edges = binner.asi8
131+
132+
if self.freq != 'D' and is_superperiod(self.freq, 'D'):
133+
day_nanos = _delta_to_nanoseconds(timedelta(1))
134+
if self.closed == 'right':
135+
bin_edges = bin_edges + day_nanos - 1
136+
else:
137+
bin_edges = bin_edges + day_nanos
138+
139+
# intraday values on last day
140+
if bin_edges[-2] > ax_values[-1]:
141+
bin_edges = bin_edges[:-1]
142+
binner = binner[:-1]
143+
144+
return binner, bin_edges
145+
140146
def _get_time_period_bins(self, axis):
141147
assert(isinstance(axis, DatetimeIndex))
142148

pandas/tseries/tests/test_offsets.py

+1
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ def test_onOffset(self):
422422

423423
tests = [(BMonthBegin(), datetime(2007, 12, 31), False),
424424
(BMonthBegin(), datetime(2008, 1, 1), True),
425+
(BMonthBegin(), datetime(2001, 4, 2), True),
425426
(BMonthBegin(), datetime(2008, 3, 3), True)]
426427

427428
for offset, date, expected in tests:

pandas/tseries/tests/test_resample.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ def test_monthly_resample_error(self):
440440
def test_resample_anchored_intraday(self):
441441
# #1471, #1458
442442

443-
rng = pd.date_range('1/1/2012', '4/1/2012', freq='10min')
443+
rng = date_range('1/1/2012', '4/1/2012', freq='10min')
444444
df = DataFrame(rng.month, index=rng)
445445

446446
result = df.resample('M')
@@ -451,7 +451,7 @@ def test_resample_anchored_intraday(self):
451451
expected = df.resample('M', kind='period', closed='left').to_timestamp()
452452
tm.assert_frame_equal(result, expected)
453453

454-
rng = pd.date_range('1/1/2012', '4/1/2013', freq='10min')
454+
rng = date_range('1/1/2012', '4/1/2013', freq='10min')
455455
df = DataFrame(rng.month, index=rng)
456456

457457
result = df.resample('Q')
@@ -462,9 +462,14 @@ def test_resample_anchored_intraday(self):
462462
expected = df.resample('Q', kind='period', closed='left').to_timestamp()
463463
tm.assert_frame_equal(result, expected)
464464

465+
def test_resample_anchored_monthstart(self):
466+
ts = _simple_ts('1/1/2000', '12/31/2002')
467+
468+
freqs = ['MS', 'BMS', 'QS-MAR', 'AS-DEC', 'AS-JUN']
469+
470+
for freq in freqs:
471+
result = ts.resample(freq, how='mean')
465472

466-
rng = pd.date_range('1/1/2012', '4/1/2015', freq='10min')
467-
df = DataFrame(rng.month, index=rng)
468473

469474
def _simple_ts(start, end, freq='D'):
470475
rng = date_range(start, end, freq=freq)

0 commit comments

Comments
 (0)