From 7cc0d9e853033b2862358991169880d17cf881f1 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Sat, 4 Aug 2018 12:59:26 -0700 Subject: [PATCH 1/6] finish moving period_helper to cython --- pandas/_libs/tslibs/period.pyx | 645 ++++++++++++++++++++++-- pandas/_libs/tslibs/src/period_helper.c | 603 ---------------------- pandas/_libs/tslibs/src/period_helper.h | 114 ----- pandas/_libs/tslibs/timedeltas.pyx | 53 +- setup.py | 7 +- 5 files changed, 642 insertions(+), 780 deletions(-) delete mode 100644 pandas/_libs/tslibs/src/period_helper.c delete mode 100644 pandas/_libs/tslibs/src/period_helper.h diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index 811f0d25c3838..4adf74fe5e459 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -# cython: profile=False from datetime import datetime, date from cpython cimport ( @@ -34,9 +33,9 @@ cdef extern from "../src/datetime/np_datetime.h": cimport util from util cimport is_period_object, is_string_object, INT32_MIN -from pandas._libs.tslibs.timedeltas import Timedelta from timestamps import Timestamp from timezones cimport is_utc, is_tzlocal, get_dst_info +from timedeltas import Timedelta from timedeltas cimport delta_to_nanoseconds cimport ccalendar @@ -55,7 +54,100 @@ from offsets import _Tick cdef bint PY2 = str == bytes -cdef extern from "period_helper.h": + +ctypedef struct asfreq_info: + int64_t intraday_conversion_factor + int is_end + int to_end + int from_end + +ctypedef int64_t (*freq_conv_func)(int64_t, asfreq_info*) nogil + + +cdef extern from *: + """ + /*** FREQUENCY CONSTANTS ***/ + + #define FR_ANN 1000 /* Annual */ + #define FR_ANNDEC FR_ANN /* Annual - December year end*/ + #define FR_ANNJAN 1001 /* Annual - January year end*/ + #define FR_ANNFEB 1002 /* Annual - February year end*/ + #define FR_ANNMAR 1003 /* Annual - March year end*/ + #define FR_ANNAPR 1004 /* Annual - April year end*/ + #define FR_ANNMAY 1005 /* Annual - May year end*/ + #define FR_ANNJUN 1006 /* Annual - June year end*/ + #define FR_ANNJUL 1007 /* Annual - July year end*/ + #define FR_ANNAUG 1008 /* Annual - August year end*/ + #define FR_ANNSEP 1009 /* Annual - September year end*/ + #define FR_ANNOCT 1010 /* Annual - October year end*/ + #define FR_ANNNOV 1011 /* Annual - November year end*/ + + /* The standard quarterly frequencies with various fiscal year ends + eg, Q42005 for Q@OCT runs Aug 1, 2005 to Oct 31, 2005 */ + #define FR_QTR 2000 /* Quarterly - December year end (default quarterly) */ + #define FR_QTRDEC FR_QTR /* Quarterly - December year end */ + #define FR_QTRJAN 2001 /* Quarterly - January year end */ + #define FR_QTRFEB 2002 /* Quarterly - February year end */ + #define FR_QTRMAR 2003 /* Quarterly - March year end */ + #define FR_QTRAPR 2004 /* Quarterly - April year end */ + #define FR_QTRMAY 2005 /* Quarterly - May year end */ + #define FR_QTRJUN 2006 /* Quarterly - June year end */ + #define FR_QTRJUL 2007 /* Quarterly - July year end */ + #define FR_QTRAUG 2008 /* Quarterly - August year end */ + #define FR_QTRSEP 2009 /* Quarterly - September year end */ + #define FR_QTROCT 2010 /* Quarterly - October year end */ + #define FR_QTRNOV 2011 /* Quarterly - November year end */ + + #define FR_MTH 3000 /* Monthly */ + + #define FR_WK 4000 /* Weekly */ + #define FR_WKSUN FR_WK /* Weekly - Sunday end of week */ + #define FR_WKMON 4001 /* Weekly - Monday end of week */ + #define FR_WKTUE 4002 /* Weekly - Tuesday end of week */ + #define FR_WKWED 4003 /* Weekly - Wednesday end of week */ + #define FR_WKTHU 4004 /* Weekly - Thursday end of week */ + #define FR_WKFRI 4005 /* Weekly - Friday end of week */ + #define FR_WKSAT 4006 /* Weekly - Saturday end of week */ + + #define FR_BUS 5000 /* Business days */ + #define FR_DAY 6000 /* Daily */ + #define FR_HR 7000 /* Hourly */ + #define FR_MIN 8000 /* Minutely */ + #define FR_SEC 9000 /* Secondly */ + #define FR_MS 10000 /* Millisecondly */ + #define FR_US 11000 /* Microsecondly */ + #define FR_NS 12000 /* Nanosecondly */ + + #define FR_UND -10000 /* Undefined */ + + static int64_t daytime_conversion_factor_matrix[7][7] = { + {1, 24, 1440, 86400, 86400000, 86400000000, 86400000000000}, + {0, 1, 60, 3600, 3600000, 3600000000, 3600000000000}, + {0, 0, 1, 60, 60000, 60000000, 60000000000}, + {0, 0, 0, 1, 1000, 1000000, 1000000000}, + {0, 0, 0, 0, 1, 1000, 1000000}, + {0, 0, 0, 0, 0, 1, 1000}, + {0, 0, 0, 0, 0, 0, 1}}; + + int max_value(int a, int b) { return a > b ? a : b; } + + static int min_value(int a, int b) { return a < b ? a : b; } + + npy_int64 get_daytime_conversion_factor(int from_index, int to_index) { + int row = min_value(from_index, to_index); + int col = max_value(from_index, to_index); + // row or col < 6 means frequency strictly lower than Daily, which + // do not use daytime_conversion_factors + if (row < 6) { + return 0; + } else if (col < 6) { + return 0; + } + return daytime_conversion_factor_matrix[row - 6][col - 6]; + } + """ + int64_t get_daytime_conversion_factor(int from_index, int to_index) nogil + int max_value(int left, int right) nogil int FR_ANN int FR_QTR int FR_MTH @@ -70,21 +162,512 @@ cdef extern from "period_helper.h": int FR_BUS int FR_UND - ctypedef struct asfreq_info: - int64_t intraday_conversion_factor - int is_end - int to_end - int from_end +cdef int64_t nofunc(int64_t ordinal, asfreq_info *af_info): + return np.iinfo(np.int32).min - ctypedef int64_t (*freq_conv_func)(int64_t, asfreq_info*) nogil - freq_conv_func get_asfreq_func(int fromFreq, int toFreq) nogil +cdef int64_t no_op(int64_t ordinal, asfreq_info *af_info): + return ordinal - int64_t get_daytime_conversion_factor(int from_index, int to_index) nogil - int max_value(int left, int right) nogil + +cdef freq_conv_func get_asfreq_func(int from_freq, int to_freq) nogil: + cdef: + int from_group = get_freq_group(from_freq) + int to_group = get_freq_group(to_freq) + + if from_group == FR_UND: + from_group = FR_DAY + + if from_group == FR_BUS: + if to_group == FR_ANN: + return asfreq_BtoA + elif to_group == FR_QTR: + return asfreq_BtoQ + elif to_group == FR_MTH: + return asfreq_BtoM + elif to_group == FR_WK: + return asfreq_BtoW + elif to_group == FR_BUS: + return no_op + elif to_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, FR_MS, FR_US, FR_NS]: + return asfreq_BtoDT + else: + return nofunc + + elif to_group == FR_BUS: + if from_group == FR_ANN: + return asfreq_AtoB + elif from_group == FR_QTR: + return asfreq_QtoB + elif from_group == FR_MTH: + return asfreq_MtoB + elif from_group == FR_WK: + return asfreq_WtoB + elif from_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, FR_MS, FR_US, FR_NS]: + return asfreq_DTtoB + else: + return nofunc + + elif from_group == FR_ANN: + if to_group == FR_ANN: + return asfreq_AtoA + elif to_group == FR_QTR: + return asfreq_AtoQ + elif to_group == FR_MTH: + return asfreq_AtoM + elif to_group == FR_WK: + return asfreq_AtoW + elif to_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, FR_MS, FR_US, FR_NS]: + return asfreq_AtoDT + else: + return nofunc + + elif from_group == FR_QTR: + if to_group == FR_ANN: + return asfreq_QtoA + elif to_group == FR_QTR: + return asfreq_QtoQ + elif to_group == FR_MTH: + return asfreq_QtoM + elif to_group == FR_WK: + return asfreq_QtoW + elif to_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, FR_MS, FR_US, FR_NS]: + return asfreq_QtoDT + else: + return nofunc + + elif from_group == FR_MTH: + if to_group == FR_ANN: + return asfreq_MtoA + elif to_group == FR_QTR: + return asfreq_MtoQ + elif to_group == FR_MTH: + return no_op + elif to_group == FR_WK: + return asfreq_MtoW + elif to_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, FR_MS, FR_US, FR_NS]: + return asfreq_MtoDT + else: + return nofunc + + elif from_group == FR_WK: + if to_group == FR_ANN: + return asfreq_WtoA + elif to_group == FR_QTR: + return asfreq_WtoQ + elif to_group == FR_MTH: + return asfreq_WtoM + elif to_group == FR_WK: + return asfreq_WtoW + elif to_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, FR_MS, FR_US, FR_NS]: + return asfreq_WtoDT + else: + return nofunc + + elif from_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, FR_MS, FR_US, FR_NS]: + if to_group == FR_ANN: + return asfreq_DTtoA + elif to_group == FR_QTR: + return asfreq_DTtoQ + elif to_group == FR_MTH: + return asfreq_DTtoM + elif to_group == FR_WK: + return asfreq_DTtoW + elif to_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, FR_MS, FR_US, FR_NS]: + if from_group > to_group: + return downsample_daytime + else: + return upsample_daytime + + else: + return nofunc + + else: + return nofunc + + +# -------------------------------------------------------------------- +# Frequency Conversion Helpers + +cdef int64_t DtoB_weekday(int64_t unix_date) nogil: + return ((unix_date + 4) // 7) * 5 + ((unix_date + 4) % 7) - 4 + + +cdef int64_t DtoB(npy_datetimestruct *dts, int roll_back, int64_t unix_date): + cdef: + int day_of_week = dayofweek(dts.year, dts.month, dts.day) + + if roll_back == 1: + if day_of_week > 4: + # change to friday before weekend + unix_date -= (day_of_week - 4) + else: + if day_of_week > 4: + # change to Monday after weekend + unix_date += (7 - day_of_week) + + return DtoB_weekday(unix_date) + + +cdef inline int64_t upsample_daytime(int64_t ordinal, asfreq_info *af_info): + if (af_info.is_end): + return (ordinal + 1) * af_info.intraday_conversion_factor - 1 + else: + return ordinal * af_info.intraday_conversion_factor + + +cdef inline int64_t downsample_daytime(int64_t ordinal, asfreq_info *af_info): + return ordinal // (af_info.intraday_conversion_factor) + + +cdef inline int64_t transform_via_day(int64_t ordinal, + asfreq_info *af_info, + freq_conv_func first_func, + freq_conv_func second_func): + cdef: + int64_t result + + result = first_func(ordinal, af_info) + result = second_func(result, af_info) + return result + +# -------------------------------------------------------------------- +# Conversion _to_ Daily Freq + +cdef void AtoD_ym(int64_t ordinal, int64_t *year, + int *month, asfreq_info *af_info): + year[0] = ordinal + 1970 + month[0] = 1 + + if af_info.from_end != 12: + month[0] += af_info.from_end + if month[0] > 12: + # This case is never reached, but is kept for symmetry + # with QtoD_ym + month[0] -= 12 + else: + year[0] -= 1 + + +cdef int64_t asfreq_AtoDT(int64_t ordinal, asfreq_info *af_info): + cdef: + int64_t unix_date, year + int month + + ordinal += af_info.is_end + AtoD_ym(ordinal, &year, &month, af_info) + + unix_date = unix_date_from_ymd(year, month, 1) + unix_date -= af_info.is_end + return upsample_daytime(unix_date, af_info) + + +cdef void QtoD_ym(int64_t ordinal, int *year, + int *month, asfreq_info *af_info): + year[0] = ordinal // 4 + 1970 + month[0] = (ordinal % 4) * 3 + 1 + + if af_info.from_end != 12: + month[0] += af_info.from_end + if month[0] > 12: + month[0] -= 12 + else: + year[0] -= 1 + + +cdef int64_t asfreq_QtoDT(int64_t ordinal, asfreq_info *af_info): + cdef: + int64_t unix_date + int year, month + + ordinal += af_info.is_end + QtoD_ym(ordinal, &year, &month, af_info) + + unix_date = unix_date_from_ymd(year, month, 1) + unix_date -= af_info.is_end + return upsample_daytime(unix_date, af_info) + + +cdef void MtoD_ym(int64_t ordinal, int *year, int *month): + year[0] = ordinal // 12 + 1970 + month[0] = ordinal % 12 + 1 + + +cdef int64_t asfreq_MtoDT(int64_t ordinal, asfreq_info *af_info): + cdef: + int64_t unix_date + int year, month + + ordinal += af_info.is_end + MtoD_ym(ordinal, &year, &month) + + unix_date = unix_date_from_ymd(year, month, 1) + unix_date -= af_info.is_end + return upsample_daytime(unix_date, af_info) + + +cdef int64_t asfreq_WtoDT(int64_t ordinal, asfreq_info *af_info): + ordinal = (ordinal * 7 + af_info.from_end - 4 + + (7 - 1) * (af_info.is_end - 1)) + return upsample_daytime(ordinal, af_info) + + +# -------------------------------------------------------------------- +# Conversion _to_ BusinessDay Freq + +cdef int64_t asfreq_AtoB(int64_t ordinal, asfreq_info *af_info): + cdef: + int roll_back + npy_datetimestruct dts + int64_t unix_date = asfreq_AtoDT(ordinal, af_info) + + pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, &dts) + roll_back = af_info.is_end + return DtoB(&dts, roll_back, unix_date) + + +cdef int64_t asfreq_QtoB(int64_t ordinal, asfreq_info *af_info): + cdef: + int roll_back + npy_datetimestruct dts + int64_t unix_date = asfreq_QtoDT(ordinal, af_info) + + pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, &dts) + roll_back = af_info.is_end + return DtoB(&dts, roll_back, unix_date) + + +cdef int64_t asfreq_MtoB(int64_t ordinal, asfreq_info *af_info): + cdef: + int roll_back + npy_datetimestruct dts + int64_t unix_date = asfreq_MtoDT(ordinal, af_info) + + pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, &dts) + roll_back = af_info.is_end + return DtoB(&dts, roll_back, unix_date) + + +cdef int64_t asfreq_WtoB(int64_t ordinal, asfreq_info *af_info): + cdef: + int roll_back + npy_datetimestruct dts + int64_t unix_date = asfreq_WtoDT(ordinal, af_info) + + pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, &dts) + roll_back = af_info.is_end + return DtoB(&dts, roll_back, unix_date) + + +cdef int64_t asfreq_DTtoB(int64_t ordinal, asfreq_info *af_info): + cdef: + int roll_back + npy_datetimestruct dts + int64_t unix_date = downsample_daytime(ordinal, af_info) + + pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, &dts) + # This usage defines roll_back the opposite way from the others + roll_back = 1 - af_info.is_end + return DtoB(&dts, roll_back, unix_date) + + +# ---------------------------------------------------------------------- +# Conversion _from_ Daily Freq + +cdef int64_t asfreq_DTtoA(int64_t ordinal, asfreq_info *af_info): + cdef: + npy_datetimestruct dts + + ordinal = downsample_daytime(ordinal, af_info) + pandas_datetime_to_datetimestruct(ordinal, NPY_FR_D, &dts) + if dts.month > af_info.to_end: + return (dts.year + 1 - 1970) + else: + return (dts.year - 1970) + + +cdef int DtoQ_yq(int64_t ordinal, asfreq_info *af_info, int *year): + cdef: + npy_datetimestruct dts + int quarter + + pandas_datetime_to_datetimestruct(ordinal, NPY_FR_D, &dts) + # TODO: Another version of this function used + # date_info_from_days_and_time(&dts, unix_date, 0) + # instead of pandas_datetime_to_datetimestruct; is one more performant? + if af_info.to_end != 12: + dts.month -= af_info.to_end + if dts.month <= 0: + dts.month += 12 + else: + dts.year += 1 + + year[0] = dts.year + quarter = month_to_quarter(dts.month) + return quarter + + +cdef int64_t asfreq_DTtoQ(int64_t ordinal, asfreq_info *af_info): + cdef: + int year, quarter + + ordinal = downsample_daytime(ordinal, af_info) + + quarter = DtoQ_yq(ordinal, af_info, &year) + return ((year - 1970) * 4 + quarter - 1) + + +cdef int64_t asfreq_DTtoM(int64_t ordinal, asfreq_info *af_info): + cdef: + npy_datetimestruct dts + + ordinal = downsample_daytime(ordinal, af_info) + pandas_datetime_to_datetimestruct(ordinal, NPY_FR_D, &dts) + return ((dts.year - 1970) * 12 + dts.month - 1) + + +cdef int64_t asfreq_DTtoW(int64_t ordinal, asfreq_info *af_info): + ordinal = downsample_daytime(ordinal, af_info) + return (ordinal + 3 - af_info.to_end) // 7 + 1 + + +# -------------------------------------------------------------------- +# Conversion _from_ BusinessDay Freq + +cdef int64_t asfreq_BtoDT(int64_t ordinal, asfreq_info *af_info): + ordinal = ((ordinal + 3) // 5) * 7 + (ordinal + 3) % 5 -3 + return upsample_daytime(ordinal, af_info) + + +cdef int64_t asfreq_BtoA(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_BtoDT, + asfreq_DTtoA) + + +cdef int64_t asfreq_BtoQ(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_BtoDT, + asfreq_DTtoQ) + + +cdef int64_t asfreq_BtoM(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_BtoDT, + asfreq_DTtoM) + + +cdef int64_t asfreq_BtoW(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_BtoDT, + asfreq_DTtoW) + + +# ---------------------------------------------------------------------- +# Conversion _from_ Annual Freq + +cdef int64_t asfreq_AtoA(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_AtoDT, + asfreq_DTtoA) + + +cdef int64_t asfreq_AtoQ(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_AtoDT, + asfreq_DTtoQ); + + +cdef int64_t asfreq_AtoM(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_AtoDT, + asfreq_DTtoM) + + +cdef int64_t asfreq_AtoW(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_AtoDT, + asfreq_DTtoW) +# ---------------------------------------------------------------------- +# Conversion _from_ Quarterly Freq + +cdef int64_t asfreq_QtoQ(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_QtoDT, + asfreq_DTtoQ) + + +cdef int64_t asfreq_QtoA(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_QtoDT, + asfreq_DTtoA) + + +cdef int64_t asfreq_QtoM(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_QtoDT, + asfreq_DTtoM) + + +cdef int64_t asfreq_QtoW(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_QtoDT, + asfreq_DTtoW) + + +# ---------------------------------------------------------------------- +# Conversion _from_ Monthly Freq + +cdef int64_t asfreq_MtoA(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_MtoDT, + asfreq_DTtoA) + + +cdef int64_t asfreq_MtoQ(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_MtoDT, + asfreq_DTtoQ) + + +cdef int64_t asfreq_MtoW(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_MtoDT, + asfreq_DTtoW) + + +# ---------------------------------------------------------------------- +# Conversion _from_ Weekly Freq + +cdef int64_t asfreq_WtoA(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_WtoDT, + asfreq_DTtoA) + + +cdef int64_t asfreq_WtoQ(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_WtoDT, + asfreq_DTtoQ) + + +cdef int64_t asfreq_WtoM(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_WtoDT, + asfreq_DTtoM) + + +cdef int64_t asfreq_WtoW(int64_t ordinal, asfreq_info *af_info): + return transform_via_day(ordinal, af_info, + asfreq_WtoDT, + asfreq_DTtoW) + + +# ---------------------------------------------------------------------- + @cython.cdivision cdef char* c_strftime(npy_datetimestruct *dts, char *fmt): """ @@ -133,6 +716,23 @@ cdef inline int get_freq_group_index(int freq) nogil: return freq // 1000 +# Find the unix_date (days elapsed since datetime(1970, 1, 1) +# for the given year/month/day. +# Assumes GREGORIAN_CALENDAR */ +cdef int64_t unix_date_from_ymd(int year, int month, int day) nogil: + # Calculate the absolute date + cdef: + npy_datetimestruct dts + int64_t unix_date + + memset(&dts, 0, sizeof(npy_datetimestruct)) + dts.year = year + dts.month = month + dts.day = day + unix_date = npy_datetimestruct_to_datetime(NPY_FR_D, &dts) + return unix_date + + # specifically _dont_ use cdvision or else ordinals near -1 are assigned to # incorrect dates GH#19643 @cython.cdivision(False) @@ -394,25 +994,6 @@ cdef int get_yq(int64_t ordinal, int freq, int *quarter, int *year): return qtr_freq -cdef int DtoQ_yq(int64_t unix_date, asfreq_info *af_info, int *year): - cdef: - npy_datetimestruct dts - int quarter - - date_info_from_days_and_time(&dts, unix_date, 0) - - if af_info.to_end != 12: - dts.month -= af_info.to_end - if dts.month <= 0: - dts.month += 12 - else: - dts.year += 1 - - year[0] = dts.year - quarter = month_to_quarter(dts.month) - return quarter - - cdef inline int month_to_quarter(int month): return (month - 1) // 3 + 1 @@ -1545,7 +2126,7 @@ cdef class _Period(object): See Also -------- Period.year : Return the calendar year of the period. - + Examples -------- If the natural and fiscal year are the same, `qyear` and `year` will diff --git a/pandas/_libs/tslibs/src/period_helper.c b/pandas/_libs/tslibs/src/period_helper.c deleted file mode 100644 index 4bf3774e35a68..0000000000000 --- a/pandas/_libs/tslibs/src/period_helper.c +++ /dev/null @@ -1,603 +0,0 @@ -/* -Copyright (c) 2016, PyData Development Team -All rights reserved. - -Distributed under the terms of the BSD Simplified License. - -The full license is in the LICENSE file, distributed with this software. - -Borrowed and derived code from scikits.timeseries that we will expose via -Cython to pandas. This primarily concerns interval representation and -frequency conversion routines. - -See end of file for stuff pandas uses (search for 'pandas'). -*/ - -#ifndef NPY_NO_DEPRECATED_API -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#endif - -#include "period_helper.h" -#include "datetime/np_datetime.h" - -/* ------------------------------------------------------------------ - * Code derived from scikits.timeseries - * ------------------------------------------------------------------*/ - -static int mod_compat(int x, int m) { - int result = x % m; - if (result < 0) return result + m; - return result; -} - -static int floordiv(int x, int divisor) { - if (x < 0) { - if (mod_compat(x, divisor)) { - return x / divisor - 1; - } else { - return x / divisor; - } - } else { - return x / divisor; - } -} - - -static int monthToQuarter(int month) { return ((month - 1) / 3) + 1; } - - -/* Find the unix_date (days elapsed since datetime(1970, 1, 1) - * for the given year/month/day. - * Assumes GREGORIAN_CALENDAR */ -npy_int64 unix_date_from_ymd(int year, int month, int day) { - /* Calculate the absolute date */ - npy_datetimestruct dts; - npy_int64 unix_date; - - memset(&dts, 0, sizeof(npy_datetimestruct)); - dts.year = year; - dts.month = month; - dts.day = day; - unix_date = npy_datetimestruct_to_datetime(NPY_FR_D, &dts); - return unix_date; -} - - -/////////////////////////////////////////////// - -// frequency specific conversion routines -// each function must take an integer fromDate and -// a char relation ('S' or 'E' for 'START' or 'END') -/////////////////////////////////////////////////////////////////////// - -// helpers for frequency conversion routines // - -static npy_int64 daytime_conversion_factor_matrix[7][7] = { - {1, 24, 1440, 86400, 86400000, 86400000000, 86400000000000}, - {0, 1, 60, 3600, 3600000, 3600000000, 3600000000000}, - {0, 0, 1, 60, 60000, 60000000, 60000000000}, - {0, 0, 0, 1, 1000, 1000000, 1000000000}, - {0, 0, 0, 0, 1, 1000, 1000000}, - {0, 0, 0, 0, 0, 1, 1000}, - {0, 0, 0, 0, 0, 0, 1}}; - -int max_value(int a, int b) { return a > b ? a : b; } - -static int min_value(int a, int b) { return a < b ? a : b; } - -static int get_freq_group(int freq) { return (freq / 1000) * 1000; } - - -npy_int64 get_daytime_conversion_factor(int from_index, int to_index) { - int row = min_value(from_index, to_index); - int col = max_value(from_index, to_index); - // row or col < 6 means frequency strictly lower than Daily, which - // do not use daytime_conversion_factors - if (row < 6) { - return 0; - } else if (col < 6) { - return 0; - } - return daytime_conversion_factor_matrix[row - 6][col - 6]; -} - -static npy_int64 upsample_daytime(npy_int64 ordinal, asfreq_info *af_info) { - if (af_info->is_end) { - return (ordinal + 1) * af_info->intraday_conversion_factor - 1; - } else { - return ordinal * af_info->intraday_conversion_factor; - } -} - -static npy_int64 downsample_daytime(npy_int64 ordinal, asfreq_info *af_info) { - return ordinal / (af_info->intraday_conversion_factor); -} - -static npy_int64 transform_via_day(npy_int64 ordinal, - asfreq_info *af_info, - freq_conv_func first_func, - freq_conv_func second_func) { - npy_int64 result; - - result = (*first_func)(ordinal, af_info); - result = (*second_func)(result, af_info); - - return result; -} - -static npy_int64 DtoB_weekday(npy_int64 unix_date) { - return floordiv(unix_date + 4, 7) * 5 + mod_compat(unix_date + 4, 7) - 4; -} - -static npy_int64 DtoB(npy_datetimestruct *dts, - int roll_back, npy_int64 unix_date) { - int day_of_week = dayofweek(dts->year, dts->month, dts->day); - - if (roll_back == 1) { - if (day_of_week > 4) { - // change to friday before weekend - unix_date -= (day_of_week - 4); - } - } else { - if (day_of_week > 4) { - // change to Monday after weekend - unix_date += (7 - day_of_week); - } - } - return DtoB_weekday(unix_date); -} - - -//************ FROM DAILY *************** - -static npy_int64 asfreq_DTtoA(npy_int64 ordinal, asfreq_info *af_info) { - npy_datetimestruct dts; - ordinal = downsample_daytime(ordinal, af_info); - pandas_datetime_to_datetimestruct(ordinal, NPY_FR_D, &dts); - if (dts.month > af_info->to_end) { - return (npy_int64)(dts.year + 1 - 1970); - } else { - return (npy_int64)(dts.year - 1970); - } -} - -static int DtoQ_yq(npy_int64 ordinal, asfreq_info *af_info, int *year) { - npy_datetimestruct dts; - int quarter; - - pandas_datetime_to_datetimestruct(ordinal, NPY_FR_D, &dts); - if (af_info->to_end != 12) { - dts.month -= af_info->to_end; - if (dts.month <= 0) { - dts.month += 12; - } else { - dts.year += 1; - } - } - - *year = dts.year; - quarter = monthToQuarter(dts.month); - return quarter; -} - -static npy_int64 asfreq_DTtoQ(npy_int64 ordinal, asfreq_info *af_info) { - int year, quarter; - - ordinal = downsample_daytime(ordinal, af_info); - - quarter = DtoQ_yq(ordinal, af_info, &year); - return (npy_int64)((year - 1970) * 4 + quarter - 1); -} - -static npy_int64 asfreq_DTtoM(npy_int64 ordinal, asfreq_info *af_info) { - npy_datetimestruct dts; - - ordinal = downsample_daytime(ordinal, af_info); - - pandas_datetime_to_datetimestruct(ordinal, NPY_FR_D, &dts); - return (npy_int64)((dts.year - 1970) * 12 + dts.month - 1); -} - -static npy_int64 asfreq_DTtoW(npy_int64 ordinal, asfreq_info *af_info) { - ordinal = downsample_daytime(ordinal, af_info); - return floordiv(ordinal + 3 - af_info->to_end, 7) + 1; -} - -static npy_int64 asfreq_DTtoB(npy_int64 ordinal, asfreq_info *af_info) { - int roll_back; - npy_datetimestruct dts; - npy_int64 unix_date = downsample_daytime(ordinal, af_info); - pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, &dts); - - // This usage defines roll_back the opposite way from the others - roll_back = 1 - af_info->is_end; - return DtoB(&dts, roll_back, unix_date); -} - -//************ FROM BUSINESS *************** - -static npy_int64 asfreq_BtoDT(npy_int64 ordinal, asfreq_info *af_info) { - ordinal = floordiv(ordinal + 3, 5) * 7 + mod_compat(ordinal + 3, 5) - 3; - - return upsample_daytime(ordinal, af_info); -} - -static npy_int64 asfreq_BtoA(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_BtoDT, asfreq_DTtoA); -} - -static npy_int64 asfreq_BtoQ(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_BtoDT, asfreq_DTtoQ); -} - -static npy_int64 asfreq_BtoM(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_BtoDT, asfreq_DTtoM); -} - -static npy_int64 asfreq_BtoW(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_BtoDT, asfreq_DTtoW); -} - -//************ FROM WEEKLY *************** - -static npy_int64 asfreq_WtoDT(npy_int64 ordinal, asfreq_info *af_info) { - ordinal = ordinal * 7 + af_info->from_end - 4 + - (7 - 1) * (af_info->is_end - 1); - return upsample_daytime(ordinal, af_info); -} - -static npy_int64 asfreq_WtoA(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_WtoDT, asfreq_DTtoA); -} - -static npy_int64 asfreq_WtoQ(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_WtoDT, asfreq_DTtoQ); -} - -static npy_int64 asfreq_WtoM(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_WtoDT, asfreq_DTtoM); -} - -static npy_int64 asfreq_WtoW(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_WtoDT, asfreq_DTtoW); -} - -static npy_int64 asfreq_WtoB(npy_int64 ordinal, asfreq_info *af_info) { - int roll_back; - npy_datetimestruct dts; - npy_int64 unix_date = asfreq_WtoDT(ordinal, af_info); - - pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, &dts); - roll_back = af_info->is_end; - return DtoB(&dts, roll_back, unix_date); -} - -//************ FROM MONTHLY *************** -static void MtoD_ym(npy_int64 ordinal, int *year, int *month) { - *year = floordiv(ordinal, 12) + 1970; - *month = mod_compat(ordinal, 12) + 1; -} - -static npy_int64 asfreq_MtoDT(npy_int64 ordinal, asfreq_info *af_info) { - npy_int64 unix_date; - int year, month; - - ordinal += af_info->is_end; - MtoD_ym(ordinal, &year, &month); - - unix_date = unix_date_from_ymd(year, month, 1); - unix_date -= af_info->is_end; - return upsample_daytime(unix_date, af_info); -} - -static npy_int64 asfreq_MtoA(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_MtoDT, asfreq_DTtoA); -} - -static npy_int64 asfreq_MtoQ(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_MtoDT, asfreq_DTtoQ); -} - -static npy_int64 asfreq_MtoW(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_MtoDT, asfreq_DTtoW); -} - -static npy_int64 asfreq_MtoB(npy_int64 ordinal, asfreq_info *af_info) { - int roll_back; - npy_datetimestruct dts; - npy_int64 unix_date = asfreq_MtoDT(ordinal, af_info); - - pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, &dts); - roll_back = af_info->is_end; - return DtoB(&dts, roll_back, unix_date); -} - -//************ FROM QUARTERLY *************** - -static void QtoD_ym(npy_int64 ordinal, int *year, int *month, - asfreq_info *af_info) { - *year = floordiv(ordinal, 4) + 1970; - *month = mod_compat(ordinal, 4) * 3 + 1; - - if (af_info->from_end != 12) { - *month += af_info->from_end; - if (*month > 12) { - *month -= 12; - } else { - *year -= 1; - } - } -} - -static npy_int64 asfreq_QtoDT(npy_int64 ordinal, asfreq_info *af_info) { - npy_int64 unix_date; - int year, month; - - ordinal += af_info->is_end; - QtoD_ym(ordinal, &year, &month, af_info); - - unix_date = unix_date_from_ymd(year, month, 1); - unix_date -= af_info->is_end; - return upsample_daytime(unix_date, af_info); -} - -static npy_int64 asfreq_QtoQ(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_QtoDT, asfreq_DTtoQ); -} - -static npy_int64 asfreq_QtoA(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_QtoDT, asfreq_DTtoA); -} - -static npy_int64 asfreq_QtoM(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_QtoDT, asfreq_DTtoM); -} - -static npy_int64 asfreq_QtoW(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_QtoDT, asfreq_DTtoW); -} - -static npy_int64 asfreq_QtoB(npy_int64 ordinal, asfreq_info *af_info) { - int roll_back; - npy_datetimestruct dts; - npy_int64 unix_date = asfreq_QtoDT(ordinal, af_info); - - pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, &dts); - roll_back = af_info->is_end; - return DtoB(&dts, roll_back, unix_date); -} - -//************ FROM ANNUAL *************** - -static void AtoD_ym(npy_int64 ordinal, npy_int64 *year, int *month, - asfreq_info *af_info) { - *year = ordinal + 1970; - *month = 1; - - if (af_info->from_end != 12) { - *month += af_info->from_end; - if (*month > 12) { - // This case is never reached, but is kept for symmetry - // with QtoD_ym - *month -= 12; - } else { - *year -= 1; - } - } -} - -static npy_int64 asfreq_AtoDT(npy_int64 ordinal, asfreq_info *af_info) { - npy_int64 unix_date, year; - int month; - - ordinal += af_info->is_end; - AtoD_ym(ordinal, &year, &month, af_info); - - unix_date = unix_date_from_ymd(year, month, 1); - unix_date -= af_info->is_end; - return upsample_daytime(unix_date, af_info); -} - -static npy_int64 asfreq_AtoA(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_AtoDT, asfreq_DTtoA); -} - -static npy_int64 asfreq_AtoQ(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_AtoDT, asfreq_DTtoQ); -} - -static npy_int64 asfreq_AtoM(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_AtoDT, asfreq_DTtoM); -} - -static npy_int64 asfreq_AtoW(npy_int64 ordinal, asfreq_info *af_info) { - return transform_via_day(ordinal, af_info, asfreq_AtoDT, asfreq_DTtoW); -} - -static npy_int64 asfreq_AtoB(npy_int64 ordinal, asfreq_info *af_info) { - int roll_back; - npy_datetimestruct dts; - npy_int64 unix_date = asfreq_AtoDT(ordinal, af_info); - - pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, &dts); - roll_back = af_info->is_end; - return DtoB(&dts, roll_back, unix_date); -} - -static npy_int64 nofunc(npy_int64 ordinal, asfreq_info *af_info) { - return INT_ERR_CODE; -} -static npy_int64 no_op(npy_int64 ordinal, asfreq_info *af_info) { - return ordinal; -} - -// end of frequency specific conversion routines - -freq_conv_func get_asfreq_func(int fromFreq, int toFreq) { - int fromGroup = get_freq_group(fromFreq); - int toGroup = get_freq_group(toFreq); - - if (fromGroup == FR_UND) { - fromGroup = FR_DAY; - } - - switch (fromGroup) { - case FR_ANN: - switch (toGroup) { - case FR_ANN: - return &asfreq_AtoA; - case FR_QTR: - return &asfreq_AtoQ; - case FR_MTH: - return &asfreq_AtoM; - case FR_WK: - return &asfreq_AtoW; - case FR_BUS: - return &asfreq_AtoB; - case FR_DAY: - case FR_HR: - case FR_MIN: - case FR_SEC: - case FR_MS: - case FR_US: - case FR_NS: - return &asfreq_AtoDT; - - default: - return &nofunc; - } - - case FR_QTR: - switch (toGroup) { - case FR_ANN: - return &asfreq_QtoA; - case FR_QTR: - return &asfreq_QtoQ; - case FR_MTH: - return &asfreq_QtoM; - case FR_WK: - return &asfreq_QtoW; - case FR_BUS: - return &asfreq_QtoB; - case FR_DAY: - case FR_HR: - case FR_MIN: - case FR_SEC: - case FR_MS: - case FR_US: - case FR_NS: - return &asfreq_QtoDT; - default: - return &nofunc; - } - - case FR_MTH: - switch (toGroup) { - case FR_ANN: - return &asfreq_MtoA; - case FR_QTR: - return &asfreq_MtoQ; - case FR_MTH: - return &no_op; - case FR_WK: - return &asfreq_MtoW; - case FR_BUS: - return &asfreq_MtoB; - case FR_DAY: - case FR_HR: - case FR_MIN: - case FR_SEC: - case FR_MS: - case FR_US: - case FR_NS: - return &asfreq_MtoDT; - default: - return &nofunc; - } - - case FR_WK: - switch (toGroup) { - case FR_ANN: - return &asfreq_WtoA; - case FR_QTR: - return &asfreq_WtoQ; - case FR_MTH: - return &asfreq_WtoM; - case FR_WK: - return &asfreq_WtoW; - case FR_BUS: - return &asfreq_WtoB; - case FR_DAY: - case FR_HR: - case FR_MIN: - case FR_SEC: - case FR_MS: - case FR_US: - case FR_NS: - return &asfreq_WtoDT; - default: - return &nofunc; - } - - case FR_BUS: - switch (toGroup) { - case FR_ANN: - return &asfreq_BtoA; - case FR_QTR: - return &asfreq_BtoQ; - case FR_MTH: - return &asfreq_BtoM; - case FR_WK: - return &asfreq_BtoW; - case FR_BUS: - return &no_op; - case FR_DAY: - case FR_HR: - case FR_MIN: - case FR_SEC: - case FR_MS: - case FR_US: - case FR_NS: - return &asfreq_BtoDT; - default: - return &nofunc; - } - - case FR_DAY: - case FR_HR: - case FR_MIN: - case FR_SEC: - case FR_MS: - case FR_US: - case FR_NS: - switch (toGroup) { - case FR_ANN: - return &asfreq_DTtoA; - case FR_QTR: - return &asfreq_DTtoQ; - case FR_MTH: - return &asfreq_DTtoM; - case FR_WK: - return &asfreq_DTtoW; - case FR_BUS: - return &asfreq_DTtoB; - case FR_DAY: - case FR_HR: - case FR_MIN: - case FR_SEC: - case FR_MS: - case FR_US: - case FR_NS: - if (fromGroup > toGroup) { - return &downsample_daytime; - } else { - return &upsample_daytime; - } - default: - return &nofunc; - } - - default: - return &nofunc; - } -} diff --git a/pandas/_libs/tslibs/src/period_helper.h b/pandas/_libs/tslibs/src/period_helper.h deleted file mode 100644 index f0198935bd421..0000000000000 --- a/pandas/_libs/tslibs/src/period_helper.h +++ /dev/null @@ -1,114 +0,0 @@ -/* -Copyright (c) 2016, PyData Development Team -All rights reserved. - -Distributed under the terms of the BSD Simplified License. - -The full license is in the LICENSE file, distributed with this software. - -Borrowed and derived code from scikits.timeseries that we will expose via -Cython to pandas. This primarily concerns interval representation and -frequency conversion routines. -*/ - -#ifndef PANDAS__LIBS_SRC_PERIOD_HELPER_H_ -#define PANDAS__LIBS_SRC_PERIOD_HELPER_H_ - -#ifndef NPY_NO_DEPRECATED_API -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#endif - -#include -#include "limits.h" -#include "numpy/ndarraytypes.h" - -/*** FREQUENCY CONSTANTS ***/ - -#define FR_ANN 1000 /* Annual */ -#define FR_ANNDEC FR_ANN /* Annual - December year end*/ -#define FR_ANNJAN 1001 /* Annual - January year end*/ -#define FR_ANNFEB 1002 /* Annual - February year end*/ -#define FR_ANNMAR 1003 /* Annual - March year end*/ -#define FR_ANNAPR 1004 /* Annual - April year end*/ -#define FR_ANNMAY 1005 /* Annual - May year end*/ -#define FR_ANNJUN 1006 /* Annual - June year end*/ -#define FR_ANNJUL 1007 /* Annual - July year end*/ -#define FR_ANNAUG 1008 /* Annual - August year end*/ -#define FR_ANNSEP 1009 /* Annual - September year end*/ -#define FR_ANNOCT 1010 /* Annual - October year end*/ -#define FR_ANNNOV 1011 /* Annual - November year end*/ - -/* The standard quarterly frequencies with various fiscal year ends - eg, Q42005 for Q@OCT runs Aug 1, 2005 to Oct 31, 2005 */ -#define FR_QTR 2000 /* Quarterly - December year end (default quarterly) */ -#define FR_QTRDEC FR_QTR /* Quarterly - December year end */ -#define FR_QTRJAN 2001 /* Quarterly - January year end */ -#define FR_QTRFEB 2002 /* Quarterly - February year end */ -#define FR_QTRMAR 2003 /* Quarterly - March year end */ -#define FR_QTRAPR 2004 /* Quarterly - April year end */ -#define FR_QTRMAY 2005 /* Quarterly - May year end */ -#define FR_QTRJUN 2006 /* Quarterly - June year end */ -#define FR_QTRJUL 2007 /* Quarterly - July year end */ -#define FR_QTRAUG 2008 /* Quarterly - August year end */ -#define FR_QTRSEP 2009 /* Quarterly - September year end */ -#define FR_QTROCT 2010 /* Quarterly - October year end */ -#define FR_QTRNOV 2011 /* Quarterly - November year end */ - -#define FR_MTH 3000 /* Monthly */ - -#define FR_WK 4000 /* Weekly */ -#define FR_WKSUN FR_WK /* Weekly - Sunday end of week */ -#define FR_WKMON 4001 /* Weekly - Monday end of week */ -#define FR_WKTUE 4002 /* Weekly - Tuesday end of week */ -#define FR_WKWED 4003 /* Weekly - Wednesday end of week */ -#define FR_WKTHU 4004 /* Weekly - Thursday end of week */ -#define FR_WKFRI 4005 /* Weekly - Friday end of week */ -#define FR_WKSAT 4006 /* Weekly - Saturday end of week */ - -#define FR_BUS 5000 /* Business days */ -#define FR_DAY 6000 /* Daily */ -#define FR_HR 7000 /* Hourly */ -#define FR_MIN 8000 /* Minutely */ -#define FR_SEC 9000 /* Secondly */ -#define FR_MS 10000 /* Millisecondly */ -#define FR_US 11000 /* Microsecondly */ -#define FR_NS 12000 /* Nanosecondly */ - -#define FR_UND -10000 /* Undefined */ - -#define INT_ERR_CODE NPY_MIN_INT32 - -typedef struct asfreq_info { - int is_end; - // char relation == 'S' (for START) --> is_end = 0 - // char relation == 'E' (for END) --> is_end = 1 - - int from_end; - int to_end; - // weekly: - // from_end --> day the week ends on in the "from" frequency - // to_end --> day the week ends on in the "to" frequency - // - // annual: - // from_end --> month the year ends on in the "from" frequency - // to_end --> month the year ends on in the "to" frequency - // - // quarterly: - // from_end --> month the year ends on in the "from" frequency - // to_end --> month the year ends on in the "to" frequency - - npy_int64 intraday_conversion_factor; -} asfreq_info; - -typedef npy_int64 (*freq_conv_func)(npy_int64, asfreq_info *af_info); - -/* - * new pandas API helper functions here - */ - -freq_conv_func get_asfreq_func(int fromFreq, int toFreq); - -npy_int64 get_daytime_conversion_factor(int from_index, int to_index); -int max_value(int a, int b); - -#endif // PANDAS__LIBS_SRC_PERIOD_HELPER_H_ diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 9e7f1d94934ba..8b8475cc3727b 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -162,7 +162,7 @@ cpdef convert_to_timedelta64(object ts, object unit): if ts.astype('int64') == NPY_NAT: return np.timedelta64(NPY_NAT) elif is_timedelta64_object(ts): - ts = ts.astype("m8[{0}]".format(unit.lower())) + ts = ts.astype("m8[{unit}]".format(unit=unit.lower())) elif is_integer_object(ts): if ts == NPY_NAT: return np.timedelta64(NPY_NAT) @@ -265,7 +265,7 @@ cpdef inline int64_t cast_from_unit(object ts, object unit) except? -1: m = 1L p = 0 else: - raise ValueError("cannot cast unit {0}".format(unit)) + raise ValueError("cannot cast unit {unit}".format(unit=unit)) # just give me the unit back if ts is None: @@ -273,11 +273,11 @@ cpdef inline int64_t cast_from_unit(object ts, object unit) except? -1: # cast the unit, multiply base/frace separately # to avoid precision issues from float -> int - base = ts + base = ts frac = ts - base if p: frac = round(frac, p) - return (base * m) + (frac * m) + return (base * m) + (frac * m) cdef inline _decode_if_necessary(object ts): @@ -296,10 +296,10 @@ cdef inline parse_timedelta_string(object ts): cdef: unicode c - bint neg=0, have_dot=0, have_value=0, have_hhmmss=0 - object current_unit=None - int64_t result=0, m=0, r - list number=[], frac=[], unit=[] + bint neg = 0, have_dot = 0, have_value = 0, have_hhmmss = 0 + object current_unit = None + int64_t result = 0, m = 0, r + list number = [], frac = [], unit = [] # neg : tracks if we have a leading negative for the value # have_dot : tracks if we are processing a dot (either post hhmmss or @@ -374,7 +374,7 @@ cdef inline parse_timedelta_string(object ts): have_hhmmss = 1 else: raise ValueError("expecting hh:mm:ss format, " - "received: {0}".format(ts)) + "received: {ts}".format(ts=ts)) unit, number = [], [] @@ -483,7 +483,7 @@ cdef inline timedelta_from_spec(object number, object frac, object unit): unit = ''.join(unit) unit = timedelta_abbrevs[unit.lower()] except KeyError: - raise ValueError("invalid abbreviation: {0}".format(unit)) + raise ValueError("invalid abbreviation: {unit}".format(unit=unit)) n = ''.join(number) + '.' + ''.join(frac) return cast_from_unit(float(n), unit) @@ -592,10 +592,10 @@ cdef inline int64_t parse_iso_format_string(object ts) except? -1: cdef: unicode c int64_t result = 0, r - int p=0 + int p = 0 object dec_unit = 'ms', err_msg - bint have_dot=0, have_value=0, neg=0 - list number=[], unit=[] + bint have_dot = 0, have_value = 0, neg = 0 + list number = [], unit = [] ts = _decode_if_necessary(ts) @@ -682,8 +682,8 @@ cdef _to_py_int_float(v): return int(v) elif is_float_object(v): return float(v) - raise TypeError("Invalid type {0}. Must be int or " - "float.".format(type(v))) + raise TypeError("Invalid type {typ}. Must be int or " + "float.".format(typ=type(v))) # Similar to Timestamp/datetime, this is a construction requirement for @@ -729,9 +729,10 @@ cdef class _Timedelta(timedelta): return True # only allow ==, != ops - raise TypeError('Cannot compare type {!r} with type ' \ - '{!r}'.format(type(self).__name__, - type(other).__name__)) + raise TypeError('Cannot compare type {cls} with ' + 'type {other}' + .format(cls=type(self).__name__, + other=type(other).__name__)) if util.is_array(other): return PyObject_RichCompare(np.array([self]), other, op) return PyObject_RichCompare(other, self, reverse_ops[op]) @@ -740,9 +741,9 @@ cdef class _Timedelta(timedelta): return False elif op == Py_NE: return True - raise TypeError('Cannot compare type {!r} with type ' \ - '{!r}'.format(type(self).__name__, - type(other).__name__)) + raise TypeError('Cannot compare type {cls} with type {other}' + .format(cls=type(self).__name__, + other=type(other).__name__)) return cmp_scalar(self.value, ots.value, op) @@ -980,8 +981,8 @@ cdef class _Timedelta(timedelta): sign = " " if format == 'all': - fmt = "{days} days{sign}{hours:02}:{minutes:02}:{seconds:02}." \ - "{milliseconds:03}{microseconds:03}{nanoseconds:03}" + fmt = ("{days} days{sign}{hours:02}:{minutes:02}:{seconds:02}." + "{milliseconds:03}{microseconds:03}{nanoseconds:03}") else: # if we have a partial day subs = (self._h or self._m or self._s or @@ -1006,7 +1007,7 @@ cdef class _Timedelta(timedelta): return fmt.format(**comp_dict) def __repr__(self): - return "Timedelta('{0}')".format(self._repr_base(format='long')) + return "Timedelta('{val}')".format(val=self._repr_base(format='long')) def __str__(self): return self._repr_base(format='long') @@ -1060,8 +1061,8 @@ cdef class _Timedelta(timedelta): components.nanoseconds) # Trim unnecessary 0s, 1.000000000 -> 1 seconds = seconds.rstrip('0').rstrip('.') - tpl = 'P{td.days}DT{td.hours}H{td.minutes}M{seconds}S'.format( - td=components, seconds=seconds) + tpl = ('P{td.days}DT{td.hours}H{td.minutes}M{seconds}S' + .format(td=components, seconds=seconds)) return tpl diff --git a/setup.py b/setup.py index 3289f1e99b87f..4fdfc0ab7de0d 100755 --- a/setup.py +++ b/setup.py @@ -234,7 +234,6 @@ def initialize_options(self): ujson_lib = pjoin(base, 'ujson', 'lib') self._clean_exclude = [pjoin(dt, 'np_datetime.c'), pjoin(dt, 'np_datetime_strings.c'), - pjoin(tsbase, 'period_helper.c'), pjoin(parser, 'tokenizer.c'), pjoin(parser, 'io.c'), pjoin(ujson_python, 'ujson.c'), @@ -616,10 +615,8 @@ def srcpath(name=None, suffix='.pyx', subdir='src'): '_libs.tslibs.period': { 'pyxfile': '_libs/tslibs/period', 'include': ts_include, - 'depends': tseries_depends + [ - 'pandas/_libs/tslibs/src/period_helper.h'], - 'sources': np_datetime_sources + [ - 'pandas/_libs/tslibs/src/period_helper.c']}, + 'depends': tseries_depends, + 'sources': np_datetime_sources}, '_libs.tslibs.resolution': { 'pyxfile': '_libs/tslibs/resolution', 'include': ts_include, From fcea3d6751f508dbca5f4821c865b6c7206e37a4 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Sat, 4 Aug 2018 17:29:44 -0700 Subject: [PATCH 2/6] flake8 fixups --- pandas/_libs/tslibs/period.pyx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index 4adf74fe5e459..a8d19ef0ed52b 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -84,7 +84,7 @@ cdef extern from *: /* The standard quarterly frequencies with various fiscal year ends eg, Q42005 for Q@OCT runs Aug 1, 2005 to Oct 31, 2005 */ - #define FR_QTR 2000 /* Quarterly - December year end (default quarterly) */ + #define FR_QTR 2000 /* Quarterly - December year end (default Q) */ #define FR_QTRDEC FR_QTR /* Quarterly - December year end */ #define FR_QTRJAN 2001 /* Quarterly - January year end */ #define FR_QTRFEB 2002 /* Quarterly - February year end */ @@ -204,7 +204,8 @@ cdef freq_conv_func get_asfreq_func(int from_freq, int to_freq) nogil: return asfreq_MtoB elif from_group == FR_WK: return asfreq_WtoB - elif from_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, FR_MS, FR_US, FR_NS]: + elif from_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, + FR_MS, FR_US, FR_NS]: return asfreq_DTtoB else: return nofunc From 85bf08123da81f26af58dfc3d84a750c5296dfc8 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Sat, 4 Aug 2018 17:31:48 -0700 Subject: [PATCH 3/6] update lint.sh --- ci/lint.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ci/lint.sh b/ci/lint.sh index ec99e1e559d6e..432be8f78aca6 100755 --- a/ci/lint.sh +++ b/ci/lint.sh @@ -93,7 +93,7 @@ if [ "$LINT" ]; then # this particular codebase (e.g. src/headers, src/klib, src/msgpack). However, # we can lint all header files since they aren't "generated" like C files are. echo "Linting *.c and *.h" - for path in '*.h' 'period_helper.c' 'datetime' 'parser' 'ujson' + for path in '*.h' 'parser' 'ujson' do echo "linting -> pandas/_libs/src/$path" cpplint --quiet --extensions=c,h --headers=h --filter=-readability/casting,-runtime/int,-build/include_subdir --recursive pandas/_libs/src/$path @@ -101,6 +101,11 @@ if [ "$LINT" ]; then RET=1 fi done + echo "linting -> pandas/_libs/tslibs/src/datetime" + cpplint --quiet --extensions=c,h --headers=h --filter=-readability/casting,-runtime/int,-build/include_subdir --recursive pandas/_libs/tslibs/src/datetime + if [ $? -ne "0" ]; then + RET=1 + fi echo "Linting *.c and *.h DONE" echo "Check for invalid testing" From cd6cc9bbdf9fd3be5b5fd09fb032e6deee34c9bb Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Sat, 4 Aug 2018 18:48:17 -0700 Subject: [PATCH 4/6] flake8 fixup --- pandas/_libs/tslibs/period.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index a8d19ef0ed52b..a880259c19140 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -271,9 +271,9 @@ cdef freq_conv_func get_asfreq_func(int from_freq, int to_freq) nogil: return asfreq_DTtoA elif to_group == FR_QTR: return asfreq_DTtoQ - elif to_group == FR_MTH: + elif to_group == FR_MTH: return asfreq_DTtoM - elif to_group == FR_WK: + elif to_group == FR_WK: return asfreq_DTtoW elif to_group in [FR_DAY, FR_HR, FR_MIN, FR_SEC, FR_MS, FR_US, FR_NS]: if from_group > to_group: From 1bb05fb1a5c963b05b74e82b97cbf2ad9f7bea76 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Sat, 4 Aug 2018 18:49:35 -0700 Subject: [PATCH 5/6] cpplint fixups... i hope --- pandas/_libs/tslibs/src/datetime/np_datetime.c | 2 +- pandas/_libs/tslibs/src/datetime/np_datetime.h | 2 +- pandas/_libs/tslibs/src/datetime/np_datetime_strings.c | 2 +- pandas/_libs/tslibs/src/datetime/np_datetime_strings.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/src/datetime/np_datetime.c b/pandas/_libs/tslibs/src/datetime/np_datetime.c index 1b33f38441253..659afd152106d 100644 --- a/pandas/_libs/tslibs/src/datetime/np_datetime.c +++ b/pandas/_libs/tslibs/src/datetime/np_datetime.c @@ -18,7 +18,7 @@ This file is derived from NumPy 1.7. See NUMPY_LICENSE.txt #ifndef NPY_NO_DEPRECATED_API #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#endif +#endif // NPY_NO_DEPRECATED_API #include #include diff --git a/pandas/_libs/tslibs/src/datetime/np_datetime.h b/pandas/_libs/tslibs/src/datetime/np_datetime.h index 9fa85b18dd219..cb264696facba 100644 --- a/pandas/_libs/tslibs/src/datetime/np_datetime.h +++ b/pandas/_libs/tslibs/src/datetime/np_datetime.h @@ -19,7 +19,7 @@ This file is derived from NumPy 1.7. See NUMPY_LICENSE.txt #ifndef NPY_NO_DEPRECATED_API #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#endif +#endif // NPY_NO_DEPRECATED_API #include #include diff --git a/pandas/_libs/tslibs/src/datetime/np_datetime_strings.c b/pandas/_libs/tslibs/src/datetime/np_datetime_strings.c index 19ade6fa5add9..05ccdd13598fb 100644 --- a/pandas/_libs/tslibs/src/datetime/np_datetime_strings.c +++ b/pandas/_libs/tslibs/src/datetime/np_datetime_strings.c @@ -24,7 +24,7 @@ This file implements string parsing and creation for NumPy datetime. #ifndef NPY_NO_DEPRECATED_API #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#endif +#endif // NPY_NO_DEPRECATED_API #include diff --git a/pandas/_libs/tslibs/src/datetime/np_datetime_strings.h b/pandas/_libs/tslibs/src/datetime/np_datetime_strings.h index e9a7fd74b05e5..c753c9839dc8d 100644 --- a/pandas/_libs/tslibs/src/datetime/np_datetime_strings.h +++ b/pandas/_libs/tslibs/src/datetime/np_datetime_strings.h @@ -24,7 +24,7 @@ This file implements string parsing and creation for NumPy datetime. #ifndef NPY_NO_DEPRECATED_API #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#endif +#endif // NPY_NO_DEPRECATED_API /* * Parses (almost) standard ISO 8601 date strings. The differences are: From 48e273bbb065082cd9dfa86139de8a6489c517d0 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Sat, 4 Aug 2018 19:50:35 -0700 Subject: [PATCH 6/6] cpplint fixup --- pandas/_libs/tslibs/src/datetime/np_datetime.h | 6 +++--- pandas/_libs/tslibs/src/datetime/np_datetime_strings.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pandas/_libs/tslibs/src/datetime/np_datetime.h b/pandas/_libs/tslibs/src/datetime/np_datetime.h index cb264696facba..3974d5083f51b 100644 --- a/pandas/_libs/tslibs/src/datetime/np_datetime.h +++ b/pandas/_libs/tslibs/src/datetime/np_datetime.h @@ -14,8 +14,8 @@ This file is derived from NumPy 1.7. See NUMPY_LICENSE.txt */ -#ifndef PANDAS__LIBS_SRC_DATETIME_NP_DATETIME_H_ -#define PANDAS__LIBS_SRC_DATETIME_NP_DATETIME_H_ +#ifndef PANDAS__LIBS_TSLIBS_SRC_DATETIME_NP_DATETIME_H_ +#define PANDAS__LIBS_TSLIBS_SRC_DATETIME_NP_DATETIME_H_ #ifndef NPY_NO_DEPRECATED_API #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION @@ -79,4 +79,4 @@ void add_minutes_to_datetimestruct(npy_datetimestruct *dts, int minutes); -#endif // PANDAS__LIBS_SRC_DATETIME_NP_DATETIME_H_ +#endif // PANDAS__LIBS_TSLIBS_SRC_DATETIME_NP_DATETIME_H_ diff --git a/pandas/_libs/tslibs/src/datetime/np_datetime_strings.h b/pandas/_libs/tslibs/src/datetime/np_datetime_strings.h index c753c9839dc8d..15d5dd357eaef 100644 --- a/pandas/_libs/tslibs/src/datetime/np_datetime_strings.h +++ b/pandas/_libs/tslibs/src/datetime/np_datetime_strings.h @@ -19,8 +19,8 @@ This file implements string parsing and creation for NumPy datetime. */ -#ifndef PANDAS__LIBS_SRC_DATETIME_NP_DATETIME_STRINGS_H_ -#define PANDAS__LIBS_SRC_DATETIME_NP_DATETIME_STRINGS_H_ +#ifndef PANDAS__LIBS_TSLIBS_SRC_DATETIME_NP_DATETIME_STRINGS_H_ +#define PANDAS__LIBS_TSLIBS_SRC_DATETIME_NP_DATETIME_STRINGS_H_ #ifndef NPY_NO_DEPRECATED_API #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION @@ -80,4 +80,4 @@ int make_iso_8601_datetime(npy_datetimestruct *dts, char *outstr, int outlen, NPY_DATETIMEUNIT base); -#endif // PANDAS__LIBS_SRC_DATETIME_NP_DATETIME_STRINGS_H_ +#endif // PANDAS__LIBS_TSLIBS_SRC_DATETIME_NP_DATETIME_STRINGS_H_