diff --git a/asv_bench/benchmarks/tslibs/timestamp.py b/asv_bench/benchmarks/tslibs/timestamp.py index 8ebb2d8d2f35d..3ef9b814dd79e 100644 --- a/asv_bench/benchmarks/tslibs/timestamp.py +++ b/asv_bench/benchmarks/tslibs/timestamp.py @@ -1,12 +1,19 @@ import datetime import dateutil +import numpy as np import pytz from pandas import Timestamp class TimestampConstruction: + def setup(self): + self.npdatetime64 = np.datetime64("2020-01-01 00:00:00") + self.dttime_unaware = datetime.datetime(2020, 1, 1, 0, 0, 0) + self.dttime_aware = datetime.datetime(2020, 1, 1, 0, 0, 0, 0, pytz.UTC) + self.ts = Timestamp("2020-01-01 00:00:00") + def time_parse_iso8601_no_tz(self): Timestamp("2017-08-25 08:16:14") @@ -28,6 +35,18 @@ def time_fromordinal(self): def time_fromtimestamp(self): Timestamp.fromtimestamp(1515448538) + def time_from_npdatetime64(self): + Timestamp(self.npdatetime64) + + def time_from_datetime_unaware(self): + Timestamp(self.dttime_unaware) + + def time_from_datetime_aware(self): + Timestamp(self.dttime_aware) + + def time_from_pd_timestamp(self): + Timestamp(self.ts) + class TimestampProperties: _tzs = [None, pytz.timezone("Europe/Amsterdam"), pytz.UTC, dateutil.tz.tzutc()] diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index d0cf92b60fe0d..a0e1c964dd365 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -109,7 +109,9 @@ Deprecations Performance improvements ~~~~~~~~~~~~~~~~~~~~~~~~ + - Performance improvement in :class:`Timedelta` constructor (:issue:`30543`) +- Performance improvement in :class:`Timestamp` constructor (:issue:`30543`) - - diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 36566b55e74ad..4915671aa6512 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -391,7 +391,18 @@ class Timestamp(_Timestamp): # User passed tzinfo instead of tz; avoid silently ignoring tz, tzinfo = tzinfo, None - if isinstance(ts_input, str): + # GH 30543 if pd.Timestamp already passed, return it + # check that only ts_input is passed + # checking verbosely, because cython doesn't optimize + # list comprehensions (as of cython 0.29.x) + if (isinstance(ts_input, Timestamp) and freq is None and + tz is None and unit is None and year is None and + month is None and day is None and hour is None and + minute is None and second is None and + microsecond is None and nanosecond is None and + tzinfo is None): + return ts_input + elif isinstance(ts_input, str): # User passed a date string to parse. # Check that the user didn't also pass a date attribute kwarg. if any(arg is not None for arg in _date_attributes): diff --git a/pandas/tests/indexes/datetimes/test_constructors.py b/pandas/tests/indexes/datetimes/test_constructors.py index b6013c3939793..68285d41bda70 100644 --- a/pandas/tests/indexes/datetimes/test_constructors.py +++ b/pandas/tests/indexes/datetimes/test_constructors.py @@ -957,3 +957,10 @@ def test_timedelta_constructor_identity(): expected = pd.Timedelta(np.timedelta64(1, "s")) result = pd.Timedelta(expected) assert result is expected + + +def test_timestamp_constructor_identity(): + # Test for #30543 + expected = pd.Timestamp("2017-01-01T12") + result = pd.Timestamp(expected) + assert result is expected diff --git a/pandas/tests/indexes/datetimes/test_timezones.py b/pandas/tests/indexes/datetimes/test_timezones.py index c785eb67e5184..cd8e8c3542cce 100644 --- a/pandas/tests/indexes/datetimes/test_timezones.py +++ b/pandas/tests/indexes/datetimes/test_timezones.py @@ -2,7 +2,6 @@ Tests for DatetimeIndex timezone-related methods """ from datetime import date, datetime, time, timedelta, tzinfo -from distutils.version import LooseVersion import dateutil from dateutil.tz import gettz, tzlocal @@ -11,7 +10,6 @@ import pytz from pandas._libs.tslibs import conversion, timezones -from pandas.compat._optional import _get_version import pandas.util._test_decorators as td import pandas as pd @@ -583,15 +581,7 @@ def test_dti_construction_ambiguous_endpoint(self, tz): ["US/Pacific", "shift_forward", "2019-03-10 03:00"], ["dateutil/US/Pacific", "shift_forward", "2019-03-10 03:00"], ["US/Pacific", "shift_backward", "2019-03-10 01:00"], - pytest.param( - "dateutil/US/Pacific", - "shift_backward", - "2019-03-10 01:00", - marks=pytest.mark.xfail( - LooseVersion(_get_version(dateutil)) < LooseVersion("2.7.0"), - reason="GH 31043", - ), - ), + ["dateutil/US/Pacific", "shift_backward", "2019-03-10 01:00"], ["US/Pacific", timedelta(hours=1), "2019-03-10 03:00"], ], )