diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index 45e4fd9f0aabb..35ace840c2cde 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -993,7 +993,7 @@ Period ^^^^^^ - Bug in :meth:`Period.strftime` and :meth:`PeriodIndex.strftime`, raising ``UnicodeDecodeError`` when a locale-specific directive was passed (:issue:`46319`) - Bug in adding a :class:`Period` object to an array of :class:`DateOffset` objects incorrectly raising ``TypeError`` (:issue:`50162`) -- +- Bug in :class:`Period` where passing a string with finer resolution than nanosecond would result in a ``KeyError`` instead of dropping the extra precision (:issue:`50417`) Plotting ^^^^^^^^ diff --git a/pandas/_libs/tslibs/parsing.pyx b/pandas/_libs/tslibs/parsing.pyx index 0f6640a90d7ed..3de1345598437 100644 --- a/pandas/_libs/tslibs/parsing.pyx +++ b/pandas/_libs/tslibs/parsing.pyx @@ -393,7 +393,7 @@ cdef parse_datetime_string_with_reso( &out_tzoffset, False ) if not string_to_dts_failed: - if dts.ps != 0 or out_local: + if out_bestunit == NPY_DATETIMEUNIT.NPY_FR_ns or out_local: # TODO: the not-out_local case we could do without Timestamp; # avoid circular import from pandas import Timestamp @@ -402,6 +402,13 @@ cdef parse_datetime_string_with_reso( parsed = datetime( dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.us ) + # Match Timestamp and drop picoseconds, femtoseconds, attoseconds + # The new resolution will just be nano + # GH 50417 + if out_bestunit in {NPY_DATETIMEUNIT.NPY_FR_ps, + NPY_DATETIMEUNIT.NPY_FR_fs, + NPY_DATETIMEUNIT.NPY_FR_as}: + out_bestunit = NPY_DATETIMEUNIT.NPY_FR_ns reso = { NPY_DATETIMEUNIT.NPY_FR_Y: "year", NPY_DATETIMEUNIT.NPY_FR_M: "month", diff --git a/pandas/tests/scalar/period/test_period.py b/pandas/tests/scalar/period/test_period.py index 0636ecb023530..710a98ba6f005 100644 --- a/pandas/tests/scalar/period/test_period.py +++ b/pandas/tests/scalar/period/test_period.py @@ -545,6 +545,11 @@ def test_period_cons_combined(self): (".000000999", 999), (".123456789", 789), (".999999999", 999), + (".999999000", 0), + # Test femtoseconds, attoseconds, picoseconds are dropped like Timestamp + (".999999001123", 1), + (".999999001123456", 1), + (".999999001123456789", 1), ], ) def test_period_constructor_nanosecond(self, day, hour, sec_float, expected):