Skip to content

Commit d40d0c5

Browse files
authored
REF: share PeriodArray.asfreq with Period.asfreq (pandas-dev#39277)
1 parent aab1744 commit d40d0c5

File tree

2 files changed

+57
-51
lines changed

2 files changed

+57
-51
lines changed

pandas/_libs/tslibs/period.pyx

+52-46
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import warnings
22

3+
cimport numpy as cnp
34
from cpython.object cimport Py_EQ, Py_NE, PyObject_RichCompareBool
4-
from numpy cimport import_array, int64_t, ndarray
5+
from numpy cimport int64_t, ndarray
56

67
import numpy as np
78

8-
import_array()
9+
cnp.import_array()
910

1011
from libc.stdlib cimport free, malloc
1112
from libc.string cimport memset, strlen
@@ -75,6 +76,7 @@ from pandas._libs.tslibs.dtypes cimport (
7576
attrname_to_abbrevs,
7677
)
7778
from pandas._libs.tslibs.parsing cimport quarter_to_myear
79+
7880
from pandas._libs.tslibs.parsing import parse_time_string
7981

8082
from pandas._libs.tslibs.nattype cimport (
@@ -993,29 +995,6 @@ def periodarr_to_dt64arr(const int64_t[:] periodarr, int freq):
993995
return ensure_datetime64ns(dta)
994996

995997

996-
cpdef int64_t period_asfreq(int64_t ordinal, int freq1, int freq2, bint end):
997-
"""
998-
Convert period ordinal from one frequency to another, and if upsampling,
999-
choose to use start ('S') or end ('E') of period.
1000-
"""
1001-
cdef:
1002-
int64_t retval
1003-
freq_conv_func func
1004-
asfreq_info af_info
1005-
1006-
if ordinal == NPY_NAT:
1007-
return NPY_NAT
1008-
1009-
func = get_asfreq_func(freq1, freq2)
1010-
get_asfreq_info(freq1, freq2, end, &af_info)
1011-
retval = func(ordinal, &af_info)
1012-
1013-
if retval == INT32_MIN:
1014-
raise ValueError('Frequency conversion failed')
1015-
1016-
return retval
1017-
1018-
1019998
cdef void get_asfreq_info(int from_freq, int to_freq,
1020999
bint is_end, asfreq_info *af_info) nogil:
10211000
"""
@@ -1068,6 +1047,18 @@ cdef inline int calc_week_end(int freq, int group) nogil:
10681047
return freq - group
10691048

10701049

1050+
cpdef int64_t period_asfreq(int64_t ordinal, int freq1, int freq2, bint end):
1051+
"""
1052+
Convert period ordinal from one frequency to another, and if upsampling,
1053+
choose to use start ('S') or end ('E') of period.
1054+
"""
1055+
cdef:
1056+
int64_t retval
1057+
1058+
_period_asfreq(&ordinal, &retval, 1, freq1, freq2, end)
1059+
return retval
1060+
1061+
10711062
@cython.wraparound(False)
10721063
@cython.boundscheck(False)
10731064
def period_asfreq_arr(ndarray[int64_t] arr, int freq1, int freq2, bint end):
@@ -1076,35 +1067,50 @@ def period_asfreq_arr(ndarray[int64_t] arr, int freq1, int freq2, bint end):
10761067
if upsampling, choose to use start ('S') or end ('E') of period.
10771068
"""
10781069
cdef:
1079-
int64_t[:] result
1080-
Py_ssize_t i, n
1070+
Py_ssize_t n = len(arr)
1071+
ndarray[int64_t] result = np.empty(n, dtype=np.int64)
1072+
1073+
_period_asfreq(
1074+
<int64_t*>cnp.PyArray_DATA(arr),
1075+
<int64_t*>cnp.PyArray_DATA(result),
1076+
n,
1077+
freq1,
1078+
freq2,
1079+
end,
1080+
)
1081+
return result
1082+
1083+
1084+
@cython.wraparound(False)
1085+
@cython.boundscheck(False)
1086+
cdef void _period_asfreq(
1087+
int64_t* ordinals,
1088+
int64_t* out,
1089+
Py_ssize_t length,
1090+
int freq1,
1091+
int freq2,
1092+
bint end,
1093+
):
1094+
"""See period_asfreq.__doc__"""
1095+
cdef:
1096+
Py_ssize_t i
10811097
freq_conv_func func
10821098
asfreq_info af_info
10831099
int64_t val
10841100

1085-
n = len(arr)
1086-
result = np.empty(n, dtype=np.int64)
1101+
if length == 1 and ordinals[0] == NPY_NAT:
1102+
# fastpath avoid calling get_asfreq_func
1103+
out[0] = NPY_NAT
1104+
return
10871105

10881106
func = get_asfreq_func(freq1, freq2)
10891107
get_asfreq_info(freq1, freq2, end, &af_info)
10901108

1091-
mask = arr == NPY_NAT
1092-
if mask.any(): # NaT process
1093-
for i in range(n):
1094-
val = arr[i]
1095-
if val != NPY_NAT:
1096-
val = func(val, &af_info)
1097-
if val == INT32_MIN:
1098-
raise ValueError("Unable to convert to desired frequency.")
1099-
result[i] = val
1100-
else:
1101-
for i in range(n):
1102-
val = func(arr[i], &af_info)
1103-
if val == INT32_MIN:
1104-
raise ValueError("Unable to convert to desired frequency.")
1105-
result[i] = val
1106-
1107-
return result.base # .base to access underlying np.ndarray
1109+
for i in range(length):
1110+
val = ordinals[i]
1111+
if val != NPY_NAT:
1112+
val = func(val, &af_info)
1113+
out[i] = val
11081114

11091115

11101116
cpdef int64_t period_ordinal(int y, int m, int d, int h, int min,

pandas/_libs/tslibs/timezones.pyx

+5-5
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ cpdef inline tzinfo maybe_get_tz(object tz):
123123
return tz
124124

125125

126-
def _p_tz_cache_key(tz):
126+
def _p_tz_cache_key(tz: tzinfo):
127127
"""
128128
Python interface for cache function to facilitate testing.
129129
"""
@@ -350,18 +350,18 @@ cpdef bint tz_compare(tzinfo start, tzinfo end):
350350
return get_timezone(start) == get_timezone(end)
351351

352352

353-
def tz_standardize(tz: tzinfo):
353+
def tz_standardize(tz: tzinfo) -> tzinfo:
354354
"""
355355
If the passed tz is a pytz timezone object, "normalize" it to the a
356356
consistent version
357357

358358
Parameters
359359
----------
360-
tz : tz object
360+
tz : tzinfo
361361

362-
Returns:
362+
Returns
363363
-------
364-
tz object
364+
tzinfo
365365

366366
Examples:
367367
--------

0 commit comments

Comments
 (0)