Skip to content

Timestamp replace compatibility #15248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
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/v0.20.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ Performance Improvements
Bug Fixes
~~~~~~~~~

- Bug in ``Timestamp.replace`` now raises ``TypeError`` when incorrect argument names are given; previously this raised ``ValueError`` (:issue:`15240`)
- Bug in ``Index`` power operations with reversed operands (:issue:`14973`)
- Bug in ``TimedeltaIndex`` addition where overflow was being allowed without error (:issue:`14816`)
- Bug in ``TimedeltaIndex`` raising a ``ValueError`` when boolean indexing with ``loc`` (:issue:`14946`)
Expand Down
3 changes: 1 addition & 2 deletions pandas/tseries/tests/test_timezones.py
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,6 @@ def test_date_range_span_dst_transition(self):
def test_convert_datetime_list(self):
dr = date_range('2012-06-02', periods=10,
tz=self.tzstr('US/Eastern'), name='foo')

dr2 = DatetimeIndex(list(dr), name='foo')
self.assert_index_equal(dr, dr2)
self.assertEqual(dr.tz, dr2.tz)
Expand Down Expand Up @@ -1198,7 +1197,7 @@ def test_replace(self):
# error
def f():
dt.replace(foo=5)
self.assertRaises(ValueError, f)
self.assertRaises(TypeError, f)

def f():
dt.replace(hour=0.1)
Expand Down
75 changes: 39 additions & 36 deletions pandas/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -650,18 +650,25 @@ class Timestamp(_Timestamp):

astimezone = tz_convert

def replace(self, **kwds):
def replace(self, year=None, month=None, day=None,
hour=None, minute=None, second=None, microsecond=None, nanosecond=None,
tzinfo=object, fold=0):
"""
implements datetime.replace, handles nanoseconds

Parameters
----------
kwargs: key-value dict

accepted keywords are:
year, month, day, hour, minute, second, microsecond, nanosecond, tzinfo

values must be integer, or for tzinfo, a tz-convertible
year : int, optional
month : int, optional
day : int, optional
hour : int, optional
minute : int, optional
second : int, optional
microsecond : int, optional
nanosecond: int, optional
tzinfo : tz-convertible, optional
fold : int, optional, default is 0
added in 3.6, NotImplemented

Returns
-------
Expand All @@ -671,14 +678,14 @@ class Timestamp(_Timestamp):
cdef:
pandas_datetimestruct dts
int64_t value
object tzinfo, result, k, v
object _tzinfo, result, k, v
_TSObject ts

# set to naive if needed
tzinfo = self.tzinfo
_tzinfo = self.tzinfo
value = self.value
if tzinfo is not None:
value = tz_convert_single(value, 'UTC', tzinfo)
if _tzinfo is not None:
value = tz_convert_single(value, 'UTC', _tzinfo)

# setup components
pandas_datetime_to_datetimestruct(value, PANDAS_FR_ns, &dts)
Expand All @@ -692,39 +699,35 @@ class Timestamp(_Timestamp):
"{v} for {k}".format(v=type(v), k=k))
return v

for k, v in kwds.items():
if k == 'year':
dts.year = validate(k, v)
elif k == 'month':
dts.month = validate(k, v)
elif k == 'day':
dts.day = validate(k, v)
elif k == 'hour':
dts.hour = validate(k, v)
elif k == 'minute':
dts.min = validate(k, v)
elif k == 'second':
dts.sec = validate(k, v)
elif k == 'microsecond':
dts.us = validate(k, v)
elif k == 'nanosecond':
dts.ps = validate(k, v) * 1000
elif k == 'tzinfo':
tzinfo = v
else:
raise ValueError("invalid name {} passed".format(k))
if year is not None:
dts.year = validate('year', year)
if month is not None:
dts.month = validate('month', month)
if day is not None:
dts.day = validate('day', day)
if hour is not None:
dts.hour = validate('hour', hour)
if minute is not None:
dts.min = validate('minute', minute)
if second is not None:
dts.sec = validate('second', second)
if microsecond is not None:
dts.us = validate('microsecond', microsecond)
if nanosecond is not None:
dts.ps = validate('nanosecond', nanosecond) * 1000
if tzinfo is not object:
_tzinfo = tzinfo

# reconstruct & check bounds
value = pandas_datetimestruct_to_datetime(PANDAS_FR_ns, &dts)
if value != NPY_NAT:
_check_dts_bounds(&dts)

# set tz if needed
if tzinfo is not None:
value = tz_convert_single(value, tzinfo, 'UTC')

result = create_timestamp_from_ts(value, dts, tzinfo, self.freq)
if _tzinfo is not None:
value = tz_convert_single(value, _tzinfo, 'UTC')

result = create_timestamp_from_ts(value, dts, _tzinfo, self.freq)
return result

def isoformat(self, sep='T'):
Expand Down