From 232c29b367168522c796fe30dac17476ed098270 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sun, 4 Nov 2018 17:27:46 -0800 Subject: [PATCH 1/3] BUG: Timestamp retains frequency of input Timestamps --- doc/source/whatsnew/v0.24.0.txt | 1 + pandas/_libs/tslibs/timestamps.pyx | 5 ++++- pandas/tests/scalar/timestamp/test_timestamp.py | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index fa748cccc0d65..9e202b6ecd81d 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -1114,6 +1114,7 @@ Datetimelike - Bug in :func:`DataFrame.combine` with datetimelike values raising a TypeError (:issue:`23079`) - Bug in :func:`date_range` with frequency of ``Day`` or higher where dates sufficiently far in the future could wrap around to the past instead of raising ``OutOfBoundsDatetime`` (:issue:`14187`) - Bug in :class:`PeriodIndex` with attribute ``freq.n`` greater than 1 where adding a :class:`DateOffset` object would return incorrect results (:issue:`23215`) +- Bug in :class:`Timestamp` constructor which would drop the frequency of an input :class:`Timestamp` (:issue:`22311`) Timedelta ^^^^^^^^^ diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 094b48920fc46..83d9176706f40 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -731,8 +731,11 @@ class Timestamp(_Timestamp): if ts.value == NPY_NAT: return NaT - if is_string_object(freq): + if freq is not None: freq = to_offset(freq) + else: + # GH 22311: Try to extract the frequency of a given Timestamp input + freq = getattr(ts_input, 'freq', None) return create_timestamp_from_ts(ts.value, ts.dts, ts.tzinfo, freq) diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index 872c510094a4f..9a77a9ccc96c3 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -569,6 +569,12 @@ def test_construct_with_different_string_format(self, arg): expected = Timestamp(datetime(2013, 1, 1), tz=pytz.FixedOffset(540)) assert result == expected + def test_construct_timestamp_preserve_original_frequency(self): + # GH 22311 + result = Timestamp(Timestamp('2010-08-08', freq='D')).freq + expected = offsets.Day() + assert result == expected + class TestTimestamp(object): From 4f34c01714e756e29b7d23ad9dd46a5daf382567 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sun, 4 Nov 2018 18:10:09 -0800 Subject: [PATCH 2/3] Be a little more strict with offset checking --- pandas/_libs/tslibs/timestamps.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 83d9176706f40..a6b41a75842f5 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -30,6 +30,7 @@ from np_datetime import OutOfBoundsDatetime from np_datetime cimport (reverse_ops, cmp_scalar, check_dts_bounds, npy_datetimestruct, dt64_to_dtstruct) from offsets cimport to_offset +from offsets import _BaseOffset from timedeltas import Timedelta from timedeltas cimport delta_to_nanoseconds from timezones cimport ( @@ -731,7 +732,7 @@ class Timestamp(_Timestamp): if ts.value == NPY_NAT: return NaT - if freq is not None: + if is_string_object(freq) or isinstance(freq, _BaseOffset): freq = to_offset(freq) else: # GH 22311: Try to extract the frequency of a given Timestamp input From 41fcdd73527e78929cb3d819c6151ae54130248d Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Mon, 5 Nov 2018 15:29:34 -0800 Subject: [PATCH 3/3] use better offest check --- pandas/_libs/tslibs/timestamps.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index a6b41a75842f5..3e9b06731afa7 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -16,7 +16,8 @@ from cpython.datetime cimport (datetime, PyDateTime_IMPORT from util cimport (is_datetime64_object, is_timedelta64_object, - is_integer_object, is_string_object, is_array) + is_integer_object, is_string_object, is_array, + is_offset_object) cimport ccalendar from conversion import tz_localize_to_utc, normalize_i8_timestamps @@ -30,7 +31,6 @@ from np_datetime import OutOfBoundsDatetime from np_datetime cimport (reverse_ops, cmp_scalar, check_dts_bounds, npy_datetimestruct, dt64_to_dtstruct) from offsets cimport to_offset -from offsets import _BaseOffset from timedeltas import Timedelta from timedeltas cimport delta_to_nanoseconds from timezones cimport ( @@ -732,9 +732,9 @@ class Timestamp(_Timestamp): if ts.value == NPY_NAT: return NaT - if is_string_object(freq) or isinstance(freq, _BaseOffset): + if is_string_object(freq): freq = to_offset(freq) - else: + elif not is_offset_object(freq): # GH 22311: Try to extract the frequency of a given Timestamp input freq = getattr(ts_input, 'freq', None)