-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
CLN: Move some PI/DTI methods to EA subclasses, implement tests #22961
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0a5f343
f1f5146
effef65
4eb5060
09f1b02
68116c4
12eb1b9
ed30d73
5b4c828
61808d3
927e4bd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,14 +10,15 @@ | |
Period, IncompatibleFrequency, DIFFERENT_FREQ_INDEX, | ||
get_period_field_arr, period_asfreq_arr) | ||
from pandas._libs.tslibs import period as libperiod | ||
from pandas._libs.tslibs.timedeltas import delta_to_nanoseconds | ||
from pandas._libs.tslibs.timedeltas import delta_to_nanoseconds, Timedelta | ||
from pandas._libs.tslibs.fields import isleapyear_arr | ||
|
||
from pandas import compat | ||
from pandas.util._decorators import cache_readonly | ||
|
||
from pandas.core.dtypes.common import ( | ||
is_integer_dtype, is_float_dtype, is_period_dtype) | ||
is_integer_dtype, is_float_dtype, is_period_dtype, | ||
is_datetime64_dtype) | ||
from pandas.core.dtypes.dtypes import PeriodDtype | ||
from pandas.core.dtypes.generic import ABCSeries | ||
|
||
|
@@ -127,6 +128,10 @@ def __new__(cls, values, freq=None, **kwargs): | |
freq = values.freq | ||
values = values.asi8 | ||
|
||
elif is_datetime64_dtype(values): | ||
# TODO: what if it has tz? | ||
values = dt64arr_to_periodarr(values, freq) | ||
|
||
return cls._simple_new(values, freq, **kwargs) | ||
|
||
@classmethod | ||
|
@@ -207,6 +212,14 @@ def is_leap_year(self): | |
""" Logical indicating if the date belongs to a leap year """ | ||
return isleapyear_arr(np.asarray(self.year)) | ||
|
||
@property | ||
def start_time(self): | ||
return self.to_timestamp(how='start') | ||
|
||
@property | ||
def end_time(self): | ||
return self.to_timestamp(how='end') | ||
|
||
def asfreq(self, freq=None, how='E'): | ||
""" | ||
Convert the Period Array/Index to the specified frequency `freq`. | ||
|
@@ -266,6 +279,48 @@ def asfreq(self, freq=None, how='E'): | |
|
||
return self._shallow_copy(new_data, freq=freq) | ||
|
||
def to_timestamp(self, freq=None, how='start'): | ||
""" | ||
Cast to DatetimeArray/Index | ||
|
||
Parameters | ||
---------- | ||
freq : string or DateOffset, optional | ||
Target frequency. The default is 'D' for week or longer, | ||
'S' otherwise | ||
how : {'s', 'e', 'start', 'end'} | ||
|
||
Returns | ||
------- | ||
DatetimeArray/Index | ||
""" | ||
from pandas.core.arrays.datetimes import DatetimeArrayMixin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are you able to put these at the top? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that's fragile. This mirrors the existing runtime import in the PeriodIndex method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok that's fine, yeah definitly appreciate making the import hierarchy nicer |
||
|
||
how = libperiod._validate_end_alias(how) | ||
|
||
end = how == 'E' | ||
if end: | ||
if freq == 'B': | ||
# roll forward to ensure we land on B date | ||
adjust = Timedelta(1, 'D') - Timedelta(1, 'ns') | ||
return self.to_timestamp(how='start') + adjust | ||
else: | ||
adjust = Timedelta(1, 'ns') | ||
return (self + 1).to_timestamp(how='start') - adjust | ||
|
||
if freq is None: | ||
base, mult = frequencies.get_freq_code(self.freq) | ||
freq = frequencies.get_to_timestamp_base(base) | ||
else: | ||
freq = Period._maybe_convert_freq(freq) | ||
|
||
base, mult = frequencies.get_freq_code(freq) | ||
new_data = self.asfreq(freq, how=how) | ||
|
||
new_data = libperiod.periodarr_to_dt64arr(new_data._ndarray_values, | ||
base) | ||
return DatetimeArrayMixin(new_data, freq='infer') | ||
|
||
# ------------------------------------------------------------------ | ||
# Arithmetic Methods | ||
|
||
|
@@ -392,6 +447,15 @@ def _maybe_convert_timedelta(self, other): | |
# ------------------------------------------------------------------- | ||
# Constructor Helpers | ||
|
||
def dt64arr_to_periodarr(data, freq, tz=None): | ||
if data.dtype != np.dtype('M8[ns]'): | ||
raise ValueError('Wrong dtype: %s' % data.dtype) | ||
|
||
freq = Period._maybe_convert_freq(freq) | ||
base, mult = frequencies.get_freq_code(freq) | ||
return libperiod.dt64arr_to_periodarr(data.view('i8'), base, tz) | ||
|
||
|
||
def _get_ordinal_range(start, end, periods, freq, mult=1): | ||
if com.count_not_none(start, end, periods) != 2: | ||
raise ValueError('Of the three parameters: start, end, and periods, ' | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably a warning, right? Maybe push the one that's in
DatetimeIndex.to_period
down here? That can be a separate PR though, since there may be other places calling PeriodArray with a tz-awarevalues
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, yah.
If it doesn't mess up your plans too much, after this I'd like to do a PR cleaning up some of the duplicated/convoluted constructors in (Period|Datetime|Timedelta)(Index|ArrayMixin). I think making some helper functions etc before the bigger refactor would help focus attention during the latter.