Skip to content

Commit efbcd68

Browse files
authored
ENH: support nanoseconds in Period constructor (#38175)
1 parent 23cbc47 commit efbcd68

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@ Datetimelike
588588
- Bug in :meth:`Series.isin` with ``datetime64[ns]`` dtype and :meth:`.DatetimeIndex.isin` incorrectly casting integers to datetimes (:issue:`36621`)
589589
- Bug in :meth:`Series.isin` with ``datetime64[ns]`` dtype and :meth:`.DatetimeIndex.isin` failing to consider timezone-aware and timezone-naive datetimes as always different (:issue:`35728`)
590590
- Bug in :meth:`Series.isin` with ``PeriodDtype`` dtype and :meth:`PeriodIndex.isin` failing to consider arguments with different ``PeriodDtype`` as always different (:issue:`37528`)
591+
- Bug in :class:`Period` constructor now correctly handles nanoseconds in the ``value`` argument (:issue:`34621` and :issue:`17053`)
591592

592593
Timedelta
593594
^^^^^^^^^

pandas/_libs/tslibs/period.pyx

+10-1
Original file line numberDiff line numberDiff line change
@@ -2345,6 +2345,7 @@ class Period(_Period):
23452345

23462346
if freq is not None:
23472347
freq = cls._maybe_convert_freq(freq)
2348+
nanosecond = 0
23482349

23492350
if ordinal is not None and value is not None:
23502351
raise ValueError("Only value or ordinal but not both should be "
@@ -2394,6 +2395,14 @@ class Period(_Period):
23942395
value = str(value)
23952396
value = value.upper()
23962397
dt, reso = parse_time_string(value, freq)
2398+
try:
2399+
ts = Timestamp(value)
2400+
except ValueError:
2401+
nanosecond = 0
2402+
else:
2403+
nanosecond = ts.nanosecond
2404+
if nanosecond != 0:
2405+
reso = 'nanosecond'
23972406
if dt is NaT:
23982407
ordinal = NPY_NAT
23992408

@@ -2425,7 +2434,7 @@ class Period(_Period):
24252434
base = freq_to_dtype_code(freq)
24262435
ordinal = period_ordinal(dt.year, dt.month, dt.day,
24272436
dt.hour, dt.minute, dt.second,
2428-
dt.microsecond, 0, base)
2437+
dt.microsecond, 1000*nanosecond, base)
24292438

24302439
return cls._from_ordinal(ordinal, freq)
24312440

pandas/tests/scalar/period/test_period.py

+16
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,22 @@ def test_period_cons_combined(self):
487487
with pytest.raises(ValueError, match=msg):
488488
Period("2011-01", freq="1D1W")
489489

490+
@pytest.mark.parametrize("day", ["1970/01/01 ", "2020-12-31 ", "1981/09/13 "])
491+
@pytest.mark.parametrize("hour", ["00:00:00", "00:00:01", "23:59:59", "12:00:59"])
492+
@pytest.mark.parametrize(
493+
"sec_float, expected",
494+
[
495+
(".000000001", 1),
496+
(".000000999", 999),
497+
(".123456789", 789),
498+
(".999999999", 999),
499+
],
500+
)
501+
def test_period_constructor_nanosecond(self, day, hour, sec_float, expected):
502+
# GH 34621
503+
504+
assert Period(day + hour + sec_float).start_time.nanosecond == expected
505+
490506
@pytest.mark.parametrize("hour", range(24))
491507
def test_period_large_ordinal(self, hour):
492508
# Issue #36430

0 commit comments

Comments
 (0)