Skip to content

Commit

Permalink
BUG: Fix bug where when replaced with 0 it Timestamp.replace didn't r…
Browse files Browse the repository at this point in the history
…ecalculate precision
  • Loading branch information
diogomsmiranda committed Jun 22, 2024
1 parent f0c77d3 commit 5e6c223
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 2 deletions.
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,6 @@ Performance improvements

Bug fixes
~~~~~~~~~
- Fixed bug in :meth:`Timestamp.replace` where it would not reflect changes into :meth:`Timestamp.unit`. (:issue:`57749`)

Categorical
^^^^^^^^^^^
Expand All @@ -491,6 +490,7 @@ Datetimelike
- Bug in :meth:`DatetimeIndex.is_year_start` and :meth:`DatetimeIndex.is_quarter_start` does not raise on Custom business days frequencies bigger then "1C" (:issue:`58664`)
- Bug in :meth:`DatetimeIndex.is_year_start` and :meth:`DatetimeIndex.is_quarter_start` returning ``False`` on double-digit frequencies (:issue:`58523`)
- Bug in setting scalar values with mismatched resolution into arrays with non-nanosecond ``datetime64``, ``timedelta64`` or :class:`DatetimeTZDtype` incorrectly truncating those scalars (:issue:`56410`)
- Bug in :meth:`Timestamp.replace` where it would not reflect changes into :meth:`Timestamp.unit`. (:issue:`57749`)

Timedelta
^^^^^^^^^
Expand Down
17 changes: 16 additions & 1 deletion pandas/_libs/tslibs/timestamps.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2633,6 +2633,8 @@ default 'raise'
pandas_datetime_to_datetimestruct(value, self._creso, &dts)
dts.ps = self.nanosecond * 1000

zero_set = False

# replace
def validate(k, v):
""" validate integers """
Expand Down Expand Up @@ -2666,13 +2668,26 @@ default 'raise'
rep_reso = NPY_DATETIMEUNIT.NPY_FR_us
else:
rep_reso = NPY_DATETIMEUNIT.NPY_FR_ms
if microsecond == 0:
zero_set = True
if nanosecond is not None:
dts.ps = validate("nanosecond", nanosecond) * 1000
rep_reso = NPY_DATETIMEUNIT.NPY_FR_ns
if nanosecond == 0:
zero_set = True
if tzinfo is not object:
tzobj = tzinfo

if rep_reso < self._creso:
# Recalculate the replacement resolution if a unit was replaced with 0
if zero_set:
if dts.ps != 0:
rep_reso = NPY_DATETIMEUNIT.NPY_FR_ns
elif dts.us != 0:
rep_reso = NPY_DATETIMEUNIT.NPY_FR_us
else:
rep_reso = NPY_DATETIMEUNIT.NPY_FR_s

if rep_reso < self._creso and not zero_set:
rep_reso = self._creso

# reconstruct & check bounds
Expand Down
6 changes: 6 additions & 0 deletions pandas/tests/scalar/timestamp/methods/test_replace.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,9 @@ def test_replace_unit(self):
ts = ts.replace(nanosecond=ts2.nanosecond)
assert ts.unit == "ns"
assert ts == ts2

def test_replace_resets_to_more_precise(self):
# GH#57749
ts = Timestamp(year=2020, month=1, day=1, nanosecond=5)
result = ts.replace(nanosecond=0)
assert result.unit == "s"

0 comments on commit 5e6c223

Please sign in to comment.