Skip to content

Commit 018aa79

Browse files
committed
updated whatsnew and simplified to_timestamp(how='end')
1 parent a23bae4 commit 018aa79

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
@@ -535,6 +535,61 @@ Returning a ``Series`` allows one to control the exact return structure and colu
535535

536536
.. _whatsnew_0230.api_breaking.build_changes:
537537

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

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 (
@@ -1221,6 +1222,10 @@ cdef class _Period(object):
12211222
freq = self._maybe_convert_freq(freq)
12221223
how = _validate_end_alias(how)
12231224

1225+
end = how == 'E'
1226+
if end:
1227+
return (self + 1).to_timestamp(how='start') - pd.Timedelta(1, 'ns')
1228+
12241229
if freq is None:
12251230
base, mult = get_freq_code(self.freq)
12261231
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)