Skip to content

Commit 1c23c5e

Browse files
authored
BUG: DatetimeIndex.is_year_start and DatetimeIndex.is_quarter_start always return False on double-digit frequencies (#58549)
* correct def get_start_end_field, add test, add a note to v3.0.0 * replace regex with to_offset * replace offset.freqstr.replace with offset.name * move to_offset from get_start_end_field up * fixup test_is_yqm_start_end * rename the argument freqstr in get_start_end_field * rename the variable freqstr in _field_accessor * simplify to_offset(freq.freqstr).name * rename the variable freqstr
1 parent 7be2e21 commit 1c23c5e

File tree

6 files changed

+24
-12
lines changed

6 files changed

+24
-12
lines changed

doc/source/whatsnew/v3.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ Interval
421421
Indexing
422422
^^^^^^^^
423423
- Bug in :meth:`DataFrame.__getitem__` returning modified columns when called with ``slice`` in Python 3.12 (:issue:`57500`)
424+
- Bug in :meth:`DatetimeIndex.is_year_start` and :meth:`DatetimeIndex.is_quarter_start` returning ``False`` on double-digit frequencies (:issue:`58523`)
424425
-
425426

426427
Missing

pandas/_libs/tslibs/fields.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def get_date_name_field(
1616
def get_start_end_field(
1717
dtindex: npt.NDArray[np.int64],
1818
field: str,
19-
freqstr: str | None = ...,
19+
freq_name: str | None = ...,
2020
month_kw: int = ...,
2121
reso: int = ..., # NPY_DATETIMEUNIT
2222
) -> npt.NDArray[np.bool_]: ...

pandas/_libs/tslibs/fields.pyx

+6-7
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ cdef bint _is_on_month(int month, int compare_month, int modby) noexcept nogil:
210210
def get_start_end_field(
211211
const int64_t[:] dtindex,
212212
str field,
213-
str freqstr=None,
213+
str freq_name=None,
214214
int month_kw=12,
215215
NPY_DATETIMEUNIT reso=NPY_FR_ns,
216216
):
@@ -223,7 +223,7 @@ def get_start_end_field(
223223
----------
224224
dtindex : ndarray[int64]
225225
field : str
226-
frestr : str or None, default None
226+
freq_name : str or None, default None
227227
month_kw : int, default 12
228228
reso : NPY_DATETIMEUNIT, default NPY_FR_ns
229229
@@ -243,18 +243,17 @@ def get_start_end_field(
243243

244244
out = np.zeros(count, dtype="int8")
245245

246-
if freqstr:
247-
if freqstr == "C":
246+
if freq_name:
247+
if freq_name == "C":
248248
raise ValueError(f"Custom business days is not supported by {field}")
249-
is_business = freqstr[0] == "B"
249+
is_business = freq_name[0] == "B"
250250

251251
# YearBegin(), BYearBegin() use month = starting month of year.
252252
# QuarterBegin(), BQuarterBegin() use startingMonth = starting
253253
# month of year. Other offsets use month, startingMonth as ending
254254
# month of year.
255255

256-
if (freqstr[0:2] in ["MS", "QS", "YS"]) or (
257-
freqstr[1:3] in ["MS", "QS", "YS"]):
256+
if freq_name.lstrip("B")[0:2] in ["MS", "QS", "YS"]:
258257
end_month = 12 if month_kw == 1 else month_kw - 1
259258
start_month = month_kw
260259
else:

pandas/_libs/tslibs/timestamps.pyx

+3-3
Original file line numberDiff line numberDiff line change
@@ -579,15 +579,15 @@ cdef class _Timestamp(ABCTimestamp):
579579
if freq:
580580
kwds = freq.kwds
581581
month_kw = kwds.get("startingMonth", kwds.get("month", 12))
582-
freqstr = freq.freqstr
582+
freq_name = freq.name
583583
else:
584584
month_kw = 12
585-
freqstr = None
585+
freq_name = None
586586

587587
val = self._maybe_convert_value_to_local()
588588

589589
out = get_start_end_field(np.array([val], dtype=np.int64),
590-
field, freqstr, month_kw, self._creso)
590+
field, freq_name, month_kw, self._creso)
591591
return out[0]
592592

593593
@property

pandas/core/arrays/datetimes.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,12 @@ def f(self):
145145
kwds = freq.kwds
146146
month_kw = kwds.get("startingMonth", kwds.get("month", 12))
147147

148+
if freq is not None:
149+
freq_name = freq.name
150+
else:
151+
freq_name = None
148152
result = fields.get_start_end_field(
149-
values, field, self.freqstr, month_kw, reso=self._creso
153+
values, field, freq_name, month_kw, reso=self._creso
150154
)
151155
else:
152156
result = fields.get_date_field(values, field, reso=self._creso)

pandas/tests/indexes/datetimes/test_scalar_compat.py

+8
Original file line numberDiff line numberDiff line change
@@ -328,3 +328,11 @@ def test_dti_is_month_start_custom(self):
328328
msg = "Custom business days is not supported by is_month_start"
329329
with pytest.raises(ValueError, match=msg):
330330
dti.is_month_start
331+
332+
def test_dti_is_year_quarter_start_doubledigit_freq(self):
333+
# GH#58523
334+
dr = date_range("2017-01-01", periods=2, freq="10YS")
335+
assert all(dr.is_year_start)
336+
337+
dr = date_range("2017-01-01", periods=2, freq="10QS")
338+
assert all(dr.is_quarter_start)

0 commit comments

Comments
 (0)