Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,7 @@ Datetimelike
- Bug in :meth:`DatetimeIndex.union` and :meth:`DatetimeIndex.intersection` when ``unit`` was non-nanosecond (:issue:`59036`)
- Bug in :meth:`Index.union` with a ``pyarrow`` timestamp dtype incorrectly returning ``object`` dtype (:issue:`58421`)
- Bug in :meth:`Series.dt.microsecond` producing incorrect results for pyarrow backed :class:`Series`. (:issue:`59154`)
- Bug in :meth:`Timestamp.replace` failing to update ``unit`` attribute when replacement introduces non-zero ``nanosecond`` or ``microsecond`` (:issue:`57749`)
- Bug in :meth:`to_datetime` not respecting dayfirst if an uncommon date string was passed. (:issue:`58859`)
- Bug in :meth:`to_datetime` on float array with missing values throwing ``FloatingPointError`` (:issue:`58419`)
- Bug in :meth:`to_datetime` on float32 df with year, month, day etc. columns leads to precision issues and incorrect result. (:issue:`60506`)
Expand Down
15 changes: 10 additions & 5 deletions pandas/_libs/tslibs/timestamps.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -3357,6 +3357,7 @@ default 'raise'
datetime ts_input
tzinfo_type tzobj
_TSObject ts
NPY_DATETIMEUNIT creso = self._creso

# set to naive if needed
tzobj = self.tzinfo
Expand Down Expand Up @@ -3396,8 +3397,12 @@ default 'raise'
dts.sec = validate("second", second)
if microsecond is not None:
dts.us = validate("microsecond", microsecond)
if creso < NPY_DATETIMEUNIT.NPY_FR_us:
# GH#57749
creso = NPY_DATETIMEUNIT.NPY_FR_us
if nanosecond is not None:
dts.ps = validate("nanosecond", nanosecond) * 1000
creso = NPY_FR_ns # GH#57749
if tzinfo is not object:
tzobj = tzinfo

Expand All @@ -3407,17 +3412,17 @@ default 'raise'
# to datetimes outside of pydatetime range.
ts = _TSObject()
try:
ts.value = npy_datetimestruct_to_datetime(self._creso, &dts)
ts.value = npy_datetimestruct_to_datetime(creso, &dts)
except OverflowError as err:
fmt = dts_to_iso_string(&dts)
raise OutOfBoundsDatetime(
f"Out of bounds timestamp: {fmt} with frequency '{self.unit}'"
) from err
ts.dts = dts
ts.creso = self._creso
ts.creso = creso
ts.fold = fold
return create_timestamp_from_ts(
ts.value, dts, tzobj, fold, reso=self._creso
ts.value, dts, tzobj, fold, reso=creso
)

elif tzobj is not None and treat_tz_as_pytz(tzobj):
Expand All @@ -3436,10 +3441,10 @@ default 'raise'
ts_input = datetime(**kwargs)

ts = convert_datetime_to_tsobject(
ts_input, tzobj, nanos=dts.ps // 1000, reso=self._creso
ts_input, tzobj, nanos=dts.ps // 1000, reso=creso
)
return create_timestamp_from_ts(
ts.value, dts, tzobj, fold, reso=self._creso
ts.value, dts, tzobj, fold, reso=creso
)

def to_julian_date(self) -> np.float64:
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/reshape/test_pivot.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ def test_pivot_tz_in_values(self):
)

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

result = pivot_table(
df.set_index("ts").reset_index(),
Expand Down
14 changes: 14 additions & 0 deletions pandas/tests/scalar/timestamp/methods/test_replace.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,17 @@ def test_replace_preserves_fold(self, fold):
ts_replaced = ts.replace(second=1)

assert ts_replaced.fold == fold

def test_replace_updates_unit(self):
# GH#57749
ts = Timestamp("2023-07-15 23:08:12.134567123")
ts2 = Timestamp("2023-07-15 23:08:12.000000")
assert ts2.unit == "us"
result = ts2.replace(microsecond=ts.microsecond, nanosecond=ts.nanosecond)
assert result.unit == "ns"
assert result == ts

ts3 = Timestamp("2023-07-15 23:08:12").as_unit("s")
result = ts3.replace(microsecond=ts2.microsecond)
assert result.unit == "us"
assert result == ts2
Loading