From 02b9157b67bbccc6023f41a62d4e845878d301d4 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sun, 10 May 2020 12:53:42 -0700 Subject: [PATCH] REF: make ccalendar objects cimportable --- pandas/_libs/tslibs/ccalendar.pxd | 4 ++++ pandas/_libs/tslibs/ccalendar.pyx | 4 ++++ pandas/_libs/tslibs/fields.pyx | 6 ++++-- pandas/_libs/tslibs/frequencies.pyx | 6 +++--- pandas/_libs/tslibs/parsing.pyx | 6 +++--- pandas/_libs/tslibs/period.pyx | 17 +++++++++++------ pandas/_libs/tslibs/timedeltas.pyx | 6 +++--- pandas/_libs/tslibs/timestamps.pyx | 6 +++--- pandas/_libs/tslibs/tzconversion.pyx | 14 +++++++------- 9 files changed, 42 insertions(+), 27 deletions(-) diff --git a/pandas/_libs/tslibs/ccalendar.pxd b/pandas/_libs/tslibs/ccalendar.pxd index 68ad1d1e68133..b55780fe7d5b9 100644 --- a/pandas/_libs/tslibs/ccalendar.pxd +++ b/pandas/_libs/tslibs/ccalendar.pxd @@ -10,3 +10,7 @@ cpdef int32_t get_days_in_month(int year, Py_ssize_t month) nogil cpdef int32_t get_week_of_year(int year, int month, int day) nogil cpdef iso_calendar_t get_iso_calendar(int year, int month, int day) nogil cpdef int32_t get_day_of_year(int year, int month, int day) nogil + +cdef int64_t DAY_NANOS +cdef int64_t HOUR_NANOS +cdef dict c_MONTH_NUMBERS diff --git a/pandas/_libs/tslibs/ccalendar.pyx b/pandas/_libs/tslibs/ccalendar.pyx index 0873084d29555..2006214169a74 100644 --- a/pandas/_libs/tslibs/ccalendar.pyx +++ b/pandas/_libs/tslibs/ccalendar.pyx @@ -40,6 +40,7 @@ MONTHS_FULL = ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] MONTH_NUMBERS = {name: num for num, name in enumerate(MONTHS)} +cdef dict c_MONTH_NUMBERS = MONTH_NUMBERS MONTH_ALIASES = {(num + 1): name for num, name in enumerate(MONTHS)} MONTH_TO_CAL_NUM = {name: num + 1 for num, name in enumerate(MONTHS)} @@ -52,6 +53,9 @@ weekday_to_int = {int_to_weekday[key]: key for key in int_to_weekday} DAY_SECONDS = 86400 HOUR_SECONDS = 3600 +cdef int64_t DAY_NANOS = DAY_SECONDS * 1_000_000_000 +cdef int64_t HOUR_NANOS = HOUR_SECONDS * 1_000_000_000 + # ---------------------------------------------------------------------- diff --git a/pandas/_libs/tslibs/fields.pyx b/pandas/_libs/tslibs/fields.pyx index 184d368659714..8d83eeb011866 100644 --- a/pandas/_libs/tslibs/fields.pyx +++ b/pandas/_libs/tslibs/fields.pyx @@ -12,8 +12,10 @@ from numpy cimport ndarray, int64_t, int32_t, int8_t, uint32_t cnp.import_array() from pandas._libs.tslibs.ccalendar import ( - get_locale_names, MONTHS_FULL, DAYS_FULL, DAY_SECONDS) + get_locale_names, MONTHS_FULL, DAYS_FULL, +) from pandas._libs.tslibs.ccalendar cimport ( + DAY_NANOS, get_days_in_month, is_leapyear, dayofweek, get_week_of_year, get_day_of_year, get_iso_calendar, iso_calendar_t) from pandas._libs.tslibs.np_datetime cimport ( @@ -38,7 +40,7 @@ def get_time_micros(const int64_t[:] dtindex): cdef: ndarray[int64_t] micros - micros = np.mod(dtindex, DAY_SECONDS * 1_000_000_000, dtype=np.int64) + micros = np.mod(dtindex, DAY_NANOS, dtype=np.int64) micros //= 1000 return micros diff --git a/pandas/_libs/tslibs/frequencies.pyx b/pandas/_libs/tslibs/frequencies.pyx index 41de364c392f7..d97a9fa0ba2fa 100644 --- a/pandas/_libs/tslibs/frequencies.pyx +++ b/pandas/_libs/tslibs/frequencies.pyx @@ -5,7 +5,7 @@ cnp.import_array() from pandas._libs.tslibs.util cimport is_integer_object, is_offset_object -from pandas._libs.tslibs.ccalendar import MONTH_NUMBERS +from pandas._libs.tslibs.ccalendar cimport c_MONTH_NUMBERS # ---------------------------------------------------------------------- # Constants @@ -458,8 +458,8 @@ cdef str _maybe_coerce_freq(code): cdef bint _quarter_months_conform(str source, str target): - snum = MONTH_NUMBERS[source] - tnum = MONTH_NUMBERS[target] + snum = c_MONTH_NUMBERS[source] + tnum = c_MONTH_NUMBERS[target] return snum % 3 == tnum % 3 diff --git a/pandas/_libs/tslibs/parsing.pyx b/pandas/_libs/tslibs/parsing.pyx index c31d4d92c6054..bfa094fcf2891 100644 --- a/pandas/_libs/tslibs/parsing.pyx +++ b/pandas/_libs/tslibs/parsing.pyx @@ -32,7 +32,7 @@ from dateutil.parser import parse as du_parse from pandas._config import get_option -from pandas._libs.tslibs.ccalendar import MONTH_NUMBERS +from pandas._libs.tslibs.ccalendar cimport c_MONTH_NUMBERS from pandas._libs.tslibs.nattype import nat_strings, NaT from pandas._libs.tslibs.util cimport ( is_array, @@ -435,9 +435,9 @@ cdef inline object _parse_dateabbr_string(object date_string, object default, f'between 1 and 4: {date_string}') if freq is not None: - # hack attack, #1228 + # TODO: hack attack, #1228 try: - mnum = MONTH_NUMBERS[get_rule_month(freq)] + 1 + mnum = c_MONTH_NUMBERS[get_rule_month(freq)] + 1 except (KeyError, ValueError): raise DateParseError(f'Unable to retrieve month ' f'information from given ' diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index c5f48fdc8c411..f1bd666472408 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -44,9 +44,14 @@ from pandas._libs.tslibs.timezones cimport is_utc, is_tzlocal, get_dst_info from pandas._libs.tslibs.timedeltas import Timedelta from pandas._libs.tslibs.timedeltas cimport delta_to_nanoseconds -cimport pandas._libs.tslibs.ccalendar as ccalendar -from pandas._libs.tslibs.ccalendar cimport dayofweek, get_day_of_year, is_leapyear -from pandas._libs.tslibs.ccalendar import MONTH_NUMBERS +from pandas._libs.tslibs.ccalendar cimport ( + dayofweek, + get_day_of_year, + is_leapyear, + get_week_of_year, + get_days_in_month, +) +from pandas._libs.tslibs.ccalendar cimport c_MONTH_NUMBERS from pandas._libs.tslibs.frequencies cimport ( get_base_alias, get_freq_code, @@ -1315,7 +1320,7 @@ cdef int pweek(int64_t ordinal, int freq): cdef: npy_datetimestruct dts get_date_info(ordinal, freq, &dts) - return ccalendar.get_week_of_year(dts.year, dts.month, dts.day) + return get_week_of_year(dts.year, dts.month, dts.day) cdef int phour(int64_t ordinal, int freq): @@ -1343,7 +1348,7 @@ cdef int pdays_in_month(int64_t ordinal, int freq): cdef: npy_datetimestruct dts get_date_info(ordinal, freq, &dts) - return ccalendar.get_days_in_month(dts.year, dts.month) + return get_days_in_month(dts.year, dts.month) @cython.wraparound(False) @@ -2486,7 +2491,7 @@ def quarter_to_myear(year: int, quarter: int, freq): if quarter <= 0 or quarter > 4: raise ValueError('Quarter must be 1 <= q <= 4') - mnum = MONTH_NUMBERS[get_rule_month(freq)] + 1 + mnum = c_MONTH_NUMBERS[get_rule_month(freq)] + 1 month = (mnum + (quarter - 1) * 3) % 12 + 1 if month > mnum: year -= 1 diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index ddbeb33d91b6a..c09166be88de8 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -23,7 +23,7 @@ from pandas._libs.tslibs.util cimport ( from pandas._libs.tslibs.base cimport ABCTimedelta, ABCTimestamp, is_tick_object -from pandas._libs.tslibs.ccalendar import DAY_SECONDS +from pandas._libs.tslibs.ccalendar cimport DAY_NANOS from pandas._libs.tslibs.np_datetime cimport ( cmp_scalar, reverse_ops, td64_to_tdstruct, pandas_timedeltastruct) @@ -277,10 +277,10 @@ cpdef inline object precision_from_unit(str unit): m = 1000000000 * 2629746 p = 9 elif unit == 'W': - m = 1000000000 * DAY_SECONDS * 7 + m = DAY_NANOS * 7 p = 9 elif unit == 'D' or unit == 'd': - m = 1000000000 * DAY_SECONDS + m = DAY_NANOS p = 9 elif unit == 'h': m = 1000000000 * 3600 diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index e656d654461c9..1935310e6bbee 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -27,8 +27,8 @@ from pandas._libs.tslibs.util cimport ( from pandas._libs.tslibs.base cimport ABCTimestamp, is_tick_object -cimport pandas._libs.tslibs.ccalendar as ccalendar -from pandas._libs.tslibs.ccalendar import DAY_SECONDS +from pandas._libs.tslibs cimport ccalendar + from pandas._libs.tslibs.conversion import normalize_i8_timestamps from pandas._libs.tslibs.conversion cimport ( _TSObject, convert_to_tsobject, @@ -1504,7 +1504,7 @@ default 'raise' Normalize Timestamp to midnight, preserving tz information. """ if self.tz is None or is_utc(self.tz): - DAY_NS = DAY_SECONDS * 1_000_000_000 + DAY_NS = ccalendar.DAY_NANOS normalized_value = self.value - (self.value % DAY_NS) return Timestamp(normalized_value).tz_localize(self.tz) normalized_value = normalize_i8_timestamps( diff --git a/pandas/_libs/tslibs/tzconversion.pyx b/pandas/_libs/tslibs/tzconversion.pyx index 6915783ac3aaa..fd0dca5475a0b 100644 --- a/pandas/_libs/tslibs/tzconversion.pyx +++ b/pandas/_libs/tslibs/tzconversion.pyx @@ -16,7 +16,7 @@ cimport numpy as cnp from numpy cimport ndarray, int64_t, uint8_t, intp_t cnp.import_array() -from pandas._libs.tslibs.ccalendar import DAY_SECONDS, HOUR_SECONDS +from pandas._libs.tslibs.ccalendar cimport DAY_NANOS, HOUR_NANOS from pandas._libs.tslibs.nattype cimport NPY_NAT from pandas._libs.tslibs.np_datetime cimport ( npy_datetimestruct, dt64_to_dtstruct) @@ -71,7 +71,7 @@ timedelta-like} int64_t *tdata int64_t v, left, right, val, v_left, v_right, new_local, remaining_mins int64_t first_delta - int64_t HOURS_NS = HOUR_SECONDS * 1000000000, shift_delta = 0 + int64_t shift_delta = 0 ndarray[int64_t] trans, result, result_a, result_b, dst_hours, delta ndarray trans_idx, grp, a_idx, b_idx, one_diff npy_datetimestruct dts @@ -142,10 +142,10 @@ timedelta-like} result_b[:] = NPY_NAT idx_shifted_left = (np.maximum(0, trans.searchsorted( - vals - DAY_SECONDS * 1000000000, side='right') - 1)).astype(np.int64) + vals - DAY_NANOS, side='right') - 1)).astype(np.int64) idx_shifted_right = (np.maximum(0, trans.searchsorted( - vals + DAY_SECONDS * 1000000000, side='right') - 1)).astype(np.int64) + vals + DAY_NANOS, side='right') - 1)).astype(np.int64) for i in range(n): val = vals[i] @@ -240,18 +240,18 @@ timedelta-like} # Handle nonexistent times if shift_forward or shift_backward or shift_delta != 0: # Shift the nonexistent time to the closest existing time - remaining_mins = val % HOURS_NS + remaining_mins = val % HOUR_NANOS if shift_delta != 0: # Validate that we don't relocalize on another nonexistent # time - if -1 < shift_delta + remaining_mins < HOURS_NS: + if -1 < shift_delta + remaining_mins < HOUR_NANOS: raise ValueError( f"The provided timedelta will relocalize on a " f"nonexistent time: {nonexistent}" ) new_local = val + shift_delta elif shift_forward: - new_local = val + (HOURS_NS - remaining_mins) + new_local = val + (HOUR_NANOS - remaining_mins) else: # Subtract 1 since the beginning hour is _inclusive_ of # nonexistent times