Skip to content

Commit 0859bac

Browse files
authored
REF: is_subperiod, is_superperiod out of libfreqs (#34387)
1 parent 65d9fe4 commit 0859bac

File tree

5 files changed

+172
-178
lines changed

5 files changed

+172
-178
lines changed

pandas/_libs/tslibs/frequencies.pyx

-160
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ cnp.import_array()
55

66
from pandas._libs.tslibs.util cimport is_integer_object
77

8-
from pandas._libs.tslibs.ccalendar cimport c_MONTH_NUMBERS
98
from pandas._libs.tslibs.offsets cimport is_offset_object
10-
from pandas._libs.tslibs.parsing cimport get_rule_month
119

1210
# ----------------------------------------------------------------------
1311
# Constants
@@ -333,161 +331,3 @@ cpdef int get_to_timestamp_base(int base):
333331
elif FreqGroup.FR_HR <= base <= FreqGroup.FR_SEC:
334332
return FreqGroup.FR_SEC
335333
return base
336-
337-
338-
# ----------------------------------------------------------------------
339-
# Frequency comparison
340-
341-
def is_subperiod(source, target) -> bint:
342-
"""
343-
Returns True if downsampling is possible between source and target
344-
frequencies
345-
346-
Parameters
347-
----------
348-
source : string or DateOffset
349-
Frequency converting from
350-
target : string or DateOffset
351-
Frequency converting to
352-
353-
Returns
354-
-------
355-
is_subperiod : boolean
356-
"""
357-
358-
if target is None or source is None:
359-
return False
360-
source = _maybe_coerce_freq(source)
361-
target = _maybe_coerce_freq(target)
362-
363-
if _is_annual(target):
364-
if _is_quarterly(source):
365-
return _quarter_months_conform(get_rule_month(source),
366-
get_rule_month(target))
367-
return source in {'D', 'C', 'B', 'M', 'H', 'T', 'S', 'L', 'U', 'N'}
368-
elif _is_quarterly(target):
369-
return source in {'D', 'C', 'B', 'M', 'H', 'T', 'S', 'L', 'U', 'N'}
370-
elif _is_monthly(target):
371-
return source in {'D', 'C', 'B', 'H', 'T', 'S', 'L', 'U', 'N'}
372-
elif _is_weekly(target):
373-
return source in {target, 'D', 'C', 'B', 'H', 'T', 'S', 'L', 'U', 'N'}
374-
elif target == 'B':
375-
return source in {'B', 'H', 'T', 'S', 'L', 'U', 'N'}
376-
elif target == 'C':
377-
return source in {'C', 'H', 'T', 'S', 'L', 'U', 'N'}
378-
elif target == 'D':
379-
return source in {'D', 'H', 'T', 'S', 'L', 'U', 'N'}
380-
elif target == 'H':
381-
return source in {'H', 'T', 'S', 'L', 'U', 'N'}
382-
elif target == 'T':
383-
return source in {'T', 'S', 'L', 'U', 'N'}
384-
elif target == 'S':
385-
return source in {'S', 'L', 'U', 'N'}
386-
elif target == 'L':
387-
return source in {'L', 'U', 'N'}
388-
elif target == 'U':
389-
return source in {'U', 'N'}
390-
elif target == 'N':
391-
return source in {'N'}
392-
393-
394-
def is_superperiod(source, target) -> bint:
395-
"""
396-
Returns True if upsampling is possible between source and target
397-
frequencies
398-
399-
Parameters
400-
----------
401-
source : string
402-
Frequency converting from
403-
target : string
404-
Frequency converting to
405-
406-
Returns
407-
-------
408-
is_superperiod : boolean
409-
"""
410-
if target is None or source is None:
411-
return False
412-
source = _maybe_coerce_freq(source)
413-
target = _maybe_coerce_freq(target)
414-
415-
if _is_annual(source):
416-
if _is_annual(target):
417-
return get_rule_month(source) == get_rule_month(target)
418-
419-
if _is_quarterly(target):
420-
smonth = get_rule_month(source)
421-
tmonth = get_rule_month(target)
422-
return _quarter_months_conform(smonth, tmonth)
423-
return target in {'D', 'C', 'B', 'M', 'H', 'T', 'S', 'L', 'U', 'N'}
424-
elif _is_quarterly(source):
425-
return target in {'D', 'C', 'B', 'M', 'H', 'T', 'S', 'L', 'U', 'N'}
426-
elif _is_monthly(source):
427-
return target in {'D', 'C', 'B', 'H', 'T', 'S', 'L', 'U', 'N'}
428-
elif _is_weekly(source):
429-
return target in {source, 'D', 'C', 'B', 'H', 'T', 'S', 'L', 'U', 'N'}
430-
elif source == 'B':
431-
return target in {'D', 'C', 'B', 'H', 'T', 'S', 'L', 'U', 'N'}
432-
elif source == 'C':
433-
return target in {'D', 'C', 'B', 'H', 'T', 'S', 'L', 'U', 'N'}
434-
elif source == 'D':
435-
return target in {'D', 'C', 'B', 'H', 'T', 'S', 'L', 'U', 'N'}
436-
elif source == 'H':
437-
return target in {'H', 'T', 'S', 'L', 'U', 'N'}
438-
elif source == 'T':
439-
return target in {'T', 'S', 'L', 'U', 'N'}
440-
elif source == 'S':
441-
return target in {'S', 'L', 'U', 'N'}
442-
elif source == 'L':
443-
return target in {'L', 'U', 'N'}
444-
elif source == 'U':
445-
return target in {'U', 'N'}
446-
elif source == 'N':
447-
return target in {'N'}
448-
449-
450-
cdef str _maybe_coerce_freq(code):
451-
""" we might need to coerce a code to a rule_code
452-
and uppercase it
453-
454-
Parameters
455-
----------
456-
source : string or DateOffset
457-
Frequency converting from
458-
459-
Returns
460-
-------
461-
code : string
462-
"""
463-
assert code is not None
464-
if is_offset_object(code):
465-
# i.e. isinstance(code, DateOffset):
466-
code = code.rule_code
467-
return code.upper()
468-
469-
470-
cdef bint _quarter_months_conform(str source, str target):
471-
snum = c_MONTH_NUMBERS[source]
472-
tnum = c_MONTH_NUMBERS[target]
473-
return snum % 3 == tnum % 3
474-
475-
476-
cdef bint _is_annual(str rule):
477-
rule = rule.upper()
478-
return rule == 'A' or rule.startswith('A-')
479-
480-
481-
cdef bint _is_quarterly(str rule):
482-
rule = rule.upper()
483-
return rule == 'Q' or rule.startswith('Q-') or rule.startswith('BQ')
484-
485-
486-
cdef bint _is_monthly(str rule):
487-
rule = rule.upper()
488-
return rule == 'M' or rule == 'BM'
489-
490-
491-
cdef bint _is_weekly(str rule):
492-
rule = rule.upper()
493-
return rule == 'W' or rule.startswith('W-')

pandas/core/resample.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
from pandas._libs import lib
99
from pandas._libs.tslibs import NaT, Period, Timedelta, Timestamp
10-
from pandas._libs.tslibs.frequencies import is_subperiod, is_superperiod
1110
from pandas._libs.tslibs.period import IncompatibleFrequency
1211
from pandas._typing import TimedeltaConvertibleTypes, TimestampConvertibleTypes
1312
from pandas.compat.numpy import function as nv
@@ -29,7 +28,7 @@
2928
from pandas.core.indexes.period import PeriodIndex, period_range
3029
from pandas.core.indexes.timedeltas import TimedeltaIndex, timedelta_range
3130

32-
from pandas.tseries.frequencies import to_offset
31+
from pandas.tseries.frequencies import is_subperiod, is_superperiod, to_offset
3332
from pandas.tseries.offsets import DateOffset, Day, Nano, Tick
3433

3534
_shared_docs_kwargs: Dict[str, str] = dict()
@@ -1709,7 +1708,7 @@ def _get_timestamp_range_edges(
17091708
origin = origin.tz_localize(None)
17101709

17111710
first, last = _adjust_dates_anchored(
1712-
first, last, freq, closed=closed, origin=origin, offset=offset,
1711+
first, last, freq, closed=closed, origin=origin, offset=offset
17131712
)
17141713
if isinstance(freq, Day):
17151714
first = first.tz_localize(index_tz)
@@ -1771,7 +1770,7 @@ def _get_period_range_edges(
17711770
adjust_last = freq.is_on_offset(last)
17721771

17731772
first, last = _get_timestamp_range_edges(
1774-
first, last, freq, closed=closed, origin=origin, offset=offset,
1773+
first, last, freq, closed=closed, origin=origin, offset=offset
17751774
)
17761775

17771776
first = (first + int(adjust_first) * freq).to_period(freq)

pandas/plotting/_matplotlib/timeseries.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@
55

66
import numpy as np
77

8-
from pandas._libs.tslibs.frequencies import (
9-
FreqGroup,
10-
base_and_stride,
11-
get_freq_code,
12-
is_subperiod,
13-
is_superperiod,
14-
)
8+
from pandas._libs.tslibs.frequencies import FreqGroup, base_and_stride, get_freq_code
159
from pandas._libs.tslibs.period import Period
1610

1711
from pandas.core.dtypes.generic import (
@@ -27,6 +21,7 @@
2721
TimeSeries_TimedeltaFormatter,
2822
)
2923
import pandas.tseries.frequencies as frequencies
24+
from pandas.tseries.frequencies import is_subperiod, is_superperiod
3025
from pandas.tseries.offsets import DateOffset
3126

3227
# ---------------------------------------------------------------------

pandas/tests/tslibs/test_libfrequencies.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
import pytest
22

3-
from pandas._libs.tslibs.frequencies import (
4-
INVALID_FREQ_ERR_MSG,
5-
_period_str_to_code,
6-
is_subperiod,
7-
is_superperiod,
8-
)
3+
from pandas._libs.tslibs.frequencies import INVALID_FREQ_ERR_MSG, _period_str_to_code
94
from pandas._libs.tslibs.parsing import get_rule_month
105

116
from pandas.tseries import offsets
7+
from pandas.tseries.frequencies import is_subperiod, is_superperiod # TODO: move tests
128

139

1410
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)