Skip to content

Commit da6668f

Browse files
committed
updated whatsnew and simplified to_timestamp(how='end')
1 parent c634319 commit da6668f

File tree

4 files changed

+71
-10
lines changed

4 files changed

+71
-10
lines changed

doc/source/whatsnew/v0.23.0.txt

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,61 @@ Returning a ``Series`` allows one to control the exact return structure and colu
533533

534534
.. _whatsnew_0230.api_breaking.build_changes:
535535

536+
.. _whatsnew_0230.api_breaking.end_time:
537+
538+
Time values in ``dt.end_time`` and ``to_timestamp(how='end')``
539+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
540+
541+
The time values in ``Period`` and ``PeriodIndex`` objects are now adjusted
542+
appropriately when calling :attr:`Series.dt.end_time`, :attr:`Period.end_time`,
543+
:attr:`PeriodIndex.end_time`, :func:`Period.to_timestamp()` with ``how='end'``,
544+
and :func:`PeriodIndex.to_timestamp()` with ``how='end'`` (:issue:`17157`)
545+
546+
Previous Behavior:
547+
548+
.. code-block:: ipython
549+
550+
In [2]: p = pd.Period('2017-01-01', 'D')
551+
In [3]: pi = pd.PeriodIndex([p])
552+
553+
In [4]: pd.Series(p).dt.end_time[0]
554+
Out[4]: Timestamp(2017-01-01 00:00:00)
555+
556+
In [5]: pd.Series(pi).dt.end_time[0]
557+
Out[5]: Timestamp(2017-01-01 00:00:00)
558+
559+
In [6]: p.end_time
560+
Out[6]: Timestamp(2017-01-01 23:59:59.999999999)
561+
562+
In [7]: pi.end_time[0]
563+
Out[7]: Timestamp(2017-01-01 00:00:00)
564+
565+
In [8]: p.to_timestamp(how='end')
566+
Out[8]: Timestamp(2017-01-01 00:00:00)
567+
568+
In [9]: pi.to_timestamp(how='end')[0]
569+
Out[9]: Timestamp(2017-01-01 00:00:00)
570+
571+
Current Behavior
572+
573+
.. ipython:: python
574+
575+
p = pd.Period('2017-01-01', 'D')
576+
pi = pd.PeriodIndex([p])
577+
578+
pd.Series(p).dt.end_time[0]
579+
580+
pd.Series(pi).dt.end_time[0]
581+
582+
p.end_time
583+
584+
pi.end_time[0]
585+
586+
p.to_timestamp(how='end')
587+
588+
pi.to_timestamp(how='end')[0]
589+
590+
536591
Build Changes
537592
^^^^^^^^^^^^^
538593

pandas/_libs/tslibs/period.pyx

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

56
from cpython cimport (
@@ -1195,6 +1196,10 @@ cdef class _Period(object):
11951196
freq = self._maybe_convert_freq(freq)
11961197
how = _validate_end_alias(how)
11971198

1199+
end = how == 'E'
1200+
if end:
1201+
return (self + 1).to_timestamp(how='start') - pd.Timedelta(1, 'ns')
1202+
11981203
if freq is None:
11991204
base, mult = get_freq_code(self.freq)
12001205
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, timedelta
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 (
@@ -674,6 +675,10 @@ def to_timestamp(self, freq=None, how='start'):
674675
"""
675676
how = _validate_end_alias(how)
676677

678+
end = how == 'E'
679+
if end:
680+
return (self + 1).to_timestamp(how='start') - pd.Timedelta(1, 'ns')
681+
677682
if freq is None:
678683
base, mult = _gfc(self.freq)
679684
freq = frequencies.get_to_timestamp_base(base)
@@ -683,16 +688,7 @@ def to_timestamp(self, freq=None, how='start'):
683688
base, mult = _gfc(freq)
684689
new_data = self.asfreq(freq, how)
685690

686-
end = how == 'E'
687-
if end:
688-
indexer = np.where(new_data.notnull())
689-
# move forward one period
690-
new_data._values[indexer] += 1
691-
new_data = period.periodarr_to_dt64arr(new_data._values, base)
692-
# subtract one nanosecond
693-
new_data[indexer] -= 1
694-
else:
695-
new_data = period.periodarr_to_dt64arr(new_data._values, base)
691+
new_data = period.periodarr_to_dt64arr(new_data._values, base)
696692
return DatetimeIndex(new_data, freq='infer', name=self.name)
697693

698694
def _maybe_convert_timedelta(self, other):

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)