Skip to content

Commit 5c8ef85

Browse files
committed
updated whatsnew and simplified to_timestamp(how='end')
1 parent d971c90 commit 5c8ef85

File tree

4 files changed

+72
-11
lines changed

4 files changed

+72
-11
lines changed

doc/source/whatsnew/v0.23.0.txt

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,61 @@ Note that this change also applies to :meth:`DataFrame.append`, which has also r
777777

778778
.. _whatsnew_0230.api_breaking.build_changes:
779779

780+
.. _whatsnew_0230.api_breaking.end_time:
781+
782+
Time values in ``dt.end_time`` and ``to_timestamp(how='end')``
783+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
784+
785+
The time values in ``Period`` and ``PeriodIndex`` objects are now adjusted
786+
appropriately when calling :attr:`Series.dt.end_time`, :attr:`Period.end_time`,
787+
:attr:`PeriodIndex.end_time`, :func:`Period.to_timestamp()` with ``how='end'``,
788+
and :func:`PeriodIndex.to_timestamp()` with ``how='end'`` (:issue:`17157`)
789+
790+
Previous Behavior:
791+
792+
.. code-block:: ipython
793+
794+
In [2]: p = pd.Period('2017-01-01', 'D')
795+
In [3]: pi = pd.PeriodIndex([p])
796+
797+
In [4]: pd.Series(p).dt.end_time[0]
798+
Out[4]: Timestamp(2017-01-01 00:00:00)
799+
800+
In [5]: pd.Series(pi).dt.end_time[0]
801+
Out[5]: Timestamp(2017-01-01 00:00:00)
802+
803+
In [6]: p.end_time
804+
Out[6]: Timestamp(2017-01-01 23:59:59.999999999)
805+
806+
In [7]: pi.end_time[0]
807+
Out[7]: Timestamp(2017-01-01 00:00:00)
808+
809+
In [8]: p.to_timestamp(how='end')
810+
Out[8]: Timestamp(2017-01-01 00:00:00)
811+
812+
In [9]: pi.to_timestamp(how='end')[0]
813+
Out[9]: Timestamp(2017-01-01 00:00:00)
814+
815+
Current Behavior
816+
817+
.. ipython:: python
818+
819+
p = pd.Period('2017-01-01', 'D')
820+
pi = pd.PeriodIndex([p])
821+
822+
pd.Series(p).dt.end_time[0]
823+
824+
pd.Series(pi).dt.end_time[0]
825+
826+
p.end_time
827+
828+
pi.end_time[0]
829+
830+
p.to_timestamp(how='end')
831+
832+
pi.to_timestamp(how='end')[0]
833+
834+
780835
Build Changes
781836
^^^^^^^^^^^^^
782837

pandas/_libs/tslibs/period.pyx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22
# cython: profile=False
3-
from datetime import datetime, date
3+
import pandas as pd
4+
from datetime import datetime, date, timedelta
45

56
from cpython cimport (
67
PyUnicode_Check,
@@ -1220,6 +1221,10 @@ cdef class _Period(object):
12201221
freq = self._maybe_convert_freq(freq)
12211222
how = _validate_end_alias(how)
12221223

1224+
end = how == 'E'
1225+
if end:
1226+
return (self + 1).to_timestamp(how='start') - pd.Timedelta(1, 'ns')
1227+
12231228
if freq is None:
12241229
base, mult = get_freq_code(self.freq)
12251230
freq = get_to_timestamp_base(base)

pandas/core/indexes/period.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from datetime import datetime
33
import numpy as np
44
import warnings
5+
import pandas as pd
56

67
from pandas.core import common as com
78
from pandas.core.dtypes.common import (
@@ -504,6 +505,10 @@ def to_timestamp(self, freq=None, how='start'):
504505
"""
505506
how = _validate_end_alias(how)
506507

508+
end = how == 'E'
509+
if end:
510+
return (self + 1).to_timestamp(how='start') - pd.Timedelta(1, 'ns')
511+
507512
if freq is None:
508513
base, mult = _gfc(self.freq)
509514
freq = frequencies.get_to_timestamp_base(base)
@@ -513,16 +518,7 @@ def to_timestamp(self, freq=None, how='start'):
513518
base, mult = _gfc(freq)
514519
new_data = self.asfreq(freq, how)
515520

516-
end = how == 'E'
517-
if end:
518-
indexer = np.where(new_data.notnull())
519-
# move forward one period
520-
new_data._values[indexer] += 1
521-
new_data = period.periodarr_to_dt64arr(new_data._values, base)
522-
# subtract one nanosecond
523-
new_data[indexer] -= 1
524-
else:
525-
new_data = period.periodarr_to_dt64arr(new_data._values, base)
521+
new_data = period.periodarr_to_dt64arr(new_data._values, base)
526522
return DatetimeIndex(new_data, freq='infer', name=self.name)
527523

528524
@property

pandas/tests/indexes/period/test_tools.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def test_to_timestamp(self):
6060

6161
exp_index = date_range('1/1/2001', end='12/31/2009', freq='A-DEC')
6262
result = series.to_timestamp(how='end')
63+
exp_index = exp_index + pd.Timedelta(1, 'D') - pd.Timedelta(1, 'ns')
6364
tm.assert_index_equal(result.index, exp_index)
6465
assert result.name == 'foo'
6566

@@ -74,16 +75,19 @@ def _get_with_delta(delta, freq='A-DEC'):
7475
delta = timedelta(hours=23)
7576
result = series.to_timestamp('H', 'end')
7677
exp_index = _get_with_delta(delta)
78+
exp_index = exp_index + pd.Timedelta(1, 'h') - pd.Timedelta(1, 'ns')
7779
tm.assert_index_equal(result.index, exp_index)
7880

7981
delta = timedelta(hours=23, minutes=59)
8082
result = series.to_timestamp('T', 'end')
8183
exp_index = _get_with_delta(delta)
84+
exp_index = exp_index + pd.Timedelta(1, 'm') - pd.Timedelta(1, 'ns')
8285
tm.assert_index_equal(result.index, exp_index)
8386

8487
result = series.to_timestamp('S', 'end')
8588
delta = timedelta(hours=23, minutes=59, seconds=59)
8689
exp_index = _get_with_delta(delta)
90+
exp_index = exp_index + pd.Timedelta(1, 's') - pd.Timedelta(1, 'ns')
8791
tm.assert_index_equal(result.index, exp_index)
8892

8993
index = PeriodIndex(freq='H', start='1/1/2001', end='1/2/2001')
@@ -92,6 +96,7 @@ def _get_with_delta(delta, freq='A-DEC'):
9296
exp_index = date_range('1/1/2001 00:59:59', end='1/2/2001 00:59:59',
9397
freq='H')
9498
result = series.to_timestamp(how='end')
99+
exp_index = exp_index + pd.Timedelta(1, 's') - pd.Timedelta(1, 'ns')
95100
tm.assert_index_equal(result.index, exp_index)
96101
assert result.name == 'foo'
97102

0 commit comments

Comments
 (0)