Skip to content

Commit 4bd0594

Browse files
author
David Jun
committed
Resolving #61086 : BUG: Collision between equivalent frequencies 'QS-FEB' and 'QS-NOV'
1 parent 882fa9c commit 4bd0594

File tree

4 files changed

+44
-1
lines changed

4 files changed

+44
-1
lines changed

doc/source/whatsnew/v3.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ Other enhancements
7575
- :meth:`pandas.concat` will raise a ``ValueError`` when ``ignore_index=True`` and ``keys`` is not ``None`` (:issue:`59274`)
7676
- :py:class:`frozenset` elements in pandas objects are now natively printed (:issue:`60690`)
7777
- Add ``"delete_rows"`` option to ``if_exists`` argument in :meth:`DataFrame.to_sql` deleting all records of the table before inserting data (:issue:`37210`).
78+
- Added :func:`DateTimeIndex.set_freq` and :class:`DateTimeIndex` now supports assigning equivalent quarerly start frequency (:issue:`61086`)
7879
- Added half-year offset classes :class:`HalfYearBegin`, :class:`HalfYearEnd`, :class:`BHalfYearBegin` and :class:`BHalfYearEnd` (:issue:`60928`)
7980
- Errors occurring during SQL I/O will now throw a generic :class:`.DatabaseError` instead of the raw Exception type from the underlying driver manager library (:issue:`60748`)
8081
- Implemented :meth:`Series.str.isascii` and :meth:`Series.str.isascii` (:issue:`59091`)

pandas/core/arrays/datetimelike.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -2519,8 +2519,13 @@ def _validate_inferred_freq(
25192519
-------
25202520
freq : DateOffset or None
25212521
"""
2522+
offset1 = to_offset(freq)
2523+
offset2 = to_offset(inferred_freq)
2524+
2525+
freq_equal = type(offset1) == type(offset2)
2526+
25222527
if inferred_freq is not None:
2523-
if freq is not None and freq != inferred_freq:
2528+
if freq is not None and not freq_equal:
25242529
raise ValueError(
25252530
f"Inferred frequency {inferred_freq} from passed "
25262531
"values does not conform to passed frequency "

pandas/core/indexes/datetimes.py

+28
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,34 @@ def _can_range_setop(self, other) -> bool:
421421

422422
# --------------------------------------------------------------------
423423

424+
def _set_freq(self, freq, *, inplace: bool = False):
425+
"""
426+
Set a new frequency for this DatetimeIndex.
427+
428+
Parameters
429+
----------
430+
freq : str, Timedelta, datetime.timedelta, or DateOffset, default 'S'
431+
Frequency strings can have multiples, e.g. '5h'. See
432+
:ref:`here <timeseries.offset_aliases>` for a list of
433+
frequency aliases.
434+
inplace : bool, default False
435+
If True, modifies object in place. Otherwise, returns a new DateTimeIndex
436+
437+
Returns
438+
-------
439+
DatetimeIndex
440+
Fixed frequency DatetimeIndex
441+
"""
442+
443+
if inplace:
444+
self._freq = to_offset(freq)
445+
else:
446+
new_index = self.copy()
447+
new_index.freq = to_offset(freq)
448+
return new_index
449+
450+
# --------------------------------------------------------------------
451+
424452
def _get_time_micros(self) -> npt.NDArray[np.int64]:
425453
"""
426454
Return the number of microseconds since midnight.

pandas/tests/indexes/datetimes/test_constructors.py

+9
Original file line numberDiff line numberDiff line change
@@ -1204,3 +1204,12 @@ def test_dti_constructor_object_dtype_dayfirst_yearfirst_with_tz(self):
12041204
result2 = DatetimeIndex([val], tz="US/Pacific", yearfirst=True)
12051205
expected2 = DatetimeIndex([yfirst]).as_unit("s")
12061206
tm.assert_index_equal(result2, expected2)
1207+
1208+
def test_datetimeindex_equivalent_freq(self):
1209+
idx2 = date_range("2020-02-01", freq="QS-FEB", periods=4)
1210+
new_idx2 = idx2._set_freq("QS-MAY")
1211+
tm.assert_index_equal(new_idx2, idx2)
1212+
assert new_idx2.freq == "QS-MAY"
1213+
1214+
idx2._set_freq("QS-MAY", inplace=True)
1215+
assert idx2.freq == "QS-MAY"

0 commit comments

Comments
 (0)