Skip to content

Commit 29ce489

Browse files
authored
BUG: Timestamp.replace failing to update unit (#62301)
1 parent 5b88827 commit 29ce489

File tree

4 files changed

+26
-6
lines changed

4 files changed

+26
-6
lines changed

doc/source/whatsnew/v3.0.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,7 @@ Datetimelike
902902
- Bug in :meth:`DatetimeIndex.union` and :meth:`DatetimeIndex.intersection` when ``unit`` was non-nanosecond (:issue:`59036`)
903903
- Bug in :meth:`Index.union` with a ``pyarrow`` timestamp dtype incorrectly returning ``object`` dtype (:issue:`58421`)
904904
- Bug in :meth:`Series.dt.microsecond` producing incorrect results for pyarrow backed :class:`Series`. (:issue:`59154`)
905+
- Bug in :meth:`Timestamp.replace` failing to update ``unit`` attribute when replacement introduces non-zero ``nanosecond`` or ``microsecond`` (:issue:`57749`)
905906
- Bug in :meth:`to_datetime` not respecting dayfirst if an uncommon date string was passed. (:issue:`58859`)
906907
- Bug in :meth:`to_datetime` on float array with missing values throwing ``FloatingPointError`` (:issue:`58419`)
907908
- Bug in :meth:`to_datetime` on float32 df with year, month, day etc. columns leads to precision issues and incorrect result. (:issue:`60506`)

pandas/_libs/tslibs/timestamps.pyx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3357,6 +3357,7 @@ default 'raise'
33573357
datetime ts_input
33583358
tzinfo_type tzobj
33593359
_TSObject ts
3360+
NPY_DATETIMEUNIT creso = self._creso
33603361
33613362
# set to naive if needed
33623363
tzobj = self.tzinfo
@@ -3396,8 +3397,12 @@ default 'raise'
33963397
dts.sec = validate("second", second)
33973398
if microsecond is not None:
33983399
dts.us = validate("microsecond", microsecond)
3400+
if creso < NPY_DATETIMEUNIT.NPY_FR_us:
3401+
# GH#57749
3402+
creso = NPY_DATETIMEUNIT.NPY_FR_us
33993403
if nanosecond is not None:
34003404
dts.ps = validate("nanosecond", nanosecond) * 1000
3405+
creso = NPY_FR_ns # GH#57749
34013406
if tzinfo is not object:
34023407
tzobj = tzinfo
34033408
@@ -3407,17 +3412,17 @@ default 'raise'
34073412
# to datetimes outside of pydatetime range.
34083413
ts = _TSObject()
34093414
try:
3410-
ts.value = npy_datetimestruct_to_datetime(self._creso, &dts)
3415+
ts.value = npy_datetimestruct_to_datetime(creso, &dts)
34113416
except OverflowError as err:
34123417
fmt = dts_to_iso_string(&dts)
34133418
raise OutOfBoundsDatetime(
34143419
f"Out of bounds timestamp: {fmt} with frequency '{self.unit}'"
34153420
) from err
34163421
ts.dts = dts
3417-
ts.creso = self._creso
3422+
ts.creso = creso
34183423
ts.fold = fold
34193424
return create_timestamp_from_ts(
3420-
ts.value, dts, tzobj, fold, reso=self._creso
3425+
ts.value, dts, tzobj, fold, reso=creso
34213426
)
34223427
34233428
elif tzobj is not None and treat_tz_as_pytz(tzobj):
@@ -3436,10 +3441,10 @@ default 'raise'
34363441
ts_input = datetime(**kwargs)
34373442
34383443
ts = convert_datetime_to_tsobject(
3439-
ts_input, tzobj, nanos=dts.ps // 1000, reso=self._creso
3444+
ts_input, tzobj, nanos=dts.ps // 1000, reso=creso
34403445
)
34413446
return create_timestamp_from_ts(
3442-
ts.value, dts, tzobj, fold, reso=self._creso
3447+
ts.value, dts, tzobj, fold, reso=creso
34433448
)
34443449
34453450
def to_julian_date(self) -> np.float64:

pandas/tests/reshape/test_pivot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ def test_pivot_tz_in_values(self):
642642
)
643643

644644
df = df.set_index("ts").reset_index()
645-
mins = df.ts.map(lambda x: x.replace(hour=0, minute=0, second=0, microsecond=0))
645+
mins = df.ts.map(lambda x: x.replace(hour=0, minute=0, second=0))
646646

647647
result = pivot_table(
648648
df.set_index("ts").reset_index(),

pandas/tests/scalar/timestamp/methods/test_replace.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,17 @@ def test_replace_preserves_fold(self, fold):
195195
ts_replaced = ts.replace(second=1)
196196

197197
assert ts_replaced.fold == fold
198+
199+
def test_replace_updates_unit(self):
200+
# GH#57749
201+
ts = Timestamp("2023-07-15 23:08:12.134567123")
202+
ts2 = Timestamp("2023-07-15 23:08:12.000000")
203+
assert ts2.unit == "us"
204+
result = ts2.replace(microsecond=ts.microsecond, nanosecond=ts.nanosecond)
205+
assert result.unit == "ns"
206+
assert result == ts
207+
208+
ts3 = Timestamp("2023-07-15 23:08:12").as_unit("s")
209+
result = ts3.replace(microsecond=ts2.microsecond)
210+
assert result.unit == "us"
211+
assert result == ts2

0 commit comments

Comments
 (0)