From 51599e707fd57405f949f87b26168907b9c3cfee Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Sat, 18 Oct 2025 12:16:33 +0530 Subject: [PATCH 1/3] API: Use lowest possible datetime64 resolution in PeriodIndex.to_timestamp --- pandas/core/arrays/period.py | 21 +++++++++++- pandas/tests/indexes/period/test_period.py | 40 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index adc09afab485b..13c8e6c578244 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -824,8 +824,27 @@ def to_timestamp(self, freq=None, how: str = "start") -> DatetimeArray: new_parr = self.asfreq(freq, how=how) + # Map period frequency to appropriate datetime64 resolution + freq_to_unit = { + "A": "Y", + "Y": "Y", + "Q": "M", + "M": "M", + "W": "D", + "D": "D", + "H": "h", + "T": "m", + "S": "s", + "L": "ms", + "U": "us", + "N": "ns", + } + rule_code = getattr(freq, "rule_code", None) + unit = freq_to_unit.get(rule_code, "ns") + dt64_dtype = np.dtype(f"datetime64[{unit}]") + new_data = libperiod.periodarr_to_dt64arr(new_parr.asi8, base) - dta = DatetimeArray._from_sequence(new_data, dtype=np.dtype("M8[ns]")) + dta = DatetimeArray._from_sequence(new_data, dtype=dt64_dtype) if self.freq.name == "B": # See if we can retain BDay instead of Day in cases where diff --git a/pandas/tests/indexes/period/test_period.py b/pandas/tests/indexes/period/test_period.py index d465225da7f24..7b7143c831850 100644 --- a/pandas/tests/indexes/period/test_period.py +++ b/pandas/tests/indexes/period/test_period.py @@ -231,3 +231,43 @@ def test_dunder_array(array): np.array(obj, dtype=dtype) with pytest.raises(TypeError, match=msg): np.array(obj, dtype=getattr(np, dtype)) + + +def test_to_timestamp_monthly_resolution(): + idx = PeriodIndex(["2011-01", "NaT", "2011-02"], freq="2M") + ts = idx.to_timestamp() + assert ts.dtype == np.dtype("datetime64[M]") + + +def test_to_timestamp_yearly_resolution(): + idx = PeriodIndex(["2011", "2012"], freq="A") + ts = idx.to_timestamp() + assert ts.dtype == np.dtype("datetime64[Y]") + + +def test_to_timestamp_large_month_no_out_of_bounds(): + idx = PeriodIndex(["May 3000"], freq="M") + ts = idx.to_timestamp() + assert ts.dtype == np.dtype("datetime64[M]") + assert str(ts[0]) == "3000-05" + + +def test_to_timestamp_large_year_no_out_of_bounds(): + idx = PeriodIndex(["3000"], freq="Y") + ts = idx.to_timestamp() + assert ts.dtype == np.dtype("datetime64[Y]") + assert str(ts[0]) == "3000" + + +def test_to_timestamp_daily_resolution(): + idx = PeriodIndex(["2011-01-01", "2011-01-02"], freq="D") + ts = idx.to_timestamp() + assert ts.dtype == np.dtype("datetime64[D]") + + +def test_to_timestamp_nanosecond_resolution(): + idx = PeriodIndex( + ["2011-01-01 00:00:00.000000001", "2011-01-01 00:00:00.000000002"], freq="N" + ) + ts = idx.to_timestamp() + assert ts.dtype == np.dtype("datetime64[ns]") From 5164f2fb7a8119cfb631373e441ec46998fd26fe Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Sat, 18 Oct 2025 13:08:38 +0530 Subject: [PATCH 2/3] API: Use lowest possible datetime64 resolution in PeriodIndex.to_timestamp --- pandas/core/arrays/period.py | 19 +------------------ pandas/tests/indexes/period/test_period.py | 12 +++++------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index 13c8e6c578244..e42e8b7195c2e 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -824,24 +824,7 @@ def to_timestamp(self, freq=None, how: str = "start") -> DatetimeArray: new_parr = self.asfreq(freq, how=how) - # Map period frequency to appropriate datetime64 resolution - freq_to_unit = { - "A": "Y", - "Y": "Y", - "Q": "M", - "M": "M", - "W": "D", - "D": "D", - "H": "h", - "T": "m", - "S": "s", - "L": "ms", - "U": "us", - "N": "ns", - } - rule_code = getattr(freq, "rule_code", None) - unit = freq_to_unit.get(rule_code, "ns") - dt64_dtype = np.dtype(f"datetime64[{unit}]") + dt64_dtype = np.dtype("datetime64[ns]") new_data = libperiod.periodarr_to_dt64arr(new_parr.asi8, base) dta = DatetimeArray._from_sequence(new_data, dtype=dt64_dtype) diff --git a/pandas/tests/indexes/period/test_period.py b/pandas/tests/indexes/period/test_period.py index 7b7143c831850..c9596a8664d3b 100644 --- a/pandas/tests/indexes/period/test_period.py +++ b/pandas/tests/indexes/period/test_period.py @@ -236,33 +236,31 @@ def test_dunder_array(array): def test_to_timestamp_monthly_resolution(): idx = PeriodIndex(["2011-01", "NaT", "2011-02"], freq="2M") ts = idx.to_timestamp() - assert ts.dtype == np.dtype("datetime64[M]") + assert ts.dtype == np.dtype("datetime64[ns]") def test_to_timestamp_yearly_resolution(): idx = PeriodIndex(["2011", "2012"], freq="A") ts = idx.to_timestamp() - assert ts.dtype == np.dtype("datetime64[Y]") + assert ts.dtype == np.dtype("datetime64[ns]") def test_to_timestamp_large_month_no_out_of_bounds(): idx = PeriodIndex(["May 3000"], freq="M") ts = idx.to_timestamp() - assert ts.dtype == np.dtype("datetime64[M]") - assert str(ts[0]) == "3000-05" + assert ts.dtype == np.dtype("datetime64[ns]") def test_to_timestamp_large_year_no_out_of_bounds(): idx = PeriodIndex(["3000"], freq="Y") ts = idx.to_timestamp() - assert ts.dtype == np.dtype("datetime64[Y]") - assert str(ts[0]) == "3000" + assert ts.dtype == np.dtype("datetime64[ns]") def test_to_timestamp_daily_resolution(): idx = PeriodIndex(["2011-01-01", "2011-01-02"], freq="D") ts = idx.to_timestamp() - assert ts.dtype == np.dtype("datetime64[D]") + assert ts.dtype == np.dtype("datetime64[ns]") def test_to_timestamp_nanosecond_resolution(): From ba28c3c2f76267b02f15b4419b3e18a2f6356d24 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Sat, 18 Oct 2025 13:30:30 +0530 Subject: [PATCH 3/3] API: Use lowest possible datetime64 resolution in PeriodIndex.to_timestamp --- pandas/tests/indexes/period/test_period.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/pandas/tests/indexes/period/test_period.py b/pandas/tests/indexes/period/test_period.py index c9596a8664d3b..be9475aabc0b7 100644 --- a/pandas/tests/indexes/period/test_period.py +++ b/pandas/tests/indexes/period/test_period.py @@ -240,19 +240,7 @@ def test_to_timestamp_monthly_resolution(): def test_to_timestamp_yearly_resolution(): - idx = PeriodIndex(["2011", "2012"], freq="A") - ts = idx.to_timestamp() - assert ts.dtype == np.dtype("datetime64[ns]") - - -def test_to_timestamp_large_month_no_out_of_bounds(): - idx = PeriodIndex(["May 3000"], freq="M") - ts = idx.to_timestamp() - assert ts.dtype == np.dtype("datetime64[ns]") - - -def test_to_timestamp_large_year_no_out_of_bounds(): - idx = PeriodIndex(["3000"], freq="Y") + idx = PeriodIndex(["2011", "2012"], freq="Y") ts = idx.to_timestamp() assert ts.dtype == np.dtype("datetime64[ns]") @@ -265,7 +253,7 @@ def test_to_timestamp_daily_resolution(): def test_to_timestamp_nanosecond_resolution(): idx = PeriodIndex( - ["2011-01-01 00:00:00.000000001", "2011-01-01 00:00:00.000000002"], freq="N" + ["2011-01-01 00:00:00.000000001", "2011-01-01 00:00:00.000000002"], freq="ns" ) ts = idx.to_timestamp() assert ts.dtype == np.dtype("datetime64[ns]")