diff --git a/pandas/src/datetime.pxd b/pandas/src/datetime.pxd index 1a977aab48514..9ae116b06c3b2 100644 --- a/pandas/src/datetime.pxd +++ b/pandas/src/datetime.pxd @@ -1,7 +1,5 @@ -from numpy cimport int64_t, int32_t, npy_int64, npy_int32, ndarray -from cpython cimport PyObject - -from cpython cimport PyUnicode_Check, PyUnicode_AsASCIIString +from numpy cimport int64_t as i8, int32_t as i4 +from cpython cimport PyObject, PyUnicode_Check, PyUnicode_AsASCIIString cdef extern from "headers/stdint.h": @@ -9,7 +7,6 @@ cdef extern from "headers/stdint.h": enum: INT32_MIN - cdef extern from "datetime.h": ctypedef class datetime.date [object PyDateTime_Date]: @@ -45,8 +42,8 @@ cdef extern from "datetime_helper.h": cdef extern from "numpy/ndarrayobject.h": - ctypedef int64_t npy_timedelta - ctypedef int64_t npy_datetime + ctypedef i8 npy_timedelta + ctypedef i8 npy_datetime ctypedef enum NPY_CASTING: NPY_NO_CASTING @@ -82,8 +79,7 @@ cdef extern from "datetime/np_datetime.h": PANDAS_FR_as ctypedef struct pandas_datetimestruct: - npy_int64 year - npy_int32 month, day, hour, min, sec, us, ps, as + i8 year, month, day, hour, min, sec, us, ps, as int convert_pydatetime_to_datetimestruct(PyObject *obj, pandas_datetimestruct *out, @@ -98,7 +94,7 @@ cdef extern from "datetime/np_datetime.h": int days_per_month_table[2][12] int dayofweek(int y, int m, int d) - int is_leapyear(int64_t year) + int is_leapyear(i8 year) PANDAS_DATETIMEUNIT get_datetime64_unit(object o) cdef extern from "datetime/np_datetime_strings.h": @@ -145,7 +141,7 @@ cdef inline int _cstring_to_dts(char *val, int length, return result -cdef inline object _datetime64_to_datetime(int64_t val): +cdef inline object _datetime64_to_datetime(i8 val): cdef pandas_datetimestruct dts pandas_datetime_to_datetimestruct(val, PANDAS_FR_ns, &dts) return _dts_to_pydatetime(&dts) @@ -155,7 +151,7 @@ cdef inline object _dts_to_pydatetime(pandas_datetimestruct *dts): dts.day, dts.hour, dts.min, dts.sec, dts.us) -cdef inline int64_t _pydatetime_to_dts(object val, pandas_datetimestruct *dts): +cdef inline i8 _pydatetime_to_dts(object val, pandas_datetimestruct *dts): dts.year = PyDateTime_GET_YEAR(val) dts.month = PyDateTime_GET_MONTH(val) dts.day = PyDateTime_GET_DAY(val) @@ -166,8 +162,7 @@ cdef inline int64_t _pydatetime_to_dts(object val, pandas_datetimestruct *dts): dts.ps = dts.as = 0 return pandas_datetimestruct_to_datetime(PANDAS_FR_ns, dts) -cdef inline int64_t _dtlike_to_datetime64(object val, - pandas_datetimestruct *dts): +cdef inline i8 _dtlike_to_datetime64(object val, pandas_datetimestruct *dts): dts.year = val.year dts.month = val.month dts.day = val.day @@ -178,12 +173,10 @@ cdef inline int64_t _dtlike_to_datetime64(object val, dts.ps = dts.as = 0 return pandas_datetimestruct_to_datetime(PANDAS_FR_ns, dts) -cdef inline int64_t _date_to_datetime64(object val, - pandas_datetimestruct *dts): +cdef inline i8 _date_to_datetime64(object val, pandas_datetimestruct *dts): dts.year = PyDateTime_GET_YEAR(val) dts.month = PyDateTime_GET_MONTH(val) dts.day = PyDateTime_GET_DAY(val) dts.hour = dts.min = dts.sec = dts.us = 0 dts.ps = dts.as = 0 return pandas_datetimestruct_to_datetime(PANDAS_FR_ns, dts) - diff --git a/pandas/src/period.c b/pandas/src/period.c index 4e7ab44c7b150..72819a54d34da 100644 --- a/pandas/src/period.c +++ b/pandas/src/period.c @@ -13,62 +13,68 @@ * Code derived from scikits.timeseries * ------------------------------------------------------------------*/ +#include -static int mod_compat(int x, int m) { - int result = x % m; - if (result < 0) return result + m; - return result; +static i8 +mod_compat(i8 x, i8 m) +{ + i8 result = x % m; + + if (result < 0) + 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 i8 +floordiv(i8 x, i8 divisor) +{ + i8 x_div_d = x / divisor; + + if (x < 0 && mod_compat(x, divisor)) + --x_div_d; + + return x_div_d; } static asfreq_info NULL_AF_INFO; /* Table with day offsets for each month (0-based, without and with leap) */ -static int month_offset[2][13] = { +static i8 month_offset[2][13] = { { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; /* Table of number of days in a month (0-based, without and with leap) */ -static int days_in_month[2][12] = { +static i8 days_in_month[2][12] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; /* Return 1/0 iff year points to a leap year in calendar. */ -static int dInfoCalc_Leapyear(npy_int64 year, int calendar) +static bool +dInfoCalc_Leapyear(i8 year, enum CalendarType calendar) { - if (calendar == GREGORIAN_CALENDAR) { - return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); - } else { - return (year % 4 == 0); - } + bool ymod4_is0 = year % 4 == 0; + + if (calendar == GREGORIAN) + return ymod4_is0 && (year % 100 != 0 || year % 400 == 0); + + return ymod4_is0; } /* Return the day of the week for the given absolute date. */ -static int dInfoCalc_DayOfWeek(npy_int64 absdate) +static i8 +dInfoCalc_DayOfWeek(i8 absdate) { - int day_of_week; - - if (absdate >= 1) { - day_of_week = (absdate - 1) % 7; - } else { - day_of_week = 6 - ((-absdate) % 7); - } - return day_of_week; + return absdate >= 1 ? (absdate - 1) % 7 : 6 - (-absdate % 7); } -static int monthToQuarter(int month) { return ((month-1)/3)+1; } +static i8 +monthToQuarter(i8 month) +{ + return (month - 1) / 3 + 1; +} /* Return the year offset, that is the absolute date of the day 31.12.(year-1) in the given calendar. @@ -78,66 +84,74 @@ static int monthToQuarter(int month) { return ((month-1)/3)+1; } using the Gregorian Epoch) value by two days because the Epoch (0001-01-01) in the Julian calendar lies 2 days before the Epoch in the Gregorian calendar. */ -static int dInfoCalc_YearOffset(npy_int64 year, int calendar) +static i8 +dInfoCalc_YearOffset(i8 yr, enum CalendarType calendar) { - year--; - if (calendar == GREGORIAN_CALENDAR) { - if (year >= 0 || -1/4 == -1) - return year*365 + year/4 - year/100 + year/400; - else - return year*365 + (year-3)/4 - (year-99)/100 + (year-399)/400; - } - else if (calendar == JULIAN_CALENDAR) { - if (year >= 0 || -1/4 == -1) - return year*365 + year/4 - 2; + i8 year = yr; + --year; + + if (calendar == GREGORIAN) + if (year >= 0 || -1 / 4 == -1) + return year * 365 + year / 4 - year / 100 + year / 400; + else + return year * 365 + (year - 3) / 4 - (year - 99) / 100 + + (year - 399) / 400; + else if (calendar == JULIAN) + if (year >= 0 || -1 / 4 == -1) + return year * 365 + year / 4 - 2; + else + return year * 365 + (year - 3) / 4 - 2; else - return year*365 + (year-3)/4 - 2; - } - Py_Error(PyExc_ValueError, "unknown calendar"); - onError: + Py_Error(PyExc_ValueError, "unknown calendar"); +onError: return INT_ERR_CODE; } /* Set the instance's value using the given date and time. calendar may be set - * to the flags: GREGORIAN_CALENDAR, JULIAN_CALENDAR to indicate the calendar + * to the flags: GREGORIAN, JULIAN to indicate the calendar * to be used. */ -static int dInfoCalc_SetFromDateAndTime(struct date_info *dinfo, - int year, int month, int day, int hour, int minute, double second, - int calendar) +static i8 +dInfoCalc_SetFromDateAndTime(date_info *dinfo, i8 year, i8 month, i8 day, + i8 hour, i8 minute, i8 second, i8 microsecond, + enum CalendarType calendar) { /* Calculate the absolute date */ { - int leap; - npy_int64 absdate; - int yearoffset; + i8 leap, absdate, yearoffset; /* Range check */ Py_AssertWithArg(year > -(INT_MAX / 366) && year < (INT_MAX / 366), - PyExc_ValueError, - "year out of range: %i", - year); + PyExc_ValueError, + "year out of range: %li", + year); /* Is it a leap year ? */ leap = dInfoCalc_Leapyear(year, calendar); /* Negative month values indicate months relative to the years end */ - if (month < 0) month += 13; + if (month < 0) + month += 13; + Py_AssertWithArg(month >= 1 && month <= 12, - PyExc_ValueError, - "month out of range (1-12): %i", - month); + PyExc_ValueError, + "month out of range (1-12): %li", + month); /* Negative values indicate days relative to the months end */ - if (day < 0) day += days_in_month[leap][month - 1] + 1; + if (day < 0) + day += days_in_month[leap][month - 1] + 1; + Py_AssertWithArg(day >= 1 && day <= days_in_month[leap][month - 1], - PyExc_ValueError, - "day out of range: %i", - day); + PyExc_ValueError, + "day out of range: %li", + day); yearoffset = dInfoCalc_YearOffset(year, calendar); - if (PyErr_Occurred()) goto onError; + + if (PyErr_Occurred()) + goto onError; absdate = day + month_offset[leap][month - 1] + yearoffset; @@ -145,11 +159,11 @@ static int dInfoCalc_SetFromDateAndTime(struct date_info *dinfo, dinfo->year = year; dinfo->month = month; - dinfo->quarter = ((month-1)/3)+1; + dinfo->quarter = (month - 1) / 3 + 1; dinfo->day = day; dinfo->day_of_week = dInfoCalc_DayOfWeek(absdate); - dinfo->day_of_year = (short)(absdate - yearoffset); + dinfo->day_of_year = absdate - yearoffset; dinfo->calendar = calendar; } @@ -157,60 +171,74 @@ static int dInfoCalc_SetFromDateAndTime(struct date_info *dinfo, /* Calculate the absolute time */ { Py_AssertWithArg(hour >= 0 && hour <= 23, - PyExc_ValueError, - "hour out of range (0-23): %i", - hour); + PyExc_ValueError, + "hour out of range (0-23): %li", + hour); Py_AssertWithArg(minute >= 0 && minute <= 59, - PyExc_ValueError, - "minute out of range (0-59): %i", - minute); - Py_AssertWithArg(second >= (double)0.0 && - (second < (double)60.0 || - (hour == 23 && minute == 59 && - second < (double)61.0)), - PyExc_ValueError, - "second out of range (0.0 - <60.0; <61.0 for 23:59): %f", - second); - - dinfo->abstime = (double)(hour*3600 + minute*60) + second; + PyExc_ValueError, + "minute out of range (0-59): %li", + minute); + Py_AssertWithArg(second >= 0 && + (second < 60L || (hour == 23 && minute == 59 && + second < 61)), + PyExc_ValueError, + "second out of range (0 - <60L; <61 for 23:59): %li", + second); + Py_AssertWithArg(microsecond >= 0 && (microsecond < 1000000 || + (hour == 23 && minute == 59 && + second < 61 && + microsecond < 1000001)), + PyExc_ValueError, + "microsecond out of range (0 - <100000; <100001 for 23:59:59): %li", + microsecond); + + dinfo->abstime = hour * US_PER_HOUR + minute * US_PER_MINUTE + + second * US_PER_SECOND + microsecond; dinfo->hour = hour; dinfo->minute = minute; dinfo->second = second; + dinfo->microsecond = microsecond; } + return 0; - onError: +onError: return INT_ERR_CODE; } /* Sets the date part of the date_info struct using the indicated calendar. - XXX This could also be done using some integer arithmetics rather - than with this iterative approach... */ -static -int dInfoCalc_SetFromAbsDate(register struct date_info *dinfo, - npy_int64 absdate, int calendar) + XXX This could also be done using some i8eger arithmetics rather + than with this iterative approach... */ +static i8 +dInfoCalc_SetFromAbsDate(register date_info *dinfo, i8 absdate, + enum CalendarType calendar) { - register npy_int64 year; - npy_int64 yearoffset; - int leap,dayoffset; - int *monthoffset; + register i8 year; + i8 yearoffset, leap, dayoffset, *monthoffset = NULL; + /* Approximate year */ - if (calendar == GREGORIAN_CALENDAR) { - year = (npy_int64)(((double)absdate) / 365.2425); - } else if (calendar == JULIAN_CALENDAR) { - year = (npy_int64)(((double)absdate) / 365.25); - } else { + switch (calendar) { + case GREGORIAN: + year = absdate / 365.2425; + break; + case JULIAN: + year = absdate / 365.25; + break; + default: Py_Error(PyExc_ValueError, "unknown calendar"); + break; } - if (absdate > 0) year++; + if (absdate > 0) + ++year; /* Apply corrections to reach the correct year */ while (1) { + /* Calculate the year offset */ yearoffset = dInfoCalc_YearOffset(year, calendar); if (PyErr_Occurred()) @@ -219,7 +247,7 @@ int dInfoCalc_SetFromAbsDate(register struct date_info *dinfo, /* Backward correction: absdate must be greater than the yearoffset */ if (yearoffset >= absdate) { - year--; + --year; continue; } @@ -228,9 +256,10 @@ int dInfoCalc_SetFromAbsDate(register struct date_info *dinfo, /* Forward correction: non leap years only have 365 days */ if (dayoffset > 365 && !leap) { - year++; + ++year; continue; } + break; } @@ -240,12 +269,11 @@ int dInfoCalc_SetFromAbsDate(register struct date_info *dinfo, /* Now iterate to find the month */ monthoffset = month_offset[leap]; { - register int month; + register i8 month; - for (month = 1; month < 13; month++) { + for (month = 1; month < 13; ++month) if (monthoffset[month] >= dayoffset) - break; - } + break; dinfo->month = month; dinfo->quarter = monthToQuarter(month); @@ -259,71 +287,88 @@ int dInfoCalc_SetFromAbsDate(register struct date_info *dinfo, return 0; - onError: +onError: return INT_ERR_CODE; } /////////////////////////////////////////////// // frequency specifc conversion routines -// each function must take an integer fromDate and +// each function must take an i8eger fromDate and // a char relation ('S' or 'E' for 'START' or 'END') /////////////////////////////////////////////////////////////////////// // helpers for frequency conversion routines // -static npy_int64 DtoB_weekday(npy_int64 absdate) { - return (((absdate) / 7) * 5) + (absdate) % 7 - BDAY_OFFSET; +static i8 +DtoB_weekday(i8 absdate) +{ + return (absdate / 7) * 5 + absdate % 7 - BDAY_OFFSET; } -static npy_int64 DtoB_WeekendToMonday(npy_int64 absdate, int day_of_week) { - if (day_of_week > 4) { - //change to Monday after weekend - absdate += (7 - day_of_week); - } +static i8 +DtoB_WeekendToMonday(i8 absdate, i8 day_of_week) +{ + if (day_of_week > 4) + // change to Monday after weekend + absdate += 7 - day_of_week; + return DtoB_weekday(absdate); } -static npy_int64 DtoB_WeekendToFriday(npy_int64 absdate, int day_of_week) { - if (day_of_week > 4) { - //change to friday before weekend - absdate -= (day_of_week - 4); - } +static i8 +DtoB_WeekendToFriday(i8 absdate, i8 day_of_week) +{ + if (day_of_week > 4) + // change to friday before weekend + absdate -= day_of_week - 4; + return DtoB_weekday(absdate); } -static npy_int64 absdate_from_ymd(int y, int m, int d) { - struct date_info tempDate; - if (dInfoCalc_SetFromDateAndTime(&tempDate, y, m, d, 0, 0, 0, GREGORIAN_CALENDAR)) { +static i8 +absdate_from_ymd(i8 y, i8 m, i8 d) +{ + date_info td; + + if (dInfoCalc_SetFromDateAndTime(&td, y, m, d, 0, 0, 0, 0, GREGORIAN)) return INT_ERR_CODE; - } - return tempDate.absdate; + + return td.absdate; } //************ FROM DAILY *************** -static npy_int64 asfreq_DtoA(npy_int64 ordinal, char relation, asfreq_info *af_info) { +static i8 +asfreq_DtoA(i8 ordinal, const char *relation, asfreq_info *af_info) +{ + date_info dinfo; - struct date_info dinfo; - if (dInfoCalc_SetFromAbsDate(&dinfo, ordinal + ORD_OFFSET, - GREGORIAN_CALENDAR)) return INT_ERR_CODE; - if (dinfo.month > af_info->to_a_year_end) { - return (npy_int64)(dinfo.year + 1 - BASE_YEAR); - } - else { - return (npy_int64)(dinfo.year - BASE_YEAR); - } + if (dInfoCalc_SetFromAbsDate(&dinfo, ordinal + ORD_OFFSET, GREGORIAN)) + return INT_ERR_CODE; + + if (dinfo.month > af_info->to_a_year_end) + return dinfo.year + 1 - BASE_YEAR; + else + return dinfo.year - BASE_YEAR; } -static npy_int64 DtoQ_yq(npy_int64 ordinal, asfreq_info *af_info, - int *year, int *quarter) { - struct date_info dinfo; - if (dInfoCalc_SetFromAbsDate(&dinfo, ordinal + ORD_OFFSET, - GREGORIAN_CALENDAR)) return INT_ERR_CODE; +static i8 +DtoQ_yq(i8 ordinal, asfreq_info *af_info, i8 *year, i8 *quarter) +{ + date_info dinfo; + + if (dInfoCalc_SetFromAbsDate(&dinfo, ordinal + ORD_OFFSET, GREGORIAN)) + return INT_ERR_CODE; + if (af_info->to_q_year_end != 12) { dinfo.month -= af_info->to_q_year_end; - if (dinfo.month <= 0) { dinfo.month += 12; } - else { dinfo.year += 1; } + + if (dinfo.month <= 0) + dinfo.month += 12; + else + ++dinfo.year; + dinfo.quarter = monthToQuarter(dinfo.month); } @@ -334,636 +379,1122 @@ static npy_int64 DtoQ_yq(npy_int64 ordinal, asfreq_info *af_info, } -static npy_int64 asfreq_DtoQ(npy_int64 ordinal, char relation, asfreq_info *af_info) { - - int year, quarter; +static i8 +asfreq_DtoQ(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + i8 year, quarter; - if (DtoQ_yq(ordinal, af_info, &year, &quarter) == INT_ERR_CODE) { + if (DtoQ_yq(ordinal, af_info, &year, &quarter) == INT_ERR_CODE) return INT_ERR_CODE; - } - return (npy_int64)((year - BASE_YEAR) * 4 + quarter - 1); + return (year - BASE_YEAR) * 4 + quarter - 1; } -static npy_int64 asfreq_DtoM(npy_int64 ordinal, char relation, asfreq_info *af_info) { +static i8 +asfreq_DtoM(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + date_info dinfo; - struct date_info dinfo; - if (dInfoCalc_SetFromAbsDate(&dinfo, ordinal + ORD_OFFSET, GREGORIAN_CALENDAR)) + if (dInfoCalc_SetFromAbsDate(&dinfo, ordinal + ORD_OFFSET, GREGORIAN)) return INT_ERR_CODE; - return (npy_int64)((dinfo.year - BASE_YEAR) * 12 + dinfo.month - 1); + + return (dinfo.year - BASE_YEAR) * 12 + dinfo.month - 1; } -static npy_int64 asfreq_DtoW(npy_int64 ordinal, char relation, asfreq_info *af_info) { - return (ordinal + ORD_OFFSET - (1 + af_info->to_week_end))/7 + 1 - WEEK_OFFSET; +static i8 +asfreq_DtoW(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return (ordinal + ORD_OFFSET - (1 + af_info->to_week_end)) / 7 + + 1 - WEEK_OFFSET; } -static npy_int64 asfreq_DtoB(npy_int64 ordinal, char relation, asfreq_info *af_info) { +static i8 +asfreq_DtoB(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + date_info dinfo; - struct date_info dinfo; - if (dInfoCalc_SetFromAbsDate(&dinfo, ordinal + ORD_OFFSET, - GREGORIAN_CALENDAR)) return INT_ERR_CODE; + if (dInfoCalc_SetFromAbsDate(&dinfo, ordinal + ORD_OFFSET, GREGORIAN)) + return INT_ERR_CODE; - if (relation == 'S') { + if (!strcmp(relation, "S")) return DtoB_WeekendToFriday(dinfo.absdate, dinfo.day_of_week); - } else { + else return DtoB_WeekendToMonday(dinfo.absdate, dinfo.day_of_week); - } } // needed for getDateInfo function -static npy_int64 asfreq_DtoD(npy_int64 ordinal, char relation, asfreq_info *af_info) { return ordinal; } +static i8 +asfreq_DtoD(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return ordinal; +} -static npy_int64 asfreq_DtoHIGHFREQ(npy_int64 ordinal, char relation, npy_int64 per_day) { - if (relation == 'S') { - return ordinal * per_day; - } - else { - return (ordinal+ 1) * per_day - 1; - } +static i8 +asfreq_DtoHIGHFREQ(i8 ordinal, const char* relation, i8 per_day) +{ + if (!strcmp(relation, "S")) + return ordinal * per_day; + else + return (ordinal + 1) * per_day - 1; +} + +static i8 +asfreq_StoHIGHFREQ(i8 ordinal, const char* relation, i8 per_sec) +{ + if (!strcmp(relation, "S")) + return ordinal * per_sec; + else + return (ordinal + 1) * per_sec - 1; +} + +static i8 +asfreq_DtoH(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoHIGHFREQ(ordinal, relation, 24L); +} + +static i8 +asfreq_DtoT(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoHIGHFREQ(ordinal, relation, 24 * 60L); +} + +static i8 +asfreq_DtoS(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoHIGHFREQ(ordinal, relation, 24 * 60L * 60L); +} + +static i8 +asfreq_DtoU(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoHIGHFREQ(ordinal, relation, US_PER_DAY); } -static npy_int64 asfreq_DtoH(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoHIGHFREQ(ordinal, relation, 24); } -static npy_int64 asfreq_DtoT(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoHIGHFREQ(ordinal, relation, 24*60); } -static npy_int64 asfreq_DtoS(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoHIGHFREQ(ordinal, relation, 24*60*60); } //************ FROM SECONDLY *************** -static npy_int64 asfreq_StoD(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return (ordinal)/(60*60*24); } +static i8 +asfreq_StoD(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return ordinal / (60L * 60L * 24L); +} -static npy_int64 asfreq_StoA(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoA(asfreq_StoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } +static i8 +asfreq_StoA(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoA(asfreq_StoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} -static npy_int64 asfreq_StoQ(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoQ(asfreq_StoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } +static i8 +asfreq_StoQ(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoQ(asfreq_StoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} -static npy_int64 asfreq_StoM(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoM(asfreq_StoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } +static i8 +asfreq_StoM(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoM(asfreq_StoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} -static npy_int64 asfreq_StoW(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoW(asfreq_StoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } +static i8 +asfreq_StoW(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoW(asfreq_StoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} -static npy_int64 asfreq_StoB(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoB(asfreq_StoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } +static i8 +asfreq_StoB(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoB(asfreq_StoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} -static npy_int64 asfreq_StoT(npy_int64 ordinal, char relation, asfreq_info *af_info) { +static i8 +asfreq_StoT(i8 ordinal, const char* relation, asfreq_info *af_info) +{ return ordinal / 60; } -static npy_int64 asfreq_StoH(npy_int64 ordinal, char relation, asfreq_info *af_info) { - return ordinal / (60*60); +static i8 +asfreq_StoH(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return ordinal / 3600; } //************ FROM MINUTELY *************** -static npy_int64 asfreq_TtoD(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return (ordinal)/(60*24); } - -static npy_int64 asfreq_TtoA(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoA(asfreq_TtoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } -static npy_int64 asfreq_TtoQ(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoQ(asfreq_TtoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } -static npy_int64 asfreq_TtoM(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoM(asfreq_TtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } -static npy_int64 asfreq_TtoW(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoW(asfreq_TtoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } -static npy_int64 asfreq_TtoB(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoB(asfreq_TtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } - -static npy_int64 asfreq_TtoH(npy_int64 ordinal, char relation, asfreq_info *af_info) { - return ordinal / 60; +static i8 +asfreq_TtoD(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return ordinal / (60 * 24); } -static npy_int64 asfreq_TtoS(npy_int64 ordinal, char relation, asfreq_info *af_info) { - if (relation == 'S') { - return ordinal*60; } - else { - return ordinal*60 + 59; - } +static i8 +asfreq_TtoA(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoA(asfreq_TtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_TtoQ(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoQ(asfreq_TtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_TtoM(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoM(asfreq_TtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_TtoW(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoW(asfreq_TtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_TtoB(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoB(asfreq_TtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_TtoH(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return ordinal / 60; +} + +static i8 +asfreq_TtoS(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + i8 out = ordinal * 60; + + if (strcmp(relation, "S")) + out += 59; + + return out; } //************ FROM HOURLY *************** -static npy_int64 asfreq_HtoD(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return ordinal / 24; } -static npy_int64 asfreq_HtoA(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoA(asfreq_HtoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } -static npy_int64 asfreq_HtoQ(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoQ(asfreq_HtoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } -static npy_int64 asfreq_HtoM(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoM(asfreq_HtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } -static npy_int64 asfreq_HtoW(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoW(asfreq_HtoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } -static npy_int64 asfreq_HtoB(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoB(asfreq_HtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } +static i8 +asfreq_HtoD(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return ordinal / 24; +} + +static i8 +asfreq_HtoA(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoA(asfreq_HtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_HtoQ(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoQ(asfreq_HtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_HtoM(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoM(asfreq_HtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_HtoW(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoW(asfreq_HtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_HtoB(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoB(asfreq_HtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} // calculation works out the same as TtoS, so we just call that function for HtoT -static npy_int64 asfreq_HtoT(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_TtoS(ordinal, relation, &NULL_AF_INFO); } +static i8 +asfreq_HtoT(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_TtoS(ordinal, relation, &NULL_AF_INFO); +} -static npy_int64 asfreq_HtoS(npy_int64 ordinal, char relation, asfreq_info *af_info) { - if (relation == 'S') { - return ordinal*60*60; - } - else { - return (ordinal + 1)*60*60 - 1; - } +static i8 +asfreq_HtoS(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + i8 ret, secs_per_hour = 3600; + + if (!strcmp(relation, "S")) + ret = ordinal * secs_per_hour; + else + ret = (ordinal + 1) * secs_per_hour - 1; + + return ret; } //************ FROM BUSINESS *************** -static npy_int64 asfreq_BtoD(npy_int64 ordinal, char relation, asfreq_info *af_info) - { - ordinal += BDAY_OFFSET; - return (((ordinal - 1) / 5) * 7 + - mod_compat(ordinal - 1, 5) + 1 - ORD_OFFSET); - } +static i8 +asfreq_BtoD(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + i8 ord = ordinal; + ord += BDAY_OFFSET; + return (ord - 1) / 5 * 7 + mod_compat(ord - 1, 5) + 1 - ORD_OFFSET; +} -static npy_int64 asfreq_BtoA(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoA(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } +static i8 +asfreq_BtoA(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoA(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} -static npy_int64 asfreq_BtoQ(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoQ(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } +static i8 +asfreq_BtoQ(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoQ(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} -static npy_int64 asfreq_BtoM(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoM(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } +static i8 +asfreq_BtoM(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoM(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} -static npy_int64 asfreq_BtoW(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoW(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } +static i8 +asfreq_BtoW(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoW(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} -static npy_int64 asfreq_BtoH(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoH(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } +static i8 +asfreq_BtoH(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoH(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} -static npy_int64 asfreq_BtoT(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoT(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } +static i8 +asfreq_BtoT(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoT(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} -static npy_int64 asfreq_BtoS(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoS(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } +static i8 +asfreq_BtoS(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoS(asfreq_BtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} //************ FROM WEEKLY *************** -static npy_int64 asfreq_WtoD(npy_int64 ordinal, char relation, asfreq_info *af_info) { - ordinal += WEEK_OFFSET; - if (relation == 'S') { - return ordinal * 7 - 6 + af_info->from_week_end - ORD_OFFSET; - } - else { - return ordinal * 7 + af_info->from_week_end - ORD_OFFSET; - } +static i8 +asfreq_WtoD(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + i8 k = 0, ord = ordinal; + ord += WEEK_OFFSET; + ord *= 7; + + if (!strcmp(relation, "S")) + k = -6; + + return ord + k + af_info->from_week_end - ORD_OFFSET; +} + +static i8 +asfreq_WtoA(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoA(asfreq_WtoD(ordinal, "E", af_info), relation, af_info); } -static npy_int64 asfreq_WtoA(npy_int64 ordinal, char relation, asfreq_info *af_info) { - return asfreq_DtoA(asfreq_WtoD(ordinal, 'E', af_info), relation, af_info); } -static npy_int64 asfreq_WtoQ(npy_int64 ordinal, char relation, asfreq_info *af_info) { - return asfreq_DtoQ(asfreq_WtoD(ordinal, 'E', af_info), relation, af_info); } -static npy_int64 asfreq_WtoM(npy_int64 ordinal, char relation, asfreq_info *af_info) { - return asfreq_DtoM(asfreq_WtoD(ordinal, 'E', af_info), relation, &NULL_AF_INFO); } +static i8 +asfreq_WtoQ(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoQ(asfreq_WtoD(ordinal, "E", af_info), relation, af_info); +} -static npy_int64 asfreq_WtoW(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoW(asfreq_WtoD(ordinal, relation, af_info), relation, af_info); } +static i8 +asfreq_WtoM(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoM(asfreq_WtoD(ordinal, "E", af_info), relation, + &NULL_AF_INFO); +} -static npy_int64 asfreq_WtoB(npy_int64 ordinal, char relation, asfreq_info *af_info) { +static i8 +asfreq_WtoW(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoW(asfreq_WtoD(ordinal, relation, af_info), relation, + af_info); +} - struct date_info dinfo; - if (dInfoCalc_SetFromAbsDate(&dinfo, - asfreq_WtoD(ordinal, relation, af_info) + ORD_OFFSET, - GREGORIAN_CALENDAR)) return INT_ERR_CODE; +static i8 +asfreq_WtoB(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + i8 wtod = asfreq_WtoD(ordinal, relation, af_info) + ORD_OFFSET; - if (relation == 'S') { - return DtoB_WeekendToMonday(dinfo.absdate, dinfo.day_of_week); - } - else { - return DtoB_WeekendToFriday(dinfo.absdate, dinfo.day_of_week); - } + date_info dinfo; + if (dInfoCalc_SetFromAbsDate(&dinfo, wtod, GREGORIAN)) + return INT_ERR_CODE; + + i8 (*f)(i8 absdate, i8 day_of_week) = NULL; + f = !strcmp(relation, "S") ? DtoB_WeekendToMonday : DtoB_WeekendToFriday; + return f(dinfo.absdate, dinfo.day_of_week); +} + +static i8 +asfreq_WtoH(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoH(asfreq_WtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); } -static npy_int64 asfreq_WtoH(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoH(asfreq_WtoD(ordinal, relation, af_info), relation, &NULL_AF_INFO); } -static npy_int64 asfreq_WtoT(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoT(asfreq_WtoD(ordinal, relation, af_info), relation, &NULL_AF_INFO); } -static npy_int64 asfreq_WtoS(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoS(asfreq_WtoD(ordinal, relation, af_info), relation, &NULL_AF_INFO); } +static i8 +asfreq_WtoT(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoT(asfreq_WtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_WtoS(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoS(asfreq_WtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} //************ FROM MONTHLY *************** -static void MtoD_ym(npy_int64 ordinal, int *y, int *m) { +static void +MtoD_ym(i8 ordinal, i8 *y, i8 *m) +{ *y = floordiv(ordinal, 12) + BASE_YEAR; *m = mod_compat(ordinal, 12) + 1; } -static npy_int64 asfreq_MtoD(npy_int64 ordinal, char relation, asfreq_info *af_info) { +static i8 +asfreq_MtoD(i8 ordinal, const char* relation, asfreq_info *af_info) +{ - npy_int64 absdate; - int y, m; + i8 absdate, y, m; - if (relation == 'S') { + if (!strcmp(relation, "S")) { MtoD_ym(ordinal, &y, &m); - if ((absdate = absdate_from_ymd(y, m, 1)) == INT_ERR_CODE) return INT_ERR_CODE; + + if ((absdate = absdate_from_ymd(y, m, 1)) == INT_ERR_CODE) + return INT_ERR_CODE; + return absdate - ORD_OFFSET; - } else { + } + else { MtoD_ym(ordinal + 1, &y, &m); - if ((absdate = absdate_from_ymd(y, m, 1)) == INT_ERR_CODE) return INT_ERR_CODE; + + if ((absdate = absdate_from_ymd(y, m, 1)) == INT_ERR_CODE) + return INT_ERR_CODE; + return absdate - 1 - ORD_OFFSET; } } -static npy_int64 asfreq_MtoA(npy_int64 ordinal, char relation, asfreq_info *af_info) { - return asfreq_DtoA(asfreq_MtoD(ordinal, 'E', &NULL_AF_INFO), relation, af_info); } +static i8 +asfreq_MtoA(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoA(asfreq_MtoD(ordinal, "E", &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_MtoQ(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoQ(asfreq_MtoD(ordinal, "E", &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_MtoW(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoW(asfreq_MtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_MtoB(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + + date_info dinfo; + i8 mtod = asfreq_MtoD(ordinal, relation, &NULL_AF_INFO) + ORD_OFFSET; -static npy_int64 asfreq_MtoQ(npy_int64 ordinal, char relation, asfreq_info *af_info) { - return asfreq_DtoQ(asfreq_MtoD(ordinal, 'E', &NULL_AF_INFO), relation, af_info); } + if (dInfoCalc_SetFromAbsDate(&dinfo, mtod, GREGORIAN)) + return INT_ERR_CODE; -static npy_int64 asfreq_MtoW(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoW(asfreq_MtoD(ordinal, relation, &NULL_AF_INFO), relation, af_info); } + i8 (*f)(i8 absdate, i8 day_of_week); + f = !strcmp(relation, "S") ? DtoB_WeekendToMonday : DtoB_WeekendToFriday; -static npy_int64 asfreq_MtoB(npy_int64 ordinal, char relation, asfreq_info *af_info) { + return f(dinfo.absdate, dinfo.day_of_week); +} - struct date_info dinfo; - if (dInfoCalc_SetFromAbsDate(&dinfo, - asfreq_MtoD(ordinal, relation, &NULL_AF_INFO) + ORD_OFFSET, - GREGORIAN_CALENDAR)) return INT_ERR_CODE; +static i8 +asfreq_MtoH(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoH(asfreq_MtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} - if (relation == 'S') { return DtoB_WeekendToMonday(dinfo.absdate, dinfo.day_of_week); } - else { return DtoB_WeekendToFriday(dinfo.absdate, dinfo.day_of_week); } +static i8 +asfreq_MtoT(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoT(asfreq_MtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); } -static npy_int64 asfreq_MtoH(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoH(asfreq_MtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } -static npy_int64 asfreq_MtoT(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoT(asfreq_MtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } -static npy_int64 asfreq_MtoS(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoS(asfreq_MtoD(ordinal, relation, &NULL_AF_INFO), relation, &NULL_AF_INFO); } +static i8 +asfreq_MtoS(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoS(asfreq_MtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} //************ FROM QUARTERLY *************** -static void QtoD_ym(npy_int64 ordinal, int *y, int *m, asfreq_info *af_info) { +static void +QtoD_ym(i8 ordinal, i8 *y, i8 *m, asfreq_info *af_info) +{ *y = floordiv(ordinal, 4) + BASE_YEAR; *m = mod_compat(ordinal, 4) * 3 + 1; if (af_info->from_q_year_end != 12) { *m += af_info->from_q_year_end; - if (*m > 12) { *m -= 12; } - else { *y -= 1; } + + if (*m > 12) + *m -= 12; + else + --*y; } } -static npy_int64 asfreq_QtoD(npy_int64 ordinal, char relation, asfreq_info *af_info) { - - npy_int64 absdate; - int y, m; +static i8 +asfreq_QtoD(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + i8 absdate, y, m; - if (relation == 'S') { + if (!strcmp(relation, "S")) { QtoD_ym(ordinal, &y, &m, af_info); - // printf("ordinal: %d, year: %d, month: %d\n", (int) ordinal, y, m); - if ((absdate = absdate_from_ymd(y, m, 1)) == INT_ERR_CODE) return INT_ERR_CODE; + + if ((absdate = absdate_from_ymd(y, m, 1)) == INT_ERR_CODE) + return INT_ERR_CODE; + return absdate - ORD_OFFSET; } else { - QtoD_ym(ordinal+1, &y, &m, af_info); - /* printf("ordinal: %d, year: %d, month: %d\n", (int) ordinal, y, m); */ - if ((absdate = absdate_from_ymd(y, m, 1)) == INT_ERR_CODE) return INT_ERR_CODE; + QtoD_ym(ordinal + 1, &y, &m, af_info); + + if ((absdate = absdate_from_ymd(y, m, 1)) == INT_ERR_CODE) + return INT_ERR_CODE; + return absdate - 1 - ORD_OFFSET; } } -static npy_int64 asfreq_QtoQ(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoQ(asfreq_QtoD(ordinal, relation, af_info), relation, af_info); } +static i8 +asfreq_QtoQ(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoQ(asfreq_QtoD(ordinal, relation, af_info), relation, + af_info); +} + +static i8 +asfreq_QtoA(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoA(asfreq_QtoD(ordinal, relation, af_info), relation, + af_info); +} -static npy_int64 asfreq_QtoA(npy_int64 ordinal, char relation, asfreq_info *af_info) { - return asfreq_DtoA(asfreq_QtoD(ordinal, relation, af_info), relation, af_info); } +static i8 +asfreq_QtoM(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoM(asfreq_QtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} -static npy_int64 asfreq_QtoM(npy_int64 ordinal, char relation, asfreq_info *af_info) { - return asfreq_DtoM(asfreq_QtoD(ordinal, relation, af_info), relation, &NULL_AF_INFO); } +static i8 +asfreq_QtoW(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoW(asfreq_QtoD(ordinal, relation, af_info), relation, + af_info); +} -static npy_int64 asfreq_QtoW(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoW(asfreq_QtoD(ordinal, relation, af_info), relation, af_info); } +static i8 +asfreq_QtoB(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + date_info dinfo; + i8 qtod = asfreq_QtoD(ordinal, relation, af_info) + ORD_OFFSET; -static npy_int64 asfreq_QtoB(npy_int64 ordinal, char relation, asfreq_info *af_info) { + if (dInfoCalc_SetFromAbsDate(&dinfo, qtod, GREGORIAN)) + return INT_ERR_CODE; - struct date_info dinfo; - if (dInfoCalc_SetFromAbsDate(&dinfo, - asfreq_QtoD(ordinal, relation, af_info) + ORD_OFFSET, - GREGORIAN_CALENDAR)) return INT_ERR_CODE; + i8 (*f)(i8 abdate, i8 day_of_week) = NULL; + f = !strcmp(relation, "S") ? DtoB_WeekendToMonday : DtoB_WeekendToFriday; - if (relation == 'S') { return DtoB_WeekendToMonday(dinfo.absdate, dinfo.day_of_week); } - else { return DtoB_WeekendToFriday(dinfo.absdate, dinfo.day_of_week); } + return f(dinfo.absdate, dinfo.day_of_week); } -static npy_int64 asfreq_QtoH(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoH(asfreq_QtoD(ordinal, relation, af_info), relation, &NULL_AF_INFO); } -static npy_int64 asfreq_QtoT(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoT(asfreq_QtoD(ordinal, relation, af_info), relation, &NULL_AF_INFO); } -static npy_int64 asfreq_QtoS(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoS(asfreq_QtoD(ordinal, relation, af_info), relation, &NULL_AF_INFO); } +static i8 +asfreq_QtoH(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoH(asfreq_QtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_QtoT(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoT(asfreq_QtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_QtoS(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoS(asfreq_QtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} //************ FROM ANNUAL *************** -static npy_int64 asfreq_AtoD(npy_int64 ordinal, char relation, asfreq_info *af_info) { - npy_int64 absdate, final_adj; - int year; - int month = (af_info->from_a_year_end) % 12; +static i8 +asfreq_AtoD(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + i8 absdate, final_adj, year; + i8 month = af_info->from_a_year_end % 12, ord = ordinal; // start from 1970 - ordinal += BASE_YEAR; + ord += BASE_YEAR; - if (month == 0) { month = 1; } - else { month += 1; } + if (month == 0) + month = 1; + else + ++month; - if (relation == 'S') { - if (af_info->from_a_year_end == 12) {year = ordinal;} - else {year = ordinal - 1;} + if (!strcmp(relation, "S")) { + year = af_info->from_a_year_end == 12 ? ord : ord - 1; final_adj = 0; } else { - if (af_info->from_a_year_end == 12) {year = ordinal+1;} - else {year = ordinal;} + if (af_info->from_a_year_end == 12) + year = ord + 1; + else + year = ord; + final_adj = -1; } + absdate = absdate_from_ymd(year, month, 1); - if (absdate == INT_ERR_CODE) { - return INT_ERR_CODE; - } + + if (absdate == INT_ERR_CODE) + return INT_ERR_CODE; + return absdate + final_adj - ORD_OFFSET; } -static npy_int64 asfreq_AtoA(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoA(asfreq_AtoD(ordinal, relation, af_info), relation, af_info); } +static i8 +asfreq_AtoA(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoA(asfreq_AtoD(ordinal, relation, af_info), relation, + af_info); +} + +static i8 +asfreq_AtoQ(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoQ(asfreq_AtoD(ordinal, relation, af_info), relation, + af_info); +} + +static i8 +asfreq_AtoM(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoM(asfreq_AtoD(ordinal, relation, af_info), relation, + af_info); +} -static npy_int64 asfreq_AtoQ(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoQ(asfreq_AtoD(ordinal, relation, af_info), relation, af_info); } +static i8 +asfreq_AtoW(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoW(asfreq_AtoD(ordinal, relation, af_info), relation, + af_info); +} -static npy_int64 asfreq_AtoM(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoM(asfreq_AtoD(ordinal, relation, af_info), relation, af_info); } +static i8 +asfreq_AtoB(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + date_info dinfo; -static npy_int64 asfreq_AtoW(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoW(asfreq_AtoD(ordinal, relation, af_info), relation, af_info); } + i8 atob = asfreq_AtoD(ordinal, relation, af_info) + ORD_OFFSET; -static npy_int64 asfreq_AtoB(npy_int64 ordinal, char relation, asfreq_info *af_info) { + if (dInfoCalc_SetFromAbsDate(&dinfo, atob, GREGORIAN)) + return INT_ERR_CODE; - struct date_info dinfo; - if (dInfoCalc_SetFromAbsDate(&dinfo, - asfreq_AtoD(ordinal, relation, af_info) + ORD_OFFSET, - GREGORIAN_CALENDAR)) return INT_ERR_CODE; + i8 (*f)(i8 date, i8 day_of_week) = NULL; + f = !strcmp(relation, "S") ? DtoB_WeekendToMonday : DtoB_WeekendToFriday; - if (relation == 'S') { return DtoB_WeekendToMonday(dinfo.absdate, dinfo.day_of_week); } - else { return DtoB_WeekendToFriday(dinfo.absdate, dinfo.day_of_week); } + return f(dinfo.absdate, dinfo.day_of_week); } -static npy_int64 asfreq_AtoH(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoH(asfreq_AtoD(ordinal, relation, af_info), relation, &NULL_AF_INFO); } -static npy_int64 asfreq_AtoT(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoT(asfreq_AtoD(ordinal, relation, af_info), relation, &NULL_AF_INFO); } -static npy_int64 asfreq_AtoS(npy_int64 ordinal, char relation, asfreq_info *af_info) - { return asfreq_DtoS(asfreq_AtoD(ordinal, relation, af_info), relation, &NULL_AF_INFO); } +static i8 +asfreq_AtoH(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoH(asfreq_AtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} -static npy_int64 nofunc(npy_int64 ordinal, char relation, asfreq_info *af_info) { return INT_ERR_CODE; } -static npy_int64 no_op(npy_int64 ordinal, char relation, asfreq_info *af_info) { return ordinal; } +static i8 +asfreq_AtoT(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoT(asfreq_AtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_AtoS(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoS(asfreq_AtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} + + +static i8 +nofunc(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return INT_ERR_CODE; +} + +static i8 +no_op(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return ordinal; +} // end of frequency specific conversion routines -static int get_freq_group(int freq) { return (freq/1000)*1000; } +static i8 +get_freq_group(i8 freq) +{ + return (freq / 1000) * 1000; +} -static int calc_a_year_end(int freq, int group) { - int result = (freq - group) % 12; - if (result == 0) {return 12;} - else {return result;} +static i8 +calc_a_year_end(i8 freq, i8 group) +{ + i8 result = (freq - group) % 12; + return !result ? 12 : result; } -static int calc_week_end(int freq, int group) { +static i8 +calc_week_end(i8 freq, i8 group) +{ return freq - group; } -void get_asfreq_info(int fromFreq, int toFreq, asfreq_info *af_info) { - int fromGroup = get_freq_group(fromFreq); - int toGroup = get_freq_group(toFreq); +void +get_asfreq_info(i8 fromFreq, i8 toFreq, asfreq_info *af_info) +{ + i8 fromGroup = get_freq_group(fromFreq); + i8 toGroup = get_freq_group(toFreq); switch(fromGroup) { - case FR_WK: { - af_info->from_week_end = calc_week_end(fromFreq, fromGroup); - } break; - case FR_ANN: { - af_info->from_a_year_end = calc_a_year_end(fromFreq, fromGroup); - } break; - case FR_QTR: { - af_info->from_q_year_end = calc_a_year_end(fromFreq, fromGroup); - } break; + case FR_WK: + af_info->from_week_end = calc_week_end(fromFreq, fromGroup); + break; + case FR_ANN: + af_info->from_a_year_end = calc_a_year_end(fromFreq, fromGroup); + break; + case FR_QTR: + af_info->from_q_year_end = calc_a_year_end(fromFreq, fromGroup); + break; } switch(toGroup) { - case FR_WK: { - af_info->to_week_end = calc_week_end(toFreq, toGroup); - } break; - case FR_ANN: { - af_info->to_a_year_end = calc_a_year_end(toFreq, toGroup); - } break; - case FR_QTR: { - af_info->to_q_year_end = calc_a_year_end(toFreq, toGroup); - } break; + case FR_WK: + af_info->to_week_end = calc_week_end(toFreq, toGroup); + break; + case FR_ANN: + af_info->to_a_year_end = calc_a_year_end(toFreq, toGroup); + break; + case FR_QTR: + af_info->to_q_year_end = calc_a_year_end(toFreq, toGroup); + break; } } -freq_conv_func get_asfreq_func(int fromFreq, int toFreq) +static i8 +asfreq_UtoS(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return ordinal / US_PER_SECOND; +} + +static i8 +asfreq_UtoD(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_StoD(asfreq_UtoS(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_UtoA(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoA(asfreq_UtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_UtoQ(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoQ(asfreq_UtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_UtoM(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoM(asfreq_UtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_UtoW(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoW(asfreq_UtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_UtoB(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoB(asfreq_UtoD(ordinal, relation, &NULL_AF_INFO), relation, + af_info); +} + +static i8 +asfreq_UtoH(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoH(asfreq_UtoD(ordinal, relation, &NULL_AF_INFO), + relation, &NULL_AF_INFO); +} + +static i8 +asfreq_UtoT(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoT(asfreq_UtoD(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} + + +static i8 +asfreq_StoU(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_StoHIGHFREQ(ordinal, relation, US_PER_SECOND); +} + +static i8 +asfreq_AtoU(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoU(asfreq_AtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_QtoU(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoU(asfreq_QtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_MtoU(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoU(asfreq_MtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_WtoU(i8 ordinal, const char* relation, asfreq_info *af_info) { - int fromGroup = get_freq_group(fromFreq); - int toGroup = get_freq_group(toFreq); + return asfreq_DtoU(asfreq_WtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_BtoU(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_DtoU(asfreq_BtoD(ordinal, relation, af_info), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_TtoU(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_StoU(asfreq_TtoS(ordinal, relation, &NULL_AF_INFO), relation, + &NULL_AF_INFO); +} + +static i8 +asfreq_HtoU(i8 ordinal, const char* relation, asfreq_info *af_info) +{ + return asfreq_TtoU(asfreq_HtoT(ordinal, relation, af_info), relation, + af_info); +} + +freq_conv_func +get_asfreq_func(i8 fromFreq, i8 toFreq) +{ + i8 fromGroup = get_freq_group(fromFreq); + i8 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: return &asfreq_AtoD; - case FR_HR: return &asfreq_AtoH; - case FR_MIN: return &asfreq_AtoT; - case FR_SEC: return &asfreq_AtoS; - 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: return &asfreq_QtoD; - case FR_HR: return &asfreq_QtoH; - case FR_MIN: return &asfreq_QtoT; - case FR_SEC: return &asfreq_QtoS; - 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: return &asfreq_MtoD; - case FR_HR: return &asfreq_MtoH; - case FR_MIN: return &asfreq_MtoT; - case FR_SEC: return &asfreq_MtoS; - 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: return &asfreq_WtoD; - case FR_HR: return &asfreq_WtoH; - case FR_MIN: return &asfreq_WtoT; - case FR_SEC: return &asfreq_WtoS; - 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_DAY: return &asfreq_BtoD; - case FR_BUS: return &no_op; - case FR_HR: return &asfreq_BtoH; - case FR_MIN: return &asfreq_BtoT; - case FR_SEC: return &asfreq_BtoS; - default: return &nofunc; - } - - case FR_DAY: - switch(toGroup) - { - case FR_ANN: return &asfreq_DtoA; - case FR_QTR: return &asfreq_DtoQ; - case FR_MTH: return &asfreq_DtoM; - case FR_WK: return &asfreq_DtoW; - case FR_BUS: return &asfreq_DtoB; - case FR_DAY: return &asfreq_DtoD; - case FR_HR: return &asfreq_DtoH; - case FR_MIN: return &asfreq_DtoT; - case FR_SEC: return &asfreq_DtoS; - default: return &nofunc; - } - - case FR_HR: - switch(toGroup) - { - case FR_ANN: return &asfreq_HtoA; - case FR_QTR: return &asfreq_HtoQ; - case FR_MTH: return &asfreq_HtoM; - case FR_WK: return &asfreq_HtoW; - case FR_BUS: return &asfreq_HtoB; - case FR_DAY: return &asfreq_HtoD; - case FR_HR: return &no_op; - case FR_MIN: return &asfreq_HtoT; - case FR_SEC: return &asfreq_HtoS; - default: return &nofunc; - } - - case FR_MIN: - switch(toGroup) - { - case FR_ANN: return &asfreq_TtoA; - case FR_QTR: return &asfreq_TtoQ; - case FR_MTH: return &asfreq_TtoM; - case FR_WK: return &asfreq_TtoW; - case FR_BUS: return &asfreq_TtoB; - case FR_DAY: return &asfreq_TtoD; - case FR_HR: return &asfreq_TtoH; - case FR_MIN: return &no_op; - case FR_SEC: return &asfreq_TtoS; - default: return &nofunc; - } - - case FR_SEC: - switch(toGroup) - { - case FR_ANN: return &asfreq_StoA; - case FR_QTR: return &asfreq_StoQ; - case FR_MTH: return &asfreq_StoM; - case FR_WK: return &asfreq_StoW; - case FR_BUS: return &asfreq_StoB; - case FR_DAY: return &asfreq_StoD; - case FR_HR: return &asfreq_StoH; - case FR_MIN: return &asfreq_StoT; - case FR_SEC: return &no_op; - default: return &nofunc; - } + 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: return &asfreq_AtoD; + case FR_HR: return &asfreq_AtoH; + case FR_MIN: return &asfreq_AtoT; + case FR_SEC: return &asfreq_AtoS; + case FR_USEC: return &asfreq_AtoU; + 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: return &asfreq_QtoD; + case FR_HR: return &asfreq_QtoH; + case FR_MIN: return &asfreq_QtoT; + case FR_SEC: return &asfreq_QtoS; + case FR_USEC: return &asfreq_QtoU; 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: return &asfreq_MtoD; + case FR_HR: return &asfreq_MtoH; + case FR_MIN: return &asfreq_MtoT; + case FR_SEC: return &asfreq_MtoS; + case FR_USEC: return &asfreq_MtoU; + 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: return &asfreq_WtoD; + case FR_HR: return &asfreq_WtoH; + case FR_MIN: return &asfreq_WtoT; + case FR_SEC: return &asfreq_WtoS; + case FR_USEC: return &asfreq_WtoU; + 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_DAY: return &asfreq_BtoD; + case FR_BUS: return &no_op; + case FR_HR: return &asfreq_BtoH; + case FR_MIN: return &asfreq_BtoT; + case FR_SEC: return &asfreq_BtoS; + case FR_USEC: return &asfreq_BtoU; + default: return &nofunc; + } + + case FR_DAY: + switch(toGroup) + { + case FR_ANN: return &asfreq_DtoA; + case FR_QTR: return &asfreq_DtoQ; + case FR_MTH: return &asfreq_DtoM; + case FR_WK: return &asfreq_DtoW; + case FR_BUS: return &asfreq_DtoB; + case FR_DAY: return &asfreq_DtoD; + case FR_HR: return &asfreq_DtoH; + case FR_MIN: return &asfreq_DtoT; + case FR_SEC: return &asfreq_DtoS; + case FR_USEC: return &asfreq_DtoU; + default: return &nofunc; + } + + case FR_HR: + switch(toGroup) + { + case FR_ANN: return &asfreq_HtoA; + case FR_QTR: return &asfreq_HtoQ; + case FR_MTH: return &asfreq_HtoM; + case FR_WK: return &asfreq_HtoW; + case FR_BUS: return &asfreq_HtoB; + case FR_DAY: return &asfreq_HtoD; + case FR_HR: return &no_op; + case FR_MIN: return &asfreq_HtoT; + case FR_SEC: return &asfreq_HtoS; + case FR_USEC: return &asfreq_HtoU; + default: return &nofunc; + } + + case FR_MIN: + switch(toGroup) + { + case FR_ANN: return &asfreq_TtoA; + case FR_QTR: return &asfreq_TtoQ; + case FR_MTH: return &asfreq_TtoM; + case FR_WK: return &asfreq_TtoW; + case FR_BUS: return &asfreq_TtoB; + case FR_DAY: return &asfreq_TtoD; + case FR_HR: return &asfreq_TtoH; + case FR_MIN: return &no_op; + case FR_SEC: return &asfreq_TtoS; + case FR_USEC: return &asfreq_TtoU; + default: return &nofunc; + } + + case FR_SEC: + switch(toGroup) + { + case FR_ANN: return &asfreq_StoA; + case FR_QTR: return &asfreq_StoQ; + case FR_MTH: return &asfreq_StoM; + case FR_WK: return &asfreq_StoW; + case FR_BUS: return &asfreq_StoB; + case FR_DAY: return &asfreq_StoD; + case FR_HR: return &asfreq_StoH; + case FR_MIN: return &asfreq_StoT; + case FR_SEC: return &no_op; + case FR_USEC: return &asfreq_StoU; + default: return &nofunc; + } + + case FR_USEC: + switch(toGroup) + { + case FR_ANN: return &asfreq_UtoA; + case FR_QTR: return &asfreq_UtoQ; + case FR_MTH: return &asfreq_UtoM; + case FR_WK: return &asfreq_UtoW; + case FR_BUS: return &asfreq_UtoB; + case FR_DAY: return &asfreq_UtoD; + case FR_HR: return &asfreq_UtoH; + case FR_MIN: return &asfreq_UtoT; + case FR_SEC: return &asfreq_UtoS; + case FR_USEC: return &no_op; + default: return &nofunc; + } + + default: return &nofunc; } } -double get_abs_time(int freq, npy_int64 daily_ord, npy_int64 ordinal) { +static i8 +get_abs_time(i8 freq, i8 daily_ord, i8 ordinal) +{ + + i8 start_ord, per_day, unit; - npy_int64 start_ord, per_day, unit; - switch(freq) + switch (freq) { - case FR_HR: - per_day = 24; - unit = 60 * 60; - break; - case FR_MIN: - per_day = 24*60; - unit = 60; - break; - case FR_SEC: - per_day = 24*60*60; - unit = 1; - break; - default: - return 0; // 24*60*60 - 1; + case FR_HR: + per_day = 24L; + unit = US_PER_HOUR; + break; + + case FR_MIN: + per_day = 24L * 60L; + unit = US_PER_MINUTE; + break; + + case FR_SEC: + per_day = 24L * 60L * 60L; + unit = US_PER_SECOND; + break; + + case FR_USEC: + per_day = US_PER_DAY; + unit = 1L; + break; + + default: + return 0L; } - start_ord = asfreq_DtoHIGHFREQ(daily_ord, 'S', per_day); - /* printf("start_ord: %d\n", start_ord); */ - return (double) ( unit * (ordinal - start_ord)); - /* if (ordinal >= 0) { */ - /* } */ - /* else { */ - /* return (double) (unit * mod_compat(ordinal - start_ord, per_day)); */ - /* } */ + start_ord = asfreq_DtoHIGHFREQ(daily_ord, "S", per_day); + return unit * (ordinal - start_ord); } /* Sets the time part of the DateTime object. */ -static -int dInfoCalc_SetFromAbsTime(struct date_info *dinfo, - double abstime) +static i8 +dInfoCalc_SetFromAbsTime(date_info *dinfo, i8 abstime) { - int inttime; - int hour,minute; - double second; - - inttime = (int)abstime; - hour = inttime / 3600; - minute = (inttime % 3600) / 60; - second = abstime - (double)(hour*3600 + minute*60); + i8 hour = abstime / US_PER_HOUR; + i8 minute = (abstime % US_PER_HOUR) / US_PER_MINUTE; + i8 second = (abstime - (hour * US_PER_HOUR + minute * US_PER_MINUTE)) / + US_PER_SECOND; + i8 microsecond = abstime - (hour * US_PER_HOUR + minute * US_PER_MINUTE + + second * US_PER_SECOND); dinfo->hour = hour; dinfo->minute = minute; dinfo->second = second; + dinfo->microsecond = microsecond; dinfo->abstime = abstime; @@ -971,29 +1502,30 @@ int dInfoCalc_SetFromAbsTime(struct date_info *dinfo, } /* Set the instance's value using the given date and time. calendar - may be set to the flags: GREGORIAN_CALENDAR, JULIAN_CALENDAR to + may be set to the flags: GREGORIAN, JULIAN to indicate the calendar to be used. */ -static -int dInfoCalc_SetFromAbsDateTime(struct date_info *dinfo, - npy_int64 absdate, - double abstime, - int calendar) +static i8 +dInfoCalc_SetFromAbsDateTime(date_info *dinfo, i8 absdate, i8 abstime, + enum CalendarType calendar) { /* Bounds check */ - Py_AssertWithArg(abstime >= 0.0 && abstime <= SECONDS_PER_DAY, - PyExc_ValueError, - "abstime out of range (0.0 - 86400.0): %f", - abstime); + Py_AssertWithArg(abstime >= 0 && abstime <= US_PER_DAY, + PyExc_ValueError, + "abstime out of range (0, 86400000000): %li", + abstime); /* Calculate the date */ - if (dInfoCalc_SetFromAbsDate(dinfo, absdate, calendar)) goto onError; + if (dInfoCalc_SetFromAbsDate(dinfo, absdate, calendar)) + goto onError; /* Calculate the time */ - if (dInfoCalc_SetFromAbsTime(dinfo, abstime)) goto onError; + if (dInfoCalc_SetFromAbsTime(dinfo, abstime)) + goto onError; return 0; - onError: + +onError: return INT_ERR_CODE; } @@ -1001,48 +1533,59 @@ int dInfoCalc_SetFromAbsDateTime(struct date_info *dinfo, * New pandas API-helper code, to expose to cython * ------------------------------------------------------------------*/ -npy_int64 asfreq(npy_int64 period_ordinal, int freq1, int freq2, char relation) +i8 +asfreq(i8 period_ordinal, i8 freq1, i8 freq2, const char* relation) { - npy_int64 val; - freq_conv_func func; - asfreq_info finfo; + freq_conv_func func = get_asfreq_func(freq1, freq2); - func = get_asfreq_func(freq1, freq2); + asfreq_info finfo; get_asfreq_info(freq1, freq2, &finfo); - val = (*func)(period_ordinal, relation, &finfo); + i8 val = func(period_ordinal, relation, &finfo); if (val == INT_ERR_CODE) { - // Py_Error(PyExc_ValueError, "Unable to convert to desired frequency."); goto onError; } + return val; + onError: return INT_ERR_CODE; } /* generate an ordinal in period space */ -npy_int64 get_period_ordinal(int year, int month, int day, - int hour, int minute, int second, - int freq) +i8 +get_period_ordinal(i8 year, i8 month, i8 day, i8 hour, i8 minute, i8 second, + i8 microsecond, i8 freq) { - npy_int64 absdays, delta; - npy_int64 weeks, days; - npy_int64 ordinal, day_adj; - int freq_group, fmonth, mdiff; - freq_group = get_freq_group(freq); + i8 absdays, delta, weeks, days, ordinal, day_adj, fmonth, mdiff; + i8 freq_group = get_freq_group(freq); + + if (freq == FR_USEC) { + absdays = absdate_from_ymd(year, month, day); + delta = absdays - ORD_OFFSET; + return delta * US_PER_DAY + hour * US_PER_HOUR + + minute * US_PER_MINUTE + second * US_PER_SECOND + microsecond; + } + + if (freq == FR_USEC) { + absdays = absdate_from_ymd(year, month, day); + delta = absdays - ORD_OFFSET; + return delta * US_PER_DAY + hour * US_PER_HOUR + + minute * US_PER_MINUTE + second * US_PER_SECOND + microsecond; + } if (freq == FR_SEC) { absdays = absdate_from_ymd(year, month, day); delta = (absdays - ORD_OFFSET); - return (npy_int64)(delta*86400 + hour*3600 + minute*60 + second); + return delta*86400 + hour*3600 + minute*60 + second; } if (freq == FR_MIN) { absdays = absdate_from_ymd(year, month, day); delta = (absdays - ORD_OFFSET); - return (npy_int64)(delta*1440 + hour*60 + minute); + return delta*1440 + hour*60 + minute; } if (freq == FR_HR) { @@ -1051,32 +1594,32 @@ npy_int64 get_period_ordinal(int year, int month, int day, goto onError; } delta = (absdays - ORD_OFFSET); - return (npy_int64)(delta*24 + hour); + return delta*24 + hour; } if (freq == FR_DAY) { - return (npy_int64) (absdate_from_ymd(year, month, day) - ORD_OFFSET); + return absdate_from_ymd(year, month, day) - ORD_OFFSET; } if (freq == FR_UND) { - return (npy_int64) (absdate_from_ymd(year, month, day) - ORD_OFFSET); + return absdate_from_ymd(year, month, day) - ORD_OFFSET; } if (freq == FR_BUS) { - if((days = absdate_from_ymd(year, month, day)) == INT_ERR_CODE) + if ((days = absdate_from_ymd(year, month, day)) == INT_ERR_CODE) { goto onError; } weeks = days / 7; - return (npy_int64)(days - weeks * 2) - BDAY_OFFSET; + return (days - weeks * 2) - BDAY_OFFSET; } if (freq_group == FR_WK) { - if((ordinal = (npy_int64)absdate_from_ymd(year, month, day)) == INT_ERR_CODE) + if ((ordinal = absdate_from_ymd(year, month, day)) == INT_ERR_CODE) { goto onError; } @@ -1091,26 +1634,26 @@ npy_int64 get_period_ordinal(int year, int month, int day, if (freq_group == FR_QTR) { - fmonth = freq - FR_QTR; - if (fmonth == 0) fmonth = 12; + fmonth = freq - FR_QTR; + if (fmonth == 0) fmonth = 12; - mdiff = month - fmonth; - if (mdiff < 0) mdiff += 12; - if (month >= fmonth) mdiff += 12; + mdiff = month - fmonth; + if (mdiff < 0) mdiff += 12; + if (month >= fmonth) mdiff += 12; - return (year - BASE_YEAR) * 4 + (mdiff - 1) / 3; + return (year - BASE_YEAR) * 4 + (mdiff - 1) / 3; } if (freq_group == FR_ANN) { - fmonth = freq - FR_ANN; - if (fmonth == 0) fmonth = 12; - if (month <= fmonth) { - return year - BASE_YEAR; - } - else { - return year - BASE_YEAR + 1; - } + fmonth = freq - FR_ANN; + if (fmonth == 0) fmonth = 12; + if (month <= fmonth) { + return year - BASE_YEAR; + } + else { + return year - BASE_YEAR + 1; + } } Py_Error(PyExc_RuntimeError, "Unable to generate frequency ordinal"); @@ -1120,40 +1663,46 @@ npy_int64 get_period_ordinal(int year, int month, int day, } /* - Returns the proleptic Gregorian ordinal of the date, as an integer. - This corresponds to the number of days since Jan., 1st, 1AD. - When the instance has a frequency less than daily, the proleptic date - is calculated for the last day of the period. + Returns the proleptic Gregorian ordinal of the date, as an i8eger. + This corresponds to the number of days since Jan., 1st, 1AD. + When the instance has a frequency less than daily, the proleptic date + is calculated for the last day of the period. */ -npy_int64 get_python_ordinal(npy_int64 period_ordinal, int freq) +i8 +get_python_ordinal(i8 period_ordinal, i8 freq) { - asfreq_info af_info; - npy_int64 (*toDaily)(npy_int64, char, asfreq_info*); - if (freq == FR_DAY) return period_ordinal + ORD_OFFSET; - toDaily = get_asfreq_func(freq, FR_DAY); + i8 (*toDaily)(i8, const char*, asfreq_info*) = get_asfreq_func(freq, + FR_DAY); + asfreq_info af_info; + get_asfreq_info(freq, FR_DAY, &af_info); - return toDaily(period_ordinal, 'E', &af_info) + ORD_OFFSET; + + return toDaily(period_ordinal, "E", &af_info) + ORD_OFFSET; } -char *str_replace(const char *s, const char *old, const char *new) { - char *ret; - int i, count = 0; +char* +str_replace(const char *s, const char *old, const char *new) +{ + char *ret = NULL; + i8 i, count = 0; size_t newlen = strlen(new); size_t oldlen = strlen(old); for (i = 0; s[i] != '\0'; i++) { if (strstr(&s[i], old) == &s[i]) { - count++; - i += oldlen - 1; + ++count; + i += oldlen - 1; } } ret = PyArray_malloc(i + 1 + count * (newlen - oldlen)); - if (ret == NULL) {return (char *)PyErr_NoMemory();} + if (ret == NULL) + return (char*) PyErr_NoMemory(); + i = 0; while (*s) { @@ -1165,6 +1714,7 @@ char *str_replace(const char *s, const char *old, const char *new) { ret[i++] = *s++; } } + ret[i] = '\0'; return ret; @@ -1173,84 +1723,86 @@ char *str_replace(const char *s, const char *old, const char *new) { // function to generate a nice string representation of the period // object, originally from DateObject_strftime -char* c_strftime(struct date_info *tmp, char *fmt) { +char* +c_strftime(date_info *tmp, char *fmt) +{ struct tm c_date; - char* result; - struct date_info dinfo = *tmp; - int result_len = strlen(fmt) + 50; + date_info dinfo = *tmp; - c_date.tm_sec = (int)dinfo.second; + size_t result_len = strlen(fmt) + 50L; + + c_date.tm_sec = dinfo.second; c_date.tm_min = dinfo.minute; c_date.tm_hour = dinfo.hour; c_date.tm_mday = dinfo.day; - c_date.tm_mon = dinfo.month - 1; - c_date.tm_year = dinfo.year - 1900; - c_date.tm_wday = (dinfo.day_of_week + 1) % 7; - c_date.tm_yday = dinfo.day_of_year - 1; - c_date.tm_isdst = -1; - - result = malloc(result_len * sizeof(char)); - + c_date.tm_mon = dinfo.month - 1L; + c_date.tm_year = dinfo.year - 1900L; + c_date.tm_wday = (dinfo.day_of_week + 1L) % 7L; + c_date.tm_yday = dinfo.day_of_year - 1L; + c_date.tm_isdst = -1L; + + // this must be freed by the caller (right now this is in cython) + char* result = malloc(result_len * sizeof(char)); strftime(result, result_len, fmt, &c_date); - return result; } -int get_yq(npy_int64 ordinal, int freq, int *quarter, int *year) { + +i8 +get_yq(i8 ordinal, i8 freq, i8 *quarter, i8 *year) +{ asfreq_info af_info; - int qtr_freq; - npy_int64 daily_ord; - npy_int64 (*toDaily)(npy_int64, char, asfreq_info*) = NULL; + i8 qtr_freq, daily_ord; + i8 (*toDaily)(i8, const char*, asfreq_info*) = get_asfreq_func(freq, FR_DAY); - toDaily = get_asfreq_func(freq, FR_DAY); get_asfreq_info(freq, FR_DAY, &af_info); - daily_ord = toDaily(ordinal, 'E', &af_info); + daily_ord = toDaily(ordinal, "E", &af_info); + + qtr_freq = get_freq_group(freq) == FR_QTR ? freq : FR_QTR; - if (get_freq_group(freq) == FR_QTR) { - qtr_freq = freq; - } else { qtr_freq = FR_QTR; } get_asfreq_info(FR_DAY, qtr_freq, &af_info); - if(DtoQ_yq(daily_ord, &af_info, year, quarter) == INT_ERR_CODE) + if (DtoQ_yq(daily_ord, &af_info, year, quarter) == INT_ERR_CODE) return -1; return 0; } - - - -static int _quarter_year(npy_int64 ordinal, int freq, int *year, int *quarter) { +static i8 +_quarter_year(i8 ordinal, i8 freq, i8 *year, i8 *quarter) +{ asfreq_info af_info; - int qtr_freq; - - ordinal = get_python_ordinal(ordinal, freq) - ORD_OFFSET; - if (get_freq_group(freq) == FR_QTR) - qtr_freq = freq; - else - qtr_freq = FR_QTR; + i8 ord = get_python_ordinal(ordinal, freq) - ORD_OFFSET; + i8 qtr_freq = get_freq_group(freq) == FR_QTR ? freq : FR_QTR; get_asfreq_info(FR_DAY, qtr_freq, &af_info); - if (DtoQ_yq(ordinal, &af_info, year, quarter) == INT_ERR_CODE) + if (DtoQ_yq(ord, &af_info, year, quarter) == INT_ERR_CODE) return INT_ERR_CODE; - if ((qtr_freq % 1000) > 12) + if (qtr_freq % 1000 > 12) *year -= 1; return 0; } -static int _ISOWeek(struct date_info *dinfo) + +static i8 +_ISOWeek(date_info *dinfo) { - int week; + i8 week; /* Estimate */ - week = (dinfo->day_of_year-1) - dinfo->day_of_week + 3; - if (week >= 0) week = week / 7 + 1; + week = (dinfo->day_of_year - 1) - dinfo->day_of_week + 3; + + if (week >= 0) { + week /= 7; + ++week; + } + /* Verify */ if (week < 0) { @@ -1261,8 +1813,8 @@ static int _ISOWeek(struct date_info *dinfo) else week = 52; } else if (week == 53) { - /* Check if the week belongs to year or year+1 */ - if (31-dinfo->day + dinfo->day_of_week < 3) { + /* Check if the week belongs to year or year+1 */ + if (31 - dinfo->day + dinfo->day_of_week < 3) { week = 1; } } @@ -1270,102 +1822,176 @@ static int _ISOWeek(struct date_info *dinfo) return week; } -int get_date_info(npy_int64 ordinal, int freq, struct date_info *dinfo) + +i8 +get_date_info(i8 ordinal, i8 freq, date_info *dinfo) { - npy_int64 absdate = get_python_ordinal(ordinal, freq); - /* printf("freq: %d, absdate: %d\n", freq, (int) absdate); */ - double abstime = get_abs_time(freq, absdate - ORD_OFFSET, ordinal); - if (abstime < 0) { - abstime += 86400; - absdate -= 1; - } + i8 absdate = get_python_ordinal(ordinal, freq); + i8 abstime = get_abs_time(freq, absdate - ORD_OFFSET, ordinal); + + if (abstime < 0) { + // add a day's worth of us to time + abstime += US_PER_DAY; + + // subtract a day from the date + --absdate; + } - if(dInfoCalc_SetFromAbsDateTime(dinfo, absdate, - abstime, GREGORIAN_CALENDAR)) + if (dInfoCalc_SetFromAbsDateTime(dinfo, absdate, abstime, GREGORIAN)) return INT_ERR_CODE; return 0; } -int pyear(npy_int64 ordinal, int freq) { - struct date_info dinfo; +i8 +pyear(i8 ordinal, i8 freq) +{ + date_info dinfo; get_date_info(ordinal, freq, &dinfo); return dinfo.year; } -int pqyear(npy_int64 ordinal, int freq) { - int year, quarter; - if( _quarter_year(ordinal, freq, &year, &quarter) == INT_ERR_CODE) +i8 +pqyear(i8 ordinal, i8 freq) +{ + i8 year, quarter; + if (_quarter_year(ordinal, freq, &year, &quarter) == INT_ERR_CODE) return INT_ERR_CODE; return year; } -int pquarter(npy_int64 ordinal, int freq) { - int year, quarter; - if(_quarter_year(ordinal, freq, &year, &quarter) == INT_ERR_CODE) +i8 +pquarter(i8 ordinal, i8 freq) +{ + i8 year, quarter; + if (_quarter_year(ordinal, freq, &year, &quarter) == INT_ERR_CODE) return INT_ERR_CODE; return quarter; } -int pmonth(npy_int64 ordinal, int freq) { - struct date_info dinfo; - if(get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) +i8 +pmonth(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) return INT_ERR_CODE; return dinfo.month; } -int pday(npy_int64 ordinal, int freq) { - struct date_info dinfo; - if(get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) +i8 +pday(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) return INT_ERR_CODE; return dinfo.day; } -int pweekday(npy_int64 ordinal, int freq) { - struct date_info dinfo; - if(get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) +i8 +pweekday(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) return INT_ERR_CODE; return dinfo.day_of_week; } -int pday_of_week(npy_int64 ordinal, int freq) { - struct date_info dinfo; - if(get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) +i8 +pday_of_week(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) return INT_ERR_CODE; return dinfo.day_of_week; } -int pday_of_year(npy_int64 ordinal, int freq) { - struct date_info dinfo; - if(get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) +i8 +pday_of_year(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) return INT_ERR_CODE; return dinfo.day_of_year; } -int pweek(npy_int64 ordinal, int freq) { - struct date_info dinfo; - if(get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) +i8 +pweek(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) return INT_ERR_CODE; return _ISOWeek(&dinfo); } -int phour(npy_int64 ordinal, int freq) { - struct date_info dinfo; - if(get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) +i8 +phour(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) return INT_ERR_CODE; return dinfo.hour; } -int pminute(npy_int64 ordinal, int freq) { - struct date_info dinfo; - if(get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) +i8 +pminute(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) return INT_ERR_CODE; return dinfo.minute; } -int psecond(npy_int64 ordinal, int freq) { - struct date_info dinfo; - if(get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) +i8 +psecond(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) + return INT_ERR_CODE; + return dinfo.second; +} + +i8 +pmicrosecond(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) + return INT_ERR_CODE; + return dinfo.microsecond; +} + +i8 +pnanosecond(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) + return INT_ERR_CODE; + return dinfo.nanosecond; +} + + +i8 +ppicosecond(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) + return INT_ERR_CODE; + return dinfo.picosecond; +} + +i8 +pfemtosecond(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) + return INT_ERR_CODE; + return dinfo.femtosecond; +} + +i8 +pattosecond(i8 ordinal, i8 freq) +{ + date_info dinfo; + if (get_date_info(ordinal, freq, &dinfo) == INT_ERR_CODE) return INT_ERR_CODE; - return (int)dinfo.second; + return dinfo.attosecond; } diff --git a/pandas/src/period.h b/pandas/src/period.h index 4ba92bf8fde41..867daf597dbca 100644 --- a/pandas/src/period.h +++ b/pandas/src/period.h @@ -12,148 +12,215 @@ #include "headers/stdint.h" #include "limits.h" + /* * declarations from period here */ -#define GREGORIAN_CALENDAR 0 -#define JULIAN_CALENDAR 1 +typedef int64_t i8; + +enum CalendarType +{ + GREGORIAN, + JULIAN +}; + +static const i8 SECONDS_PER_DAY = 86400; -#define SECONDS_PER_DAY ((double) 86400.0) +#define Py_AssertWithArg(x, errortype, errorstr, a1) \ + { \ + if (!((x))) { \ + PyErr_Format((errortype), (errorstr), (a1)); \ + goto onError; \ + } \ + } + +#define Py_Error(errortype, errorstr) \ + { \ + PyErr_SetString((errortype), (errorstr)); \ + goto onError; \ + } -#define Py_AssertWithArg(x,errortype,errorstr,a1) {if (!(x)) {PyErr_Format(errortype,errorstr,a1);goto onError;}} -#define Py_Error(errortype,errorstr) {PyErr_SetString(errortype,errorstr);goto onError;} /*** FREQUENCY CONSTANTS ***/ // HIGHFREQ_ORIG is the datetime ordinal from which to begin the second // frequency ordinal sequence -// typedef int64_t npy_int64; +// typedef int64_t i8; // begins second ordinal at 1/1/1970 unix epoch // #define HIGHFREQ_ORIG 62135683200LL -#define BASE_YEAR 1970 -#define ORD_OFFSET 719163LL // days until 1970-01-01 -#define BDAY_OFFSET 513689LL // days until 1970-01-01 -#define WEEK_OFFSET 102737LL -#define HIGHFREQ_ORIG 0 // ORD_OFFSET * 86400LL // days until 1970-01-01 - -#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*/ +static const i8 BASE_YEAR = 1970; +static const i8 ORD_OFFSET = 719163; // days until 1970-01-01 +static const i8 BDAY_OFFSET = 513689; // days until 1970-01-01 +static const i8 WEEK_OFFSET = 102737; +static const i8 HIGHFREQ_ORIG = 0; // ORD_OFFSET * 86400LL // days until 1970-01-01 + +enum Annual +{ + FR_ANN = 1000, /* Annual */ + FR_ANNDEC = FR_ANN, /* Annual - December year end*/ + FR_ANNJAN, /* Annual - January year end*/ + FR_ANNFEB, /* Annual - February year end*/ + FR_ANNMAR, /* Annual - March year end*/ + FR_ANNAPR, /* Annual - April year end*/ + FR_ANNMAY, /* Annual - May year end*/ + FR_ANNJUN, /* Annual - June year end*/ + FR_ANNJUL, /* Annual - July year end*/ + FR_ANNAUG, /* Annual - August year end*/ + FR_ANNSEP, /* Annual - September year end*/ + FR_ANNOCT, /* Annual - October year end*/ + FR_ANNNOV /* 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_UND -10000 /* Undefined */ - -#define INT_ERR_CODE INT32_MIN - -#define MEM_CHECK(item) if (item == NULL) { return PyErr_NoMemory(); } -#define ERR_CHECK(item) if (item == NULL) { return NULL; } - -typedef struct asfreq_info { - int from_week_end; // day the week ends on in the "from" frequency - int to_week_end; // day the week ends on in the "to" frequency - - int from_a_year_end; // month the year ends on in the "from" frequency - int to_a_year_end; // month the year ends on in the "to" frequency - - int from_q_year_end; // month the year ends on in the "from" frequency - int to_q_year_end; // month the year ends on in the "to" frequency +enum Quarterly +{ + FR_QTR = 2000, /* Quarterly - December year end (default quarterly) */ + FR_QTRDEC = FR_QTR, /* Quarterly - December year end */ + FR_QTRJAN, /* Quarterly - January year end */ + FR_QTRFEB, /* Quarterly - February year end */ + FR_QTRMAR, /* Quarterly - March year end */ + FR_QTRAPR, /* Quarterly - April year end */ + FR_QTRMAY, /* Quarterly - May year end */ + FR_QTRJUN, /* Quarterly - June year end */ + FR_QTRJUL, /* Quarterly - July year end */ + FR_QTRAUG, /* Quarterly - August year end */ + FR_QTRSEP, /* Quarterly - September year end */ + FR_QTROCT, /* Quarterly - October year end */ + FR_QTRNOV /* Quarterly - November year end */ +}; + +/* #define FR_MTH 3000 /\* Monthly *\/ */ + +enum Monthly +{ + FR_MTH = 3000 +}; + + +enum Weekly +{ + FR_WK = 4000, /* Weekly */ + FR_WKSUN = FR_WK, /* Weekly - Sunday end of week */ + FR_WKMON, /* Weekly - Monday end of week */ + FR_WKTUE, /* Weekly - Tuesday end of week */ + FR_WKWED, /* Weekly - Wednesday end of week */ + FR_WKTHU, /* Weekly - Thursday end of week */ + FR_WKFRI, /* Weekly - Friday end of week */ + FR_WKSAT /* Weekly - Saturday end of week */ +}; + +enum BusinessDaily { FR_BUS = 5000 }; +enum Daily { FR_DAY = 6000 }; +enum Hourly { FR_HR = 7000 }; +enum Minutely { FR_MIN = 8000 }; +enum Secondly { FR_SEC = 9000 }; +enum Microsecondly { FR_USEC = 10000 }; + +enum Undefined { FR_UND = -10000 }; + +static const i8 US_PER_SECOND = 1000000L; +static const i8 US_PER_MINUTE = 60 * 1000000L; +static const i8 US_PER_HOUR = 60 * 60 * 1000000L; +static const i8 US_PER_DAY = 24 * 60 * 60 * 1000000L; +static const i8 US_PER_WEEK = 7 * 24 * 60 * 60 * 1000000L; + +static const i8 NS_PER_SECOND = 1000000000L; +static const i8 NS_PER_MINUTE = 60 * 1000000000L; +static const i8 NS_PER_HOUR = 60 * 60 * 1000000000L; +static const i8 NS_PER_DAY = 24 * 60 * 60 * 1000000000L; +static const i8 NS_PER_WEEK = 7 * 24 * 60 * 60 * 1000000000L; + +// make sure INT64_MIN is a macro! +static const i8 INT_ERR_CODE = INT64_MIN; + +#define MEM_CHECK(item) \ + { \ + if (item == NULL) \ + return PyErr_NoMemory(); \ + } + +#define ERR_CHECK(item) \ + { \ + if (item == NULL) \ + return NULL; \ + } + +typedef struct asfreq_info +{ + i8 from_week_end; // day the week ends on in the "from" frequency + i8 to_week_end; // day the week ends on in the "to" frequency + + i8 from_a_year_end; // month the year ends on in the "from" frequency + i8 to_a_year_end; // month the year ends on in the "to" frequency + + i8 from_q_year_end; // month the year ends on in the "from" frequency + i8 to_q_year_end; // month the year ends on in the "to" frequency } asfreq_info; -typedef struct date_info { - npy_int64 absdate; - double abstime; - - double second; - int minute; - int hour; - int day; - int month; - int quarter; - int year; - int day_of_week; - int day_of_year; - int calendar; +typedef struct date_info +{ + i8 absdate; + i8 abstime; + + i8 attosecond; + i8 femtosecond; + i8 picosecond; + i8 nanosecond; + i8 microsecond; + i8 second; + i8 minute; + i8 hour; + i8 day; + i8 month; + i8 quarter; + i8 year; + i8 day_of_week; + i8 day_of_year; + i8 calendar; } date_info; -typedef npy_int64 (*freq_conv_func)(npy_int64, char, asfreq_info*); +typedef i8 (*freq_conv_func)(i8, const char*, asfreq_info*); /* * new pandas API helper functions here */ -npy_int64 asfreq(npy_int64 period_ordinal, int freq1, int freq2, char relation); - -npy_int64 get_period_ordinal(int year, int month, int day, - int hour, int minute, int second, - int freq); - -npy_int64 get_python_ordinal(npy_int64 period_ordinal, int freq); - -int get_date_info(npy_int64 ordinal, int freq, struct date_info *dinfo); -freq_conv_func get_asfreq_func(int fromFreq, int toFreq); -void get_asfreq_info(int fromFreq, int toFreq, asfreq_info *af_info); - -int pyear(npy_int64 ordinal, int freq); -int pqyear(npy_int64 ordinal, int freq); -int pquarter(npy_int64 ordinal, int freq); -int pmonth(npy_int64 ordinal, int freq); -int pday(npy_int64 ordinal, int freq); -int pweekday(npy_int64 ordinal, int freq); -int pday_of_week(npy_int64 ordinal, int freq); -int pday_of_year(npy_int64 ordinal, int freq); -int pweek(npy_int64 ordinal, int freq); -int phour(npy_int64 ordinal, int freq); -int pminute(npy_int64 ordinal, int freq); -int psecond(npy_int64 ordinal, int freq); +i8 asfreq(i8 period_ordinal, i8 freq1, i8 freq2, const char* relation); + +i8 get_period_ordinal(i8 year, i8 month, i8 day, i8 hour, i8 minute, i8 second, + i8 microsecond, i8 freq); + +i8 get_python_ordinal(i8 period_ordinal, i8 freq); + +i8 get_date_info(i8 ordinal, i8 freq, struct date_info *dinfo); +freq_conv_func get_asfreq_func(i8 fromFreq, i8 toFreq); +void get_asfreq_info(i8 fromFreq, i8 toFreq, asfreq_info *af_info); + +i8 pyear(i8 ordinal, i8 freq); +i8 pqyear(i8 ordinal, i8 freq); +i8 pquarter(i8 ordinal, i8 freq); +i8 pmonth(i8 ordinal, i8 freq); +i8 pday(i8 ordinal, i8 freq); +i8 pweekday(i8 ordinal, i8 freq); +i8 pday_of_week(i8 ordinal, i8 freq); +i8 pday_of_year(i8 ordinal, i8 freq); +i8 pweek(i8 ordinal, i8 freq); +i8 phour(i8 ordinal, i8 freq); +i8 pminute(i8 ordinal, i8 freq); +i8 psecond(i8 ordinal, i8 freq); +i8 pmicrosecond(i8 ordinal, i8 freq); +i8 pnanosecond(i8 ordinal, i8 freq); +i8 ppicosecond(i8 ordinal, i8 freq); +i8 pfemtosecond(i8 ordinal, i8 freq); +i8 pattosecond(i8 ordinal, i8 freq); -double getAbsTime(int freq, npy_int64 dailyDate, npy_int64 originalDate); char *c_strftime(struct date_info *dinfo, char *fmt); -int get_yq(npy_int64 ordinal, int freq, int *quarter, int *year); +i8 get_yq(i8 ordinal, i8 freq, i8 *quarter, i8 *year); #endif diff --git a/pandas/tseries/converter.py b/pandas/tseries/converter.py index dc0df89d1ef9c..bccef5e2e6a77 100644 --- a/pandas/tseries/converter.py +++ b/pandas/tseries/converter.py @@ -52,12 +52,15 @@ class TimeConverter(units.ConversionInterface): def convert(value, unit, axis): valid_types = (str, pydt.time) if (isinstance(value, valid_types) or com.is_integer(value) or - com.is_float(value)): + com.is_float(value)): return time2num(value) + if isinstance(value, Index): return value.map(time2num) + if isinstance(value, (list, tuple, np.ndarray)): return [time2num(x) for x in value] + return value @staticmethod @@ -95,7 +98,6 @@ def __call__(self, x, pos=0): return pydt.time(h, m, s, us).strftime(fmt) - ### Period Conversion @@ -107,7 +109,7 @@ def convert(values, units, axis): raise TypeError('Axis must have `freq` set to convert to Periods') valid_types = (str, datetime, Period, pydt.date, pydt.time) if (isinstance(values, valid_types) or com.is_integer(values) or - com.is_float(values)): + com.is_float(values)): return get_datevalue(values, axis.freq) if isinstance(values, Index): return values.map(lambda x: get_datevalue(x, axis.freq)) @@ -286,19 +288,19 @@ def __call__(self): if dmin > dmax: dmax, dmin = dmin, dmax - delta = relativedelta(dmax, dmin) + # delta = relativedelta(dmax, dmin) # We need to cap at the endpoints of valid datetime - try: - start = dmin - delta - except ValueError: - start = _from_ordinal(1.0) + # try: + # start = dmin - delta + # except ValueError: + # start = _from_ordinal(1.0) - try: - stop = dmax + delta - except ValueError: - # The magic number! - stop = _from_ordinal(3652059.9999999) + # try: + # stop = dmax + delta + # except ValueError: + # # The magic number! + # stop = _from_ordinal(3652059.9999999) nmax, nmin = dates.date2num((dmax, dmin)) @@ -318,7 +320,7 @@ def __call__(self): raise RuntimeError(('MillisecondLocator estimated to generate %d ' 'ticks from %s to %s: exceeds Locator.MAXTICKS' '* 2 (%d) ') % - (estimate, dmin, dmax, self.MAXTICKS * 2)) + (estimate, dmin, dmax, self.MAXTICKS * 2)) freq = '%dL' % self._get_interval() tz = self.tz.tzname(None) @@ -330,7 +332,7 @@ def __call__(self): if len(all_dates) > 0: locs = self.raise_if_exceeds(dates.date2num(all_dates)) return locs - except Exception, e: # pragma: no cover + except Exception: # pragma: no cover pass lims = dates.date2num([dmin, dmax]) @@ -347,19 +349,19 @@ def autoscale(self): if dmin > dmax: dmax, dmin = dmin, dmax - delta = relativedelta(dmax, dmin) + # delta = relativedelta(dmax, dmin) # We need to cap at the endpoints of valid datetime - try: - start = dmin - delta - except ValueError: - start = _from_ordinal(1.0) + # try: + # start = dmin - delta + # except ValueError: + # start = _from_ordinal(1.0) - try: - stop = dmax + delta - except ValueError: - # The magic number! - stop = _from_ordinal(3652059.9999999) + # try: + # stop = dmax + delta + # except ValueError: + # # The magic number! + # stop = _from_ordinal(3652059.9999999) dmin, dmax = self.datalim_to_dt() @@ -454,7 +456,9 @@ def _daily_finder(vmin, vmax, freq): periodsperday = -1 if freq >= FreqGroup.FR_HR: - if freq == FreqGroup.FR_SEC: + if freq == FreqGroup.FR_USEC: + periodsperday = 24 * 60 * 60 * 1000000 + elif freq == FreqGroup.FR_SEC: periodsperday = 24 * 60 * 60 elif freq == FreqGroup.FR_MIN: periodsperday = 24 * 60 @@ -497,11 +501,8 @@ def _daily_finder(vmin, vmax, freq): info_fmt = info['fmt'] def first_label(label_flags): - if (label_flags[0] == 0) and (label_flags.size > 1) and \ - ((vmin_orig % 1) > 0.0): - return label_flags[1] - else: - return label_flags[0] + conds = label_flags[0] == 0, label_flags.size > 1, vmin_orig % 1 > 0.0 + return label_flags[int(all(conds))] # Case 1. Less than a month if span <= periodspermonth: @@ -543,8 +544,7 @@ def _second_finder(label_interval): info['min'][second_start & (_second % label_interval == 0)] = True year_start = period_break(dates_, 'year') info_fmt = info['fmt'] - info_fmt[second_start & (_second % - label_interval == 0)] = '%H:%M:%S' + info_fmt[second_start & (_second % label_interval == 0)] = '%H:%M:%S' info_fmt[day_start] = '%H:%M:%S\n%d-%b' info_fmt[year_start] = '%H:%M:%S\n%d-%b\n%Y' @@ -588,6 +588,7 @@ def _second_finder(label_interval): info_fmt[day_start] = '%d' info_fmt[month_start] = '%d\n%b' info_fmt[year_start] = '%d\n%b\n%Y' + if not has_level_label(year_start, vmin_orig): if not has_level_label(month_start, vmin_orig): info_fmt[first_label(day_start)] = '%d\n%b\n%Y' @@ -902,11 +903,10 @@ def autoscale(self): vmax += 1 return nonsingular(vmin, vmax) + #####------------------------------------------------------------------------- #---- --- Formatter --- #####------------------------------------------------------------------------- - - class TimeSeries_DateFormatter(Formatter): """ Formats the ticks along an axis controlled by a :class:`PeriodIndex`. diff --git a/pandas/tseries/frequencies.py b/pandas/tseries/frequencies.py index 3bf29af8581a9..16a84fbfbe8cd 100644 --- a/pandas/tseries/frequencies.py +++ b/pandas/tseries/frequencies.py @@ -22,6 +22,7 @@ class FreqGroup(object): FR_HR = 7000 FR_MIN = 8000 FR_SEC = 9000 + FR_USEC = 10000 class Resolution(object): @@ -34,11 +35,11 @@ class Resolution(object): @classmethod def get_str(cls, reso): - return {RESO_US: 'microsecond', - RESO_SEC: 'second', - RESO_MIN: 'minute', - RESO_HR: 'hour', - RESO_DAY: 'day'}.get(reso, 'day') + return {cls.RESO_US: 'microsecond', + cls.RESO_SEC: 'second', + cls.RESO_MIN: 'minute', + cls.RESO_HR: 'hour', + cls.RESO_DAY: 'day'}.get(reso, 'day') def get_reso_string(reso): @@ -48,8 +49,10 @@ def get_reso_string(reso): def get_to_timestamp_base(base): if base <= FreqGroup.FR_WK: return FreqGroup.FR_DAY + if FreqGroup.FR_HR <= base <= FreqGroup.FR_SEC: return FreqGroup.FR_SEC + return base @@ -57,6 +60,7 @@ def get_freq_group(freq): if isinstance(freq, basestring): base, mult = get_freq_code(freq) freq = base + return (freq // 1000) * 1000 @@ -64,28 +68,29 @@ def get_freq(freq): if isinstance(freq, basestring): base, mult = get_freq_code(freq) freq = base + return freq def get_freq_code(freqstr): """ - Parameters ---------- + freqstr : str Returns ------- + code, stride """ if isinstance(freqstr, DateOffset): freqstr = (get_offset_name(freqstr), freqstr.n) if isinstance(freqstr, tuple): - if (com.is_integer(freqstr[0]) and - com.is_integer(freqstr[1])): - # e.g., freqstr = (2000, 1) + if (com.is_integer(freqstr[0]) and com.is_integer(freqstr[1])): + #e.g., freqstr = (2000, 1) return freqstr else: - # e.g., freqstr = ('T', 5) + #e.g., freqstr = ('T', 5) try: code = _period_str_to_code(freqstr[0]) stride = freqstr[1] @@ -285,7 +290,8 @@ def _get_freq_str(base, mult=1): 'Q': 'Q', 'A': 'A', 'W': 'W', - 'M': 'M' + 'M': 'M', + 'U': 'U', } need_suffix = ['QS', 'BQ', 'BQS', 'AS', 'BA', 'BAS'] @@ -598,6 +604,7 @@ def get_standard_freq(freq): "H": 7000, # Hourly "T": 8000, # Minutely "S": 9000, # Secondly + "U": 10000, # Microsecondly } _reverse_period_code_map = {} @@ -625,6 +632,7 @@ def _period_alias_dictionary(): H_aliases = ["H", "HR", "HOUR", "HRLY", "HOURLY"] T_aliases = ["T", "MIN", "MINUTE", "MINUTELY"] S_aliases = ["S", "SEC", "SECOND", "SECONDLY"] + U_aliases = ["U", "USEC", "MICROSECOND", "MICROSECONDLY"] for k in M_aliases: alias_dict[k] = 'M' @@ -644,6 +652,9 @@ def _period_alias_dictionary(): for k in S_aliases: alias_dict[k] = 'S' + for k in U_aliases: + alias_dict[k] = 'U' + A_prefixes = ["A", "Y", "ANN", "ANNUAL", "ANNUALLY", "YR", "YEAR", "YEARLY"] @@ -711,6 +722,7 @@ def _period_alias_dictionary(): "hour": "H", "minute": "T", "second": "S", + "microsecond": "U", } @@ -1002,23 +1014,25 @@ def is_subperiod(source, target): if _is_quarterly(source): return _quarter_months_conform(_get_rule_month(source), _get_rule_month(target)) - return source in ['D', 'B', 'M', 'H', 'T', 'S'] + return source in ['D', 'B', 'M', 'H', 'T', 'S', 'U'] elif _is_quarterly(target): - return source in ['D', 'B', 'M', 'H', 'T', 'S'] + return source in ['D', 'B', 'M', 'H', 'T', 'S', 'U'] elif target == 'M': - return source in ['D', 'B', 'H', 'T', 'S'] + return source in ['D', 'B', 'H', 'T', 'S', 'U'] elif _is_weekly(target): - return source in [target, 'D', 'B', 'H', 'T', 'S'] + return source in [target, 'D', 'B', 'H', 'T', 'S', 'U'] elif target == 'B': - return source in ['B', 'H', 'T', 'S'] + return source in ['B', 'H', 'T', 'S', 'U'] elif target == 'D': - return source in ['D', 'H', 'T', 'S'] + return source in ['D', 'H', 'T', 'S', 'U'] elif target == 'H': - return source in ['H', 'T', 'S'] + return source in ['H', 'T', 'S', 'U'] elif target == 'T': - return source in ['T', 'S'] + return source in ['T', 'S', 'U'] elif target == 'S': - return source in ['S'] + return source in ['S', 'U'] + elif target == 'U': + return source == target def is_superperiod(source, target): @@ -1053,23 +1067,25 @@ def is_superperiod(source, target): smonth = _get_rule_month(source) tmonth = _get_rule_month(target) return _quarter_months_conform(smonth, tmonth) - return target in ['D', 'B', 'M', 'H', 'T', 'S'] + return target in ['D', 'B', 'M', 'H', 'T', 'S', 'U'] elif _is_quarterly(source): - return target in ['D', 'B', 'M', 'H', 'T', 'S'] + return target in ['D', 'B', 'M', 'H', 'T', 'S', 'U'] elif source == 'M': - return target in ['D', 'B', 'H', 'T', 'S'] + return target in ['D', 'B', 'H', 'T', 'S', 'U'] elif _is_weekly(source): - return target in [source, 'D', 'B', 'H', 'T', 'S'] + return target in [source, 'D', 'B', 'H', 'T', 'S', 'U'] elif source == 'B': - return target in ['D', 'B', 'H', 'T', 'S'] + return target in ['D', 'B', 'H', 'T', 'S', 'U'] elif source == 'D': - return target in ['D', 'B', 'H', 'T', 'S'] + return target in ['D', 'B', 'H', 'T', 'S', 'U'] elif source == 'H': - return target in ['H', 'T', 'S'] + return target in ['H', 'T', 'S', 'U'] elif source == 'T': - return target in ['T', 'S'] + return target in ['T', 'S', 'U'] elif source == 'S': - return target in ['S'] + return target in ['S', 'U'] + elif source == 'U': + return target == source def _get_rule_month(source, default='DEC'): diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 24594d1bea9d6..f2cf1e0d899ae 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -116,7 +116,7 @@ def __repr__(self): attrs = [] for attr in self.__dict__: if ((attr == 'kwds' and len(self.kwds) == 0) - or attr.startswith('_')): + or attr.startswith('_')): continue if attr not in exclude: attrs.append('='.join((attr, repr(getattr(self, attr))))) @@ -415,8 +415,7 @@ def apply(self, other): n = self.n wkday, days_in_month = tslib.monthrange(other.year, other.month) - lastBDay = days_in_month - max(((wkday + days_in_month - 1) - % 7) - 4, 0) + lastBDay = days_in_month - max(((wkday + days_in_month - 1) % 7) - 4, 0) if n > 0 and not other.day >= lastBDay: n = n - 1 @@ -587,7 +586,8 @@ def apply(self, other): else: months = self.n + 1 - return self.getOffsetOfMonth(other + relativedelta(months=months, day=1)) + return self.getOffsetOfMonth(other + relativedelta(months=months, + day=1)) def getOffsetOfMonth(self, dt): w = Week(weekday=self.weekday) @@ -631,8 +631,7 @@ def apply(self, other): n = self.n wkday, days_in_month = tslib.monthrange(other.year, other.month) - lastBDay = days_in_month - max(((wkday + days_in_month - 1) - % 7) - 4, 0) + lastBDay = days_in_month - max(((wkday + days_in_month - 1) % 7) - 4, 0) monthsToGo = 3 - ((other.month - self.startingMonth) % 3) if monthsToGo == 3: @@ -826,11 +825,11 @@ def apply(self, other): years = n if n > 0: if (other.month < self.month or - (other.month == self.month and other.day < lastBDay)): + (other.month == self.month and other.day < lastBDay)): years -= 1 elif n <= 0: if (other.month > self.month or - (other.month == self.month and other.day > lastBDay)): + (other.month == self.month and other.day > lastBDay)): years += 1 other = other + relativedelta(years=years) @@ -874,11 +873,11 @@ def apply(self, other): if n > 0: # roll back first for positive n if (other.month < self.month or - (other.month == self.month and other.day < first)): + (other.month == self.month and other.day < first)): years -= 1 elif n <= 0: # roll forward if (other.month > self.month or - (other.month == self.month and other.day > first)): + (other.month == self.month and other.day > first)): years += 1 # set first bday for result @@ -930,7 +929,7 @@ def _decrement(date): def _rollf(date): if (date.month != self.month or - date.day < tslib.monthrange(date.year, date.month)[1]): + date.day < tslib.monthrange(date.year, date.month)[1]): date = _increment(date) return date diff --git a/pandas/tseries/period.py b/pandas/tseries/period.py index 75decb91485ca..efd5eb5719404 100644 --- a/pandas/tseries/period.py +++ b/pandas/tseries/period.py @@ -1,12 +1,10 @@ # pylint: disable=E1101,E1103,W0232 -import operator from datetime import datetime, date import numpy as np -import pandas.tseries.offsets as offsets -from pandas.tseries.frequencies import (get_freq_code as _gfc, - _month_numbers, FreqGroup) +from pandas.tseries.frequencies import (get_freq_code as _gfc, _month_numbers, + FreqGroup) from pandas.tseries.index import DatetimeIndex, Int64Index, Index from pandas.tseries.tools import parse_time_string import pandas.tseries.frequencies as _freq_mod @@ -26,7 +24,9 @@ def _period_field_accessor(name, alias): def f(self): base, mult = _gfc(self.freq) return tslib.get_period_field(alias, self.ordinal, base) + f.__name__ = name + return property(f) @@ -34,17 +34,19 @@ def _field_accessor(name, alias): def f(self): base, mult = _gfc(self.freq) return tslib.get_period_field_arr(alias, self.values, base) + f.__name__ = name + return property(f) class Period(object): - __slots__ = ['freq', 'ordinal'] + __slots__ = 'freq', 'ordinal' def __init__(self, value=None, freq=None, ordinal=None, year=None, month=1, quarter=None, day=1, - hour=0, minute=0, second=0): + hour=0, minute=0, second=0, microsecond=0): """ Represents an period of time @@ -61,6 +63,7 @@ def __init__(self, value=None, freq=None, ordinal=None, hour : int, default 0 minute : int, default 0 second : int, default 0 + microsecond : int, default 0 """ # freq points to a tuple (base, mult); base is one of the defined # periods such as A, Q, etc. Every five minutes would be, e.g., @@ -72,8 +75,8 @@ def __init__(self, value=None, freq=None, ordinal=None, self.ordinal = None if ordinal is not None and value is not None: - raise ValueError(("Only value or ordinal but not both should be " - "given but not both")) + raise ValueError("Only value or ordinal but not both should be " + "given but not both") elif ordinal is not None: if not com.is_integer(ordinal): raise ValueError("Ordinal must be an integer") @@ -86,7 +89,8 @@ def __init__(self, value=None, freq=None, ordinal=None, raise ValueError("If value is None, freq cannot be None") self.ordinal = _ordinal_from_fields(year, month, quarter, day, - hour, minute, second, freq) + hour, minute, second, + microsecond, freq) elif isinstance(value, Period): other = value @@ -112,8 +116,8 @@ def __init__(self, value=None, freq=None, ordinal=None, if freq is None: raise ValueError('Must supply freq for datetime value') else: - msg = "Value must be Period, string, integer, or datetime" - raise ValueError(msg) + raise ValueError("Value must be Period, string, integer, or " + "datetime") base, mult = _gfc(freq) if mult != 1: @@ -122,7 +126,7 @@ def __init__(self, value=None, freq=None, ordinal=None, if self.ordinal is None: self.ordinal = tslib.period_ordinal(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, - base) + dt.microsecond, base) self.freq = _freq_mod._get_freq_str(base) @@ -168,14 +172,15 @@ def asfreq(self, freq, how='E'): resampled : Period """ how = _validate_end_alias(how) - base1, mult1 = _gfc(self.freq) + base1, _ = _gfc(self.freq) base2, mult2 = _gfc(freq) if mult2 != 1: raise ValueError('Only mult == 1 supported') - end = how == 'E' - new_ordinal = tslib.period_asfreq(self.ordinal, base1, base2, end) + hows = {'S': 'S', 'E': 'E', 'START': 'S', 'END': 'E'} + new_ordinal = tslib.period_asfreq(self.ordinal, base1, base2, + hows[how.upper()]) return Period(ordinal=new_ordinal, freq=base2) @@ -209,10 +214,10 @@ def to_timestamp(self, freq=None, how='start'): how = _validate_end_alias(how) if freq is None: - base, mult = _gfc(self.freq) + base, _ = _gfc(self.freq) freq = _freq_mod.get_to_timestamp_base(base) - base, mult = _gfc(freq) + base, _ = _gfc(freq) val = self.asfreq(freq, how) dt64 = tslib.period_ordinal_to_dt64(val.ordinal, base) @@ -224,6 +229,7 @@ def to_timestamp(self, freq=None, how='start'): hour = _period_field_accessor('hour', 5) minute = _period_field_accessor('minute', 6) second = _period_field_accessor('second', 7) + microsecond = _period_field_accessor('microsecond', 11) weekofyear = _period_field_accessor('week', 8) week = weekofyear dayofweek = _period_field_accessor('dayofweek', 10) @@ -305,6 +311,26 @@ def strftime(self, fmt): +-----------+--------------------------------+-------+ | ``%S`` | Second as a decimal number | \(4) | | | [00,61]. | | + +-----------|--------------------------------|-------+ + | ``%u`` | Microsecond as a decimal | | + | | number | | + | | [000000, 999999] | | + +-----------+--------------------------------+-------+ + | ``%u`` | Microsecond as a decimal number| | + | | [00,999999]. | | + | | | | + | | | | + | | | | + | | | | + | | | | + +-----------+--------------------------------+-------+ + | ``%u`` | Microsecond as a decimal number| | + | | [00,999999]. | | + | | | | + | | | | + | | | | + | | | | + | | | | +-----------+--------------------------------+-------+ | ``%U`` | Week number of the year | \(5) | | | (Sunday as the first day of | | @@ -407,6 +433,8 @@ def _get_date_and_freq(value, freq): freq = 'T' elif reso == 'second': freq = 'S' + elif reso == 'microsecond': + freq = 'U' else: raise ValueError("Invalid frequency or could not infer: %s" % reso) @@ -428,9 +456,8 @@ def dt64arr_to_periodarr(data, freq, tz): base, mult = _gfc(freq) return tslib.dt64arr_to_periodarr(data.view('i8'), base, tz) -# --- Period index sketch - +# --- Period index sketch def _period_index_cmp(opname): """ Wrap comparison operations to convert datetime-like to datetime64 @@ -496,6 +523,7 @@ class PeriodIndex(Int64Index): hour : int or array, default None minute : int or array, default None second : int or array, default None + microsecond : int or array, default None tz : object, default None Timezone for converting datetime64 data to Periods @@ -518,7 +546,7 @@ def __new__(cls, data=None, ordinal=None, freq=None, start=None, end=None, periods=None, copy=False, name=None, year=None, month=None, quarter=None, day=None, - hour=None, minute=None, second=None, + hour=None, minute=None, second=None, microsecond=None, tz=None): freq = _freq_mod.get_standard_freq(freq) @@ -534,7 +562,8 @@ def __new__(cls, data=None, ordinal=None, if ordinal is not None: data = np.asarray(ordinal, dtype=np.int64) else: - fields = [year, month, quarter, day, hour, minute, second] + fields = [year, month, quarter, day, hour, minute, second, + microsecond] data, freq = cls._generate_range(start, end, periods, freq, fields) else: @@ -556,10 +585,11 @@ def _generate_range(cls, start, end, periods, freq, fields): 'or endpoints, but not both') subarr, freq = _get_ordinal_range(start, end, periods, freq) elif field_count > 0: - y, mth, q, d, h, minute, s = fields + y, mth, q, d, h, minute, s, us = fields subarr, freq = _range_from_fields(year=y, month=mth, quarter=q, day=d, hour=h, minute=minute, - second=s, freq=freq) + second=s, microsecond=us, + freq=freq) else: raise ValueError('Not enough parameters to construct ' 'Period range') @@ -604,7 +634,7 @@ def _from_arraylike(cls, data, freq, tz): base1, _ = _gfc(data.freq) base2, _ = _gfc(freq) data = tslib.period_asfreq_arr(data.values, base1, - base2, 1) + base2, 'E') else: if freq is None and len(data) > 0: freq = getattr(data[0], 'freq', None) @@ -643,9 +673,14 @@ def _box_values(self, values): def asof_locs(self, where, mask): """ + Parameters + ---------- where : array of timestamps mask : array of booleans where data is not NA + Returns + ------- + result : array_like """ where_idx = where if isinstance(where_idx, DatetimeIndex): @@ -718,14 +753,15 @@ def asfreq(self, freq=None, how='E'): freq = _freq_mod.get_standard_freq(freq) - base1, mult1 = _gfc(self.freq) + base1, _ = _gfc(self.freq) base2, mult2 = _gfc(freq) if mult2 != 1: raise ValueError('Only mult == 1 supported') - end = how == 'E' - new_data = tslib.period_asfreq_arr(self.values, base1, base2, end) + hows = {'S': 'S', 'E': 'E', 'START': 'S', 'END': 'E'} + new_data = tslib.period_asfreq_arr(self.values, base1, base2, + hows[how.upper()]) result = new_data.view(PeriodIndex) result.name = self.name @@ -741,6 +777,7 @@ def to_datetime(self, dayfirst=False): hour = _field_accessor('hour', 5) minute = _field_accessor('minute', 6) second = _field_accessor('second', 7) + microsecond = _field_accessor('microsecond', 11) weekofyear = _field_accessor('week', 8) week = weekofyear dayofweek = _field_accessor('dayofweek', 10) @@ -786,10 +823,10 @@ def to_timestamp(self, freq=None, how='start'): how = _validate_end_alias(how) if freq is None: - base, mult = _gfc(self.freq) + base, _ = _gfc(self.freq) freq = _freq_mod.get_to_timestamp_base(base) - base, mult = _gfc(freq) + base, _ = _gfc(freq) new_data = self.asfreq(freq, how) new_data = tslib.periodarr_to_dt64arr(new_data.values, base) @@ -835,7 +872,7 @@ def get_value(self, series, key): return super(PeriodIndex, self).get_value(series, key) except (KeyError, IndexError): try: - asdt, parsed, reso = parse_time_string(key, self.freq) + asdt, _, reso = parse_time_string(key, self.freq) grp = _freq_mod._infer_period_group(reso) freqn = _freq_mod._period_group(self.freq) @@ -876,7 +913,7 @@ def get_loc(self, key): return self._engine.get_loc(key) except KeyError: try: - asdt, parsed, reso = parse_time_string(key, self.freq) + asdt, _, _ = parse_time_string(key, self.freq) key = asdt except TypeError: pass @@ -1108,16 +1145,23 @@ def _get_ordinal_range(start, end, periods, freq): return data, freq -def _range_from_fields(year=None, month=None, quarter=None, day=None, - hour=None, minute=None, second=None, freq=None): +def _range_from_fields(year=None, month=None, quarter=None, day=None, hour=None, + minute=None, second=None, microsecond=None, freq=None): + + if day is None: + day = 1 + if hour is None: hour = 0 + if minute is None: minute = 0 + if second is None: second = 0 - if day is None: - day = 1 + + if microsecond is None: + microsecond = 0 ordinals = [] @@ -1134,17 +1178,18 @@ def _range_from_fields(year=None, month=None, quarter=None, day=None, year, quarter = _make_field_arrays(year, quarter) for y, q in zip(year, quarter): y, m = _quarter_to_myear(y, q, freq) - val = tslib.period_ordinal(y, m, 1, 1, 1, 1, base) + val = tslib.period_ordinal(y, m, 1, 1, 1, 1, 1, base) ordinals.append(val) else: base, mult = _gfc(freq) if mult != 1: raise ValueError('Only mult == 1 supported') - arrays = _make_field_arrays(year, month, day, hour, minute, second) - for y, mth, d, h, mn, s in zip(*arrays): - ordinals.append(tslib.period_ordinal(y, mth, d, h, mn, s, base)) - + arrays = _make_field_arrays(year, month, day, hour, minute, second, + microsecond) + for y, mth, d, h, mn, s, us in zip(*arrays): + ordinals.append(tslib.period_ordinal(y, mth, d, h, mn, s, us, + base)) return np.array(ordinals, dtype=np.int64), freq @@ -1164,7 +1209,7 @@ def _make_field_arrays(*fields): def _ordinal_from_fields(year, month, quarter, day, hour, minute, - second, freq): + second, microsecond, freq): base, mult = _gfc(freq) if mult != 1: raise ValueError('Only mult == 1 supported') @@ -1172,7 +1217,8 @@ def _ordinal_from_fields(year, month, quarter, day, hour, minute, if quarter is not None: year, month = _quarter_to_myear(year, quarter, freq) - return tslib.period_ordinal(year, month, day, hour, minute, second, base) + return tslib.period_ordinal(year, month, day, hour, minute, second, + microsecond, base) def _quarter_to_myear(year, quarter, freq): diff --git a/pandas/tseries/tests/test_frequencies.py b/pandas/tseries/tests/test_frequencies.py index aad831ae48a64..fd078dcdb7da9 100644 --- a/pandas/tseries/tests/test_frequencies.py +++ b/pandas/tseries/tests/test_frequencies.py @@ -1,7 +1,6 @@ -from datetime import datetime, time, timedelta -import sys -import os +from datetime import datetime, timedelta import unittest +from unittest import TestCase import nose @@ -9,13 +8,12 @@ from pandas import Index, DatetimeIndex, date_range, period_range -from pandas.tseries.frequencies import to_offset, infer_freq +from pandas.tseries.frequencies import (to_offset, infer_freq, Resolution, + get_reso_string) from pandas.tseries.tools import to_datetime import pandas.tseries.frequencies as fmod import pandas.tseries.offsets as offsets -import pandas.lib as lib - def test_to_offset_multiple(): freqstr = '2h30min' @@ -253,7 +251,30 @@ def test_is_superperiod_subperiod(): assert(fmod.is_superperiod(offsets.Hour(), offsets.Minute())) assert(fmod.is_subperiod(offsets.Minute(), offsets.Hour())) + +class TestResolution(TestCase): + def test_resolution(self): + resos = 'microsecond', 'second', 'minute', 'hour', 'day' + + for i, r in enumerate(resos): + s = Resolution.get_str(i) + self.assertEqual(s, r) + + self.assertEqual(Resolution.get_str(None), 'day') + + def test_get_reso_string(self): + resos = 'microsecond', 'second', 'minute', 'hour', 'day' + + for i, r in enumerate(resos): + s = Resolution.get_str(i) + self.assertEqual(s, r) + self.assertEqual(get_reso_string(i), s) + + self.assertEqual(Resolution.get_str(None), 'day') + self.assertEqual(get_reso_string(None), 'day') + + if __name__ == '__main__': import nose - nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'], + nose.runmodule(argv=[__file__,'-vvs','-x','--pdb', '--pdb-failure'], exit=False) diff --git a/pandas/tseries/tests/test_period.py b/pandas/tseries/tests/test_period.py index 22264a5613922..5119e94d6ea9d 100644 --- a/pandas/tseries/tests/test_period.py +++ b/pandas/tseries/tests/test_period.py @@ -22,7 +22,7 @@ import pandas.core.datetools as datetools import pandas as pd import numpy as np -randn = np.random.randn +from numpy.random import randn from pandas import Series, TimeSeries, DataFrame from pandas.util.testing import assert_series_equal, assert_almost_equal @@ -93,7 +93,7 @@ def test_period_constructor(self): i4 = Period('2005', freq='M') i5 = Period('2005', freq='m') - self.assert_(i1 != i4) + self.assertNotEqual(i1, i4) self.assertEquals(i4, i5) i1 = Period.now('Q') @@ -183,9 +183,13 @@ def test_period_constructor(self): i2 = Period(datetime(2007, 1, 1), freq='M') self.assertEqual(i1, i2) - self.assertRaises(ValueError, Period, ordinal=200701) + i1 = Period(date(2007, 1, 1), freq='U') + i2 = Period(datetime(2007, 1, 1), freq='U') + self.assertEqual(i1, i2) - self.assertRaises(KeyError, Period, '2007-1-1', freq='U') + # errors + self.assertRaises(ValueError, Period, ordinal=200701) + self.assertRaises(KeyError, Period, '2007-1-1', freq='L') def test_freq_str(self): i1 = Period('1982', freq='Min') @@ -200,8 +204,12 @@ def test_repr(self): def test_strftime(self): p = Period('2000-1-1 12:34:12', freq='S') - self.assert_(p.strftime('%Y-%m-%d %H:%M:%S') == - '2000-01-01 12:34:12') + s = p.strftime('%Y-%m-%d %H:%M:%S') + self.assertEqual(s, '2000-01-01 12:34:12') + + p = Period('2001-1-1 12:34:12', freq='U') + s = p.strftime('%Y-%m-%d %H:%M:%S.%u') + self.assertEqual(s, '2001-01-01 12:34:12.000000') def test_sub_delta(self): left, right = Period('2011', freq='A'), Period('2007', freq='A') @@ -223,13 +231,12 @@ def test_to_timestamp(self): for a in aliases: self.assertEquals(end_ts, p.to_timestamp('D', how=a)) - from_lst = ['A', 'Q', 'M', 'W', 'B', - 'D', 'H', 'Min', 'S'] + from_lst = 'A', 'Q', 'M', 'W', 'B', 'D', 'H', 'Min', 'S', 'U' def _ex(p): return Timestamp((p + 1).start_time.value - 1) - for i, fcode in enumerate(from_lst): + for fcode in from_lst: p = Period('1982', freq=fcode) result = p.to_timestamp().to_period(fcode) self.assertEquals(result, p) @@ -254,22 +261,26 @@ def _ex(p): expected = datetime(1985, 12, 31) self.assertEquals(result, expected) - expected = datetime(1985, 1, 1) - result = p.to_timestamp('H', how='start') - self.assertEquals(result, expected) - result = p.to_timestamp('T', how='start') - self.assertEquals(result, expected) - result = p.to_timestamp('S', how='start') + result = p.to_timestamp('U', how='end') + expected = datetime(1985, 12, 31, 23, 59, 59, 999999) self.assertEquals(result, expected) + expected = datetime(1985, 1, 1) + + for freq in ('H', 'T', 'S', 'U'): + result = p.to_timestamp(freq, how='start') + self.assertEquals(result, expected) + self.assertRaises(ValueError, p.to_timestamp, '5t') def test_start_time(self): - freq_lst = ['A', 'Q', 'M', 'D', 'H', 'T', 'S'] + freq_lst = 'A', 'Q', 'M', 'D', 'H', 'T', 'S', 'U' xp = datetime(2012, 1, 1) + for f in freq_lst: p = Period('2012', freq=f) self.assertEquals(p.start_time, xp) + self.assertEquals(Period('2012', freq='B').start_time, datetime(2011, 12, 30)) self.assertEquals(Period('2012', freq='W').start_time, @@ -278,8 +289,8 @@ def test_start_time(self): def test_end_time(self): p = Period('2012', freq='A') - def _ex(*args): - return Timestamp(Timestamp(datetime(*args)).value - 1) + def _ex(*args, **kwargs): + return Timestamp(Timestamp(datetime(*args, **kwargs)).value - 1) xp = _ex(2013, 1, 1) self.assertEquals(xp, p.end_time) @@ -300,6 +311,18 @@ def _ex(*args): p = Period('2012', freq='H') self.assertEquals(p.end_time, xp) + xp = _ex(2012, 1, 1, hour=0, minute=1) + p = Period('2012', freq='T') + self.assertEquals(p.end_time, xp) + + xp = _ex(2012, 1, 1, hour=0, minute=0, second=1) + p = Period('2012', freq='S') + self.assertEquals(p.end_time, xp) + + xp = _ex(2012, 1, 1, hour=0, minute=0, second=0, microsecond=1) + p = Period('2012', freq='U') + self.assertEquals(p.end_time, xp) + xp = _ex(2012, 1, 2) self.assertEquals(Period('2012', freq='B').end_time, xp) @@ -336,7 +359,7 @@ def test_properties_monthly(self): assert_equal(m_ival_x.quarter, 3) elif 10 <= x + 1 <= 12: assert_equal(m_ival_x.quarter, 4) - assert_equal(m_ival_x.month, x + 1) + assert_equal(m_ival_x.month, x + 1) def test_properties_weekly(self): # Test properties on Periods with daily frequency. @@ -409,6 +432,21 @@ def test_properties_secondly(self): assert_equal(s_date.minute, 0) assert_equal(s_date.second, 0) + def test_properties_microsecondly(self): + u_date = Period(freq='U', year=2007, month=1, day=1, hour=0, minute=40, + second=5, microsecond=10) + # + assert_equal(u_date.year, 2007) + assert_equal(u_date.quarter, 1) + assert_equal(u_date.month, 1) + assert_equal(u_date.day, 1) + assert_equal(u_date.weekday, 0) + assert_equal(u_date.dayofyear, 1) + assert_equal(u_date.hour, 0) + assert_equal(u_date.minute, 40) + assert_equal(u_date.second, 5) + assert_equal(u_date.microsecond, 10) + def test_pnow(self): dt = datetime.now() @@ -436,23 +474,24 @@ def test_constructor_corner(self): def test_constructor_infer_freq(self): p = Period('2007-01-01') - self.assert_(p.freq == 'D') + self.assertEqual(p.freq, 'D') p = Period('2007-01-01 07') - self.assert_(p.freq == 'H') + self.assertEqual(p.freq, 'H') p = Period('2007-01-01 07:10') - self.assert_(p.freq == 'T') + self.assertEqual(p.freq, 'T') p = Period('2007-01-01 07:10:15') - self.assert_(p.freq == 'S') + self.assertEqual(p.freq, 'S') - self.assertRaises(ValueError, Period, '2007-01-01 07:10:15.123456') + p = Period('2007-01-01 07:10:15.123456') + self.assertEqual(p.freq, 'U') def test_comparisons(self): p = Period('2007-01-01') self.assertEquals(p, p) - self.assert_(not p == 1) + self.assertNotEqual(p, 1) def noWrap(item): @@ -500,6 +539,11 @@ def test_conv_annual(self): hour=0, minute=0, second=0) ival_A_to_S_end = Period(freq='S', year=2007, month=12, day=31, hour=23, minute=59, second=59) + ival_A_to_U_start = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=0, microsecond=0) + ival_A_to_U_end = Period(freq='U', year=2007, month=12, day=31, + hour=23, minute=59, second=59, + microsecond=999999) ival_AJAN_to_D_end = Period(freq='D', year=2007, month=1, day=31) ival_AJAN_to_D_start = Period(freq='D', year=2006, month=2, day=1) @@ -526,6 +570,8 @@ def test_conv_annual(self): assert_equal(ival_A.asfreq('T', 'E'), ival_A_to_T_end) assert_equal(ival_A.asfreq('S', 'S'), ival_A_to_S_start) assert_equal(ival_A.asfreq('S', 'E'), ival_A_to_S_end) + assert_equal(ival_A.asfreq('U', 'S'), ival_A_to_U_start) + assert_equal(ival_A.asfreq('U', 'E'), ival_A_to_U_end) assert_equal(ival_AJAN.asfreq('D', 'S'), ival_AJAN_to_D_start) assert_equal(ival_AJAN.asfreq('D', 'E'), ival_AJAN_to_D_end) @@ -568,6 +614,11 @@ def test_conv_quarterly(self): hour=0, minute=0, second=0) ival_Q_to_S_end = Period(freq='S', year=2007, month=3, day=31, hour=23, minute=59, second=59) + ival_Q_to_U_start = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=0, microsecond=0) + ival_Q_to_U_end = Period(freq='U', year=2007, month=3, day=31, + hour=23, minute=59, second=59, + microsecond=999999) ival_QEJAN_to_D_start = Period(freq='D', year=2006, month=2, day=1) ival_QEJAN_to_D_end = Period(freq='D', year=2006, month=4, day=30) @@ -592,6 +643,8 @@ def test_conv_quarterly(self): assert_equal(ival_Q.asfreq('Min', 'E'), ival_Q_to_T_end) assert_equal(ival_Q.asfreq('S', 'S'), ival_Q_to_S_start) assert_equal(ival_Q.asfreq('S', 'E'), ival_Q_to_S_end) + assert_equal(ival_Q.asfreq('U', 'S'), ival_Q_to_U_start) + assert_equal(ival_Q.asfreq('U', 'E'), ival_Q_to_U_end) assert_equal(ival_QEJAN.asfreq('D', 'S'), ival_QEJAN_to_D_start) assert_equal(ival_QEJAN.asfreq('D', 'E'), ival_QEJAN_to_D_end) @@ -626,6 +679,11 @@ def test_conv_monthly(self): hour=0, minute=0, second=0) ival_M_to_S_end = Period(freq='S', year=2007, month=1, day=31, hour=23, minute=59, second=59) + ival_M_to_U_start = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=0, microsecond=0) + ival_M_to_U_end = Period(freq='U', year=2007, month=1, day=31, + hour=23, minute=59, second=59, + microsecond=999999) assert_equal(ival_M.asfreq('A'), ival_M_to_A) assert_equal(ival_M_end_of_year.asfreq('A'), ival_M_to_A) @@ -644,6 +702,8 @@ def test_conv_monthly(self): assert_equal(ival_M.asfreq('Min', 'E'), ival_M_to_T_end) assert_equal(ival_M.asfreq('S', 'S'), ival_M_to_S_start) assert_equal(ival_M.asfreq('S', 'E'), ival_M_to_S_end) + assert_equal(ival_M.asfreq('U', 'S'), ival_M_to_U_start) + assert_equal(ival_M.asfreq('U', 'E'), ival_M_to_U_end) assert_equal(ival_M.asfreq('M'), ival_M) @@ -715,6 +775,11 @@ def test_conv_weekly(self): hour=0, minute=0, second=0) ival_W_to_S_end = Period(freq='S', year=2007, month=1, day=7, hour=23, minute=59, second=59) + ival_W_to_U_start = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=0, microsecond=0) + ival_W_to_U_end = Period(freq='U', year=2007, month=1, day=7, + hour=23, minute=59, second=59, + microsecond=999999) assert_equal(ival_W.asfreq('A'), ival_W_to_A) assert_equal(ival_W_end_of_year.asfreq('A'), @@ -754,6 +819,9 @@ def test_conv_weekly(self): assert_equal(ival_W.asfreq('S', 'S'), ival_W_to_S_start) assert_equal(ival_W.asfreq('S', 'E'), ival_W_to_S_end) + assert_equal(ival_W.asfreq('U', 'S'), ival_W_to_U_start) + assert_equal(ival_W.asfreq('U', 'E'), ival_W_to_U_end) + assert_equal(ival_W.asfreq('WK'), ival_W) def test_conv_business(self): @@ -782,6 +850,11 @@ def test_conv_business(self): hour=0, minute=0, second=0) ival_B_to_S_end = Period(freq='S', year=2007, month=1, day=1, hour=23, minute=59, second=59) + ival_B_to_U_start = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=0, microsecond=0) + ival_B_to_U_end = Period(freq='U', year=2007, month=1, day=1, + hour=23, minute=59, second=59, + microsecond=999999) assert_equal(ival_B.asfreq('A'), ival_B_to_A) assert_equal(ival_B_end_of_year.asfreq('A'), ival_B_to_A) @@ -800,6 +873,8 @@ def test_conv_business(self): assert_equal(ival_B.asfreq('Min', 'E'), ival_B_to_T_end) assert_equal(ival_B.asfreq('S', 'S'), ival_B_to_S_start) assert_equal(ival_B.asfreq('S', 'E'), ival_B_to_S_end) + assert_equal(ival_B.asfreq('U', 'S'), ival_B_to_U_start) + assert_equal(ival_B.asfreq('U', 'E'), ival_B_to_U_end) assert_equal(ival_B.asfreq('B'), ival_B) @@ -845,6 +920,11 @@ def test_conv_daily(self): hour=0, minute=0, second=0) ival_D_to_S_end = Period(freq='S', year=2007, month=1, day=1, hour=23, minute=59, second=59) + ival_D_to_U_start = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=0, microsecond=0) + ival_D_to_U_end = Period(freq='U', year=2007, month=1, day=1, + hour=23, minute=59, second=59, + microsecond=999999) assert_equal(ival_D.asfreq('A'), ival_D_to_A) @@ -871,12 +951,17 @@ def test_conv_daily(self): assert_equal(ival_D_sunday.asfreq('B', 'S'), ival_B_friday) assert_equal(ival_D_sunday.asfreq('B', 'E'), ival_B_monday) + assert_equal(ival_D_monday.asfreq('B', 'S'), ival_B_monday) + assert_equal(ival_D_monday.asfreq('B', 'E'), ival_B_monday) + assert_equal(ival_D.asfreq('H', 'S'), ival_D_to_H_start) assert_equal(ival_D.asfreq('H', 'E'), ival_D_to_H_end) assert_equal(ival_D.asfreq('Min', 'S'), ival_D_to_T_start) assert_equal(ival_D.asfreq('Min', 'E'), ival_D_to_T_end) assert_equal(ival_D.asfreq('S', 'S'), ival_D_to_S_start) assert_equal(ival_D.asfreq('S', 'E'), ival_D_to_S_end) + assert_equal(ival_D.asfreq('U', 'S'), ival_D_to_U_start) + assert_equal(ival_D.asfreq('U', 'E'), ival_D_to_U_end) assert_equal(ival_D.asfreq('D'), ival_D) @@ -912,6 +997,10 @@ def test_conv_hourly(self): hour=0, minute=0, second=0) ival_H_to_S_end = Period(freq='S', year=2007, month=1, day=1, hour=0, minute=59, second=59) + ival_H_to_U_start = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=0, microsecond=0) + ival_H_to_U_end = Period(freq='U', year=2007, month=1, day=1, hour=0, + minute=59, second=59, microsecond=999999) assert_equal(ival_H.asfreq('A'), ival_H_to_A) assert_equal(ival_H_end_of_year.asfreq('A'), ival_H_to_A) @@ -928,16 +1017,20 @@ def test_conv_hourly(self): assert_equal(ival_H.asfreq('Min', 'S'), ival_H_to_T_start) assert_equal(ival_H.asfreq('Min', 'E'), ival_H_to_T_end) + assert_equal(ival_H.asfreq('S', 'S'), ival_H_to_S_start) assert_equal(ival_H.asfreq('S', 'E'), ival_H_to_S_end) + assert_equal(ival_H.asfreq('U', 'S'), ival_H_to_U_start) + assert_equal(ival_H.asfreq('U', 'E'), ival_H_to_U_end) + assert_equal(ival_H.asfreq('H'), ival_H) def test_conv_minutely(self): # frequency conversion tests: from Minutely Frequency" - ival_T = Period(freq='Min', year=2007, month=1, day=1, - hour=0, minute=0) + ival_T = Period(freq='Min', year=2007, month=1, day=1, hour=0, + minute=0) ival_T_end_of_year = Period(freq='Min', year=2007, month=12, day=31, hour=23, minute=59) ival_T_end_of_quarter = Period(freq='Min', year=2007, month=3, day=31, @@ -965,6 +1058,11 @@ def test_conv_minutely(self): hour=0, minute=0, second=0) ival_T_to_S_end = Period(freq='S', year=2007, month=1, day=1, hour=0, minute=0, second=59) + ival_T_to_U_start = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=0, microsecond=0) + ival_T_to_U_end = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=59, + microsecond=999999) assert_equal(ival_T.asfreq('A'), ival_T_to_A) assert_equal(ival_T_end_of_year.asfreq('A'), ival_T_to_A) @@ -984,6 +1082,9 @@ def test_conv_minutely(self): assert_equal(ival_T.asfreq('S', 'S'), ival_T_to_S_start) assert_equal(ival_T.asfreq('S', 'E'), ival_T_to_S_end) + assert_equal(ival_T.asfreq('U', 'S'), ival_T_to_U_start) + assert_equal(ival_T.asfreq('U', 'E'), ival_T_to_U_end) + assert_equal(ival_T.asfreq('Min'), ival_T) def test_conv_secondly(self): @@ -992,21 +1093,32 @@ def test_conv_secondly(self): ival_S = Period(freq='S', year=2007, month=1, day=1, hour=0, minute=0, second=0) ival_S_end_of_year = Period(freq='S', year=2007, month=12, day=31, - hour=23, minute=59, second=59) + hour=23, minute=59, second=59, + microsecond=999999) ival_S_end_of_quarter = Period(freq='S', year=2007, month=3, day=31, - hour=23, minute=59, second=59) + hour=23, minute=59, second=59, + microsecond=999999) ival_S_end_of_month = Period(freq='S', year=2007, month=1, day=31, - hour=23, minute=59, second=59) + hour=23, minute=59, second=59, + microsecond=999999) ival_S_end_of_week = Period(freq='S', year=2007, month=1, day=7, - hour=23, minute=59, second=59) + hour=23, minute=59, second=59, + microsecond=999999) ival_S_end_of_day = Period(freq='S', year=2007, month=1, day=1, - hour=23, minute=59, second=59) + hour=23, minute=59, second=59, + microsecond=999999) ival_S_end_of_bus = Period(freq='S', year=2007, month=1, day=1, - hour=23, minute=59, second=59) + hour=23, minute=59, second=59, + microsecond=999999) ival_S_end_of_hour = Period(freq='S', year=2007, month=1, day=1, - hour=0, minute=59, second=59) + hour=0, minute=59, second=59, + microsecond=999999) ival_S_end_of_minute = Period(freq='S', year=2007, month=1, day=1, - hour=0, minute=0, second=59) + hour=0, minute=0, second=59, + microsecond=999999) + ival_S_end_of_second = Period(freq='S', year=2007, month=1, day=1, + hour=0, minute=0, second=0, + microsecond=999999) ival_S_to_A = Period(freq='A', year=2007) ival_S_to_Q = Period(freq='Q', year=2007, quarter=1) @@ -1014,30 +1126,114 @@ def test_conv_secondly(self): ival_S_to_W = Period(freq='WK', year=2007, month=1, day=7) ival_S_to_D = Period(freq='D', year=2007, month=1, day=1) ival_S_to_B = Period(freq='B', year=2007, month=1, day=1) - ival_S_to_H = Period(freq='H', year=2007, month=1, day=1, - hour=0) - ival_S_to_T = Period(freq='Min', year=2007, month=1, day=1, - hour=0, minute=0) + ival_S_to_H = Period(freq='H', year=2007, month=1, day=1, hour=0) + ival_S_to_T = Period(freq='Min', year=2007, month=1, day=1, hour=0, + minute=0) + ival_S_to_U = Period(freq='U', year=2007, month=1, day=1, hour=0, + minute=0, second=0, microsecond=999999) + + ival_S_to_U_start = Period(freq='U', year=2007, month=1, day=1, hour=0, + minute=0, second=0, microsecond=0) + ival_S_to_U_end = Period(freq='U', year=2007, month=1, day=1, hour=0, + minute=0, second=0, microsecond=999999) assert_equal(ival_S.asfreq('A'), ival_S_to_A) assert_equal(ival_S_end_of_year.asfreq('A'), ival_S_to_A) + assert_equal(ival_S.asfreq('Q'), ival_S_to_Q) assert_equal(ival_S_end_of_quarter.asfreq('Q'), ival_S_to_Q) + assert_equal(ival_S.asfreq('M'), ival_S_to_M) assert_equal(ival_S_end_of_month.asfreq('M'), ival_S_to_M) + assert_equal(ival_S.asfreq('WK'), ival_S_to_W) assert_equal(ival_S_end_of_week.asfreq('WK'), ival_S_to_W) + assert_equal(ival_S.asfreq('D'), ival_S_to_D) assert_equal(ival_S_end_of_day.asfreq('D'), ival_S_to_D) + assert_equal(ival_S.asfreq('B'), ival_S_to_B) assert_equal(ival_S_end_of_bus.asfreq('B'), ival_S_to_B) + assert_equal(ival_S.asfreq('H'), ival_S_to_H) assert_equal(ival_S_end_of_hour.asfreq('H'), ival_S_to_H) + assert_equal(ival_S.asfreq('Min'), ival_S_to_T) assert_equal(ival_S_end_of_minute.asfreq('Min'), ival_S_to_T) + assert_equal(ival_S.asfreq('U'), ival_S_to_U) + assert_equal(ival_S_end_of_second.asfreq('U'), ival_S_to_U) + + assert_equal(ival_S.asfreq('U', 'S'), ival_S_to_U_start) + assert_equal(ival_S.asfreq('U', 'E'), ival_S_to_U_end) + assert_equal(ival_S.asfreq('S'), ival_S) + def test_conv_microsecondly(self): + ival_U = Period(freq='U', year=2007, month=1, day=1, hour=0, minute=0, + second=0, microsecond=0) + ival_U_end_of_year = Period(freq='U', year=2007, month=12, day=31, + hour=23, minute=59, second=59, + microsecond=999999) + ival_U_end_of_quarter = Period(freq='U', year=2007, month=3, day=31, + hour=23, minute=59, second=59, + microsecond=999999) + ival_U_end_of_month = Period(freq='U', year=2007, month=1, day=31, + hour=23, minute=59, second=59, + microsecond=999999) + ival_U_end_of_week = Period(freq='U', year=2007, month=1, day=7, + hour=23, minute=59, second=59, + microsecond=999999) + ival_U_end_of_day = Period(freq='U', year=2007, month=1, day=1, + hour=23, minute=59, second=59, + microsecond=999999) + ival_U_end_of_bus = Period(freq='U', year=2007, month=1, day=1, + hour=23, minute=59, second=59, + microsecond=999999) + ival_U_end_of_hour = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=59, second=59, + microsecond=999999) + ival_U_end_of_minute = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=59, + microsecond=999999) + ival_U_end_of_second = Period(freq='U', year=2007, month=1, day=1, + hour=0, minute=0, second=0, + microsecond=999999) + + ival_U_to_A = Period(freq='A', year=2007) + ival_U_to_Q = Period(freq='Q', year=2007, quarter=1) + ival_U_to_M = Period(freq='M', year=2007, month=1) + ival_U_to_W = Period(freq='WK', year=2007, month=1, day=7) + ival_U_to_D = Period(freq='D', year=2007, month=1, day=1) + ival_U_to_B = Period(freq='B', year=2007, month=1, day=1) + ival_U_to_H = Period(freq='H', year=2007, month=1, day=1, hour=0) + ival_U_to_T = Period(freq='Min', year=2007, month=1, day=1, hour=0, + minute=0) + ival_U_to_S = Period(freq='S', year=2007, month=1, day=1, hour=0, + minute=0, second=0) + + assert_equal(ival_U.asfreq('A'), ival_U_to_A) + assert_equal(ival_U.asfreq('Q'), ival_U_to_Q) + assert_equal(ival_U.asfreq('M'), ival_U_to_M) + assert_equal(ival_U.asfreq('WK'), ival_U_to_W) + assert_equal(ival_U.asfreq('D'), ival_U_to_D) + assert_equal(ival_U.asfreq('B'), ival_U_to_B) + assert_equal(ival_U.asfreq('H', 'S'), ival_U_to_H) + assert_equal(ival_U.asfreq('Min', 'S'), ival_U_to_T) + assert_equal(ival_U.asfreq('S'), ival_U_to_S) + + assert_equal(ival_U_end_of_year.asfreq('A'), ival_U_to_A) + assert_equal(ival_U_end_of_quarter.asfreq('Q'), ival_U_to_Q) + assert_equal(ival_U_end_of_month.asfreq('M'), ival_U_to_M) + assert_equal(ival_U_end_of_week.asfreq('WK'), ival_U_to_W) + assert_equal(ival_U_end_of_day.asfreq('D'), ival_U_to_D) + assert_equal(ival_U_end_of_bus.asfreq('B'), ival_U_to_B) + assert_equal(ival_U_end_of_hour.asfreq('H', 'S'), ival_U_to_H) + assert_equal(ival_U_end_of_minute.asfreq('Min', 'S'), ival_U_to_T) + assert_equal(ival_U_end_of_second.asfreq('S'), ival_U_to_S) + + assert_equal(ival_U.asfreq('U'), ival_U) + class TestPeriodIndex(TestCase): def __init__(self, *args, **kwds): @@ -1074,9 +1270,8 @@ def test_constructor_field_arrays(self): expected = period_range('1990Q3', '2009Q2', freq='Q-DEC') self.assert_(index.equals(expected)) - self.assertRaises( - ValueError, PeriodIndex, year=years, quarter=quarters, - freq='2Q-DEC') + self.assertRaises(ValueError, PeriodIndex, year=years, + quarter=quarters, freq='2Q-DEC') index = PeriodIndex(year=years, quarter=quarters) self.assert_(index.equals(expected)) @@ -1097,9 +1292,10 @@ def test_constructor_field_arrays(self): self.assert_(idx.equals(exp)) def test_constructor_U(self): - # U was used as undefined period - self.assertRaises(KeyError, period_range, '2007-1-1', periods=500, - freq='U') + pass + # # U was used as undefined period + # self.assertRaises(KeyError, period_range, '2007-1-1', periods=500, + # freq='U') def test_constructor_arrays_negative_year(self): years = np.arange(1960, 2000).repeat(4) @@ -1217,8 +1413,8 @@ def test_sub(self): self.assert_(result.equals(exp)) def test_periods_number_check(self): - self.assertRaises( - ValueError, period_range, '2011-1-1', '2012-1-1', 'B') + self.assertRaises(ValueError, period_range, '2011-1-1', '2012-1-1', + 'B') def test_to_timestamp(self): index = PeriodIndex(freq='A', start='1/1/2001', end='12/1/2009') @@ -1252,6 +1448,12 @@ def _get_with_delta(delta, freq='A-DEC'): exp_index = _get_with_delta(delta) self.assert_(result.index.equals(exp_index)) + result = series.to_timestamp('U', 'end') + delta = timedelta(hours=23, minutes=59, seconds=59, + microseconds=999999) + exp_index = _get_with_delta(delta) + self.assert_(result.index.equals(exp_index)) + self.assertRaises(ValueError, index.to_timestamp, '5t') index = PeriodIndex(freq='H', start='1/1/2001', end='1/2/2001') @@ -1361,6 +1563,12 @@ def _get_with_delta(delta, freq='A-DEC'): exp_index = _get_with_delta(delta) self.assert_(result.index.equals(exp_index)) + result = df.to_timestamp('U', 'end') + delta = timedelta(hours=23, minutes=59, seconds=59, + microseconds=999999) + exp_index = _get_with_delta(delta) + self.assert_(result.index.equals(exp_index)) + # columns df = df.T @@ -1388,6 +1596,12 @@ def _get_with_delta(delta, freq='A-DEC'): exp_index = _get_with_delta(delta) self.assert_(result.columns.equals(exp_index)) + result = df.to_timestamp('U', 'end', axis=1) + delta = timedelta(hours=23, minutes=59, seconds=59, + microseconds=999999) + exp_index = _get_with_delta(delta) + self.assert_(result.columns.equals(exp_index)) + # invalid axis self.assertRaises(ValueError, df.to_timestamp, axis=2) @@ -1435,6 +1649,11 @@ def test_constructor(self): pi = PeriodIndex(freq='S', start='1/1/2001', end='1/1/2001 23:59:59') assert_equal(len(pi), 24 * 60 * 60) + pi = self.assertRaises(MemoryError, PeriodIndex, freq='U', + start='1/1/2001', + end='1/1/2001 23:59:59.999999') + # assert_equal(len(pi), 24 * 60 * 60 * 1000000) + start = Period('02-Apr-2005', 'B') i1 = PeriodIndex(start=start, periods=20) assert_equal(len(i1), 20) @@ -1470,8 +1689,8 @@ def test_constructor(self): try: PeriodIndex(start=start) - raise AssertionError( - 'Must specify periods if missing start or end') + msg = 'Must specify periods if missing start or end' + raise AssertionError(msg) except ValueError: pass @@ -1524,6 +1743,12 @@ def test_shift(self): assert_equal(len(pi1), len(pi2)) assert_equal(pi1.shift(-1).values, pi2.values) + # fails on cpcloud's machine due to not enough memory + # pi1 = PeriodIndex(freq='U', start='1/1/2001', end='12/1/2009') + # pi2 = PeriodIndex(freq='U', start='12/31/2000', end='11/30/2009') + # assert_equal(len(pi1), len(pi2)) + # assert_equal(pi1.shift(-1).values, pi2.values) + def test_asfreq(self): pi1 = PeriodIndex(freq='A', start='1/1/2001', end='1/1/2001') pi2 = PeriodIndex(freq='Q', start='1/1/2001', end='1/1/2001') @@ -1532,6 +1757,8 @@ def test_asfreq(self): pi5 = PeriodIndex(freq='H', start='1/1/2001', end='1/1/2001 00:00') pi6 = PeriodIndex(freq='Min', start='1/1/2001', end='1/1/2001 00:00') pi7 = PeriodIndex(freq='S', start='1/1/2001', end='1/1/2001 00:00:00') + pi8 = PeriodIndex(freq='U', start='1/1/2001', + end='1/1/2001 00:00:00.000000') self.assertEquals(pi1.asfreq('Q', 'S'), pi2) self.assertEquals(pi1.asfreq('Q', 's'), pi2) @@ -1540,6 +1767,7 @@ def test_asfreq(self): self.assertEquals(pi1.asfreq('H', 'beGIN'), pi5) self.assertEquals(pi1.asfreq('Min', 'S'), pi6) self.assertEquals(pi1.asfreq('S', 'S'), pi7) + self.assertEquals(pi1.asfreq('U', 'S'), pi8) self.assertEquals(pi2.asfreq('A', 'S'), pi1) self.assertEquals(pi2.asfreq('M', 'S'), pi3) @@ -1547,6 +1775,7 @@ def test_asfreq(self): self.assertEquals(pi2.asfreq('H', 'S'), pi5) self.assertEquals(pi2.asfreq('Min', 'S'), pi6) self.assertEquals(pi2.asfreq('S', 'S'), pi7) + self.assertEquals(pi2.asfreq('U', 'S'), pi8) self.assertEquals(pi3.asfreq('A', 'S'), pi1) self.assertEquals(pi3.asfreq('Q', 'S'), pi2) @@ -1554,6 +1783,7 @@ def test_asfreq(self): self.assertEquals(pi3.asfreq('H', 'S'), pi5) self.assertEquals(pi3.asfreq('Min', 'S'), pi6) self.assertEquals(pi3.asfreq('S', 'S'), pi7) + self.assertEquals(pi3.asfreq('U', 'S'), pi8) self.assertEquals(pi4.asfreq('A', 'S'), pi1) self.assertEquals(pi4.asfreq('Q', 'S'), pi2) @@ -1561,6 +1791,7 @@ def test_asfreq(self): self.assertEquals(pi4.asfreq('H', 'S'), pi5) self.assertEquals(pi4.asfreq('Min', 'S'), pi6) self.assertEquals(pi4.asfreq('S', 'S'), pi7) + self.assertEquals(pi4.asfreq('U', 'S'), pi8) self.assertEquals(pi5.asfreq('A', 'S'), pi1) self.assertEquals(pi5.asfreq('Q', 'S'), pi2) @@ -1568,6 +1799,7 @@ def test_asfreq(self): self.assertEquals(pi5.asfreq('D', 'S'), pi4) self.assertEquals(pi5.asfreq('Min', 'S'), pi6) self.assertEquals(pi5.asfreq('S', 'S'), pi7) + self.assertEquals(pi5.asfreq('U', 'S'), pi8) self.assertEquals(pi6.asfreq('A', 'S'), pi1) self.assertEquals(pi6.asfreq('Q', 'S'), pi2) @@ -1575,6 +1807,7 @@ def test_asfreq(self): self.assertEquals(pi6.asfreq('D', 'S'), pi4) self.assertEquals(pi6.asfreq('H', 'S'), pi5) self.assertEquals(pi6.asfreq('S', 'S'), pi7) + self.assertEquals(pi6.asfreq('U', 'S'), pi8) self.assertEquals(pi7.asfreq('A', 'S'), pi1) self.assertEquals(pi7.asfreq('Q', 'S'), pi2) @@ -1582,6 +1815,15 @@ def test_asfreq(self): self.assertEquals(pi7.asfreq('D', 'S'), pi4) self.assertEquals(pi7.asfreq('H', 'S'), pi5) self.assertEquals(pi7.asfreq('Min', 'S'), pi6) + self.assertEquals(pi7.asfreq('U', 'S'), pi8) + + self.assertEquals(pi8.asfreq('A', 'S'), pi1) + self.assertEquals(pi8.asfreq('Q', 'S'), pi2) + self.assertEquals(pi8.asfreq('M', 'S'), pi3) + self.assertEquals(pi8.asfreq('D', 'S'), pi4) + self.assertEquals(pi8.asfreq('H', 'S'), pi5) + self.assertEquals(pi8.asfreq('Min', 'S'), pi6) + self.assertEquals(pi8.asfreq('S', 'S'), pi7) self.assertRaises(ValueError, pi7.asfreq, 'T', 'foo') self.assertRaises(ValueError, pi1.asfreq, '5t') @@ -1621,11 +1863,17 @@ def test_badinput(self): def test_negative_ordinals(self): p = Period(ordinal=-1000, freq='A') + self.assertLess(p.ordinal, 0) + self.assertEqual(p.ordinal, -1000) p = Period(ordinal=0, freq='A') + self.assertEqual(p.ordinal, 0) idx = PeriodIndex(ordinal=[-1, 0, 1], freq='A') + assert_equal(idx.values, np.array([-1, 0, 1])) + idx = PeriodIndex(ordinal=np.array([-1, 0, 1]), freq='A') + assert_equal(idx.values, np.array([-1, 0, 1])) def test_dti_to_period(self): dti = DatetimeIndex(start='1/1/2005', end='12/1/2005', freq='M') @@ -1747,7 +1995,7 @@ def test_joins(self): joined = index.join(index[:-5], how=kind) self.assert_(isinstance(joined, PeriodIndex)) - self.assert_(joined.freq == index.freq) + self.assertEqual(joined.freq, index.freq) def test_align_series(self): rng = period_range('1/1/2000', '1/1/2010', freq='A') @@ -1840,17 +2088,21 @@ def test_fields(self): self._check_all_fields(pi) pi = PeriodIndex(freq='S', start='12/31/2001 00:00:00', - end='12/31/2001 00:05:00') + end='12/31/2001 00:00:02') + self._check_all_fields(pi) + + pi = PeriodIndex(freq='U', start='12/31/2001 00:00:00.000000', + end='12/31/2001 00:00:00.000002') self._check_all_fields(pi) end_intv = Period('2006-12-31', 'W') - i1 = PeriodIndex(end=end_intv, periods=10) + pi = PeriodIndex(end=end_intv, periods=10) self._check_all_fields(pi) def _check_all_fields(self, periodindex): fields = ['year', 'month', 'day', 'hour', 'minute', 'second', 'weekofyear', 'week', 'dayofweek', - 'weekday', 'dayofyear', 'quarter', 'qyear'] + 'weekday', 'dayofyear', 'quarter', 'qyear', 'microsecond'] periods = list(periodindex) @@ -1977,13 +2229,16 @@ def test_minutely(self): def test_secondly(self): self._check_freq('S', '1970-01-01') + def test_microsecondly(self): + self._check_freq('U', '1970-01-01') + def _check_freq(self, freq, base_date): rng = PeriodIndex(start=base_date, periods=10, freq=freq) exp = np.arange(10, dtype=np.int64) self.assert_(np.array_equal(rng.values, exp)) def test_negone_ordinals(self): - freqs = ['A', 'M', 'Q', 'D', 'H', 'T', 'S'] + freqs = ['A', 'M', 'Q', 'D', 'H', 'T', 'S', 'U'] period = Period(ordinal=-1, freq='D') for freq in freqs: diff --git a/pandas/tslib.pyx b/pandas/tslib.pyx index f970ecc406c28..9bc58381346fe 100644 --- a/pandas/tslib.pyx +++ b/pandas/tslib.pyx @@ -1,15 +1,17 @@ # cython: profile=False cimport numpy as np -from numpy cimport (int32_t, int64_t, import_array, ndarray, +from numpy cimport (int32_t as i4, import_array, ndarray, NPY_INT64, NPY_DATETIME) import numpy as np +ctypedef int64_t i8 + from cpython cimport * # Cython < 0.17 doesn't have this in cpython -cdef extern from "Python.h": - cdef PyTypeObject *Py_TYPE(object) +# cdef extern from "Python.h": + # cdef int PyObject_TypeCheck(PyObject*, PyTypeObject*) from libc.stdlib cimport free @@ -37,7 +39,7 @@ PyDateTime_IMPORT # in numpy 1.7, will prob need the following: # numpy_pydatetime_import -cdef int64_t NPY_NAT = util.get_nat() +cdef i8 NPY_NAT = util.get_nat() try: @@ -45,7 +47,8 @@ try: except NameError: # py3 basestring = str -def ints_to_pydatetime(ndarray[int64_t] arr, tz=None): + +cpdef ndarray[object] ints_to_pydatetime(ndarray[i8] arr, tz=None): cdef: Py_ssize_t i, n = len(arr) pandas_datetimestruct dts @@ -84,10 +87,15 @@ def ints_to_pydatetime(ndarray[int64_t] arr, tz=None): return result + from dateutil.tz import tzlocal -def _is_tzlocal(tz): - return isinstance(tz, tzlocal) + +cpdef bint _is_tzlocal(object tz): + cdef bint isa = PyObject_TypeCheck(tz, tzlocal) + return isa + + # Python front end to C extension type _Timestamp # This serves as the box for datetime64 @@ -295,9 +303,10 @@ class NaTType(_NaT): def toordinal(self): return -1 -fields = ['year', 'quarter', 'month', 'day', 'hour', - 'minute', 'second', 'microsecond', 'nanosecond', - 'week', 'dayofyear'] +cdef tuple fields = ('year', 'quarter', 'month', 'day', 'hour', + 'minute', 'second', 'microsecond', 'nanosecond', + 'week', 'dayofyear') + for field in fields: prop = property(fget=lambda self: -1) setattr(NaTType, field, prop) @@ -307,19 +316,24 @@ NaT = NaTType() iNaT = util.get_nat() -cdef _tz_format(object obj, object zone): + +cdef object _tz_format(object obj, object zone): try: return obj.strftime(' %%Z, tz=%s' % zone) except: return ', tz=%s' % zone -def is_timestamp_array(ndarray[object] values): + +cpdef bint is_timestamp_array(ndarray[object] values): cdef int i, n = len(values) - if n == 0: + + if not n: return False + for i in range(n): if not is_timestamp(values[i]): return False + return True @@ -327,10 +341,13 @@ cpdef object get_value_box(ndarray arr, object loc): cdef: Py_ssize_t i, sz void* data_ptr + if util.is_float_object(loc): casted = int(loc) + if casted == loc: loc = casted + i = loc sz = np.PyArray_SIZE(arr) @@ -348,23 +365,27 @@ cpdef object get_value_box(ndarray arr, object loc): #---------------------------------------------------------------------- # Frequency inference -def unique_deltas(ndarray[int64_t] arr): +cpdef ndarray[i8] unique_deltas(ndarray[i8] arr): cdef: Py_ssize_t i, n = len(arr) - int64_t val + i8 val khiter_t k kh_int64_t *table int ret = 0 list uniques = [] + ndarray[i8] result table = kh_init_int64() kh_resize_int64(table, 10) + for i in range(n - 1): val = arr[i + 1] - arr[i] k = kh_get_int64(table, val) + if k == table.n_buckets: kh_put_int64(table, val, &ret) uniques.append(val) + kh_destroy_int64(table) result = np.array(uniques, dtype=np.int64) @@ -372,14 +393,14 @@ def unique_deltas(ndarray[int64_t] arr): return result -cdef inline bint _is_multiple(int64_t us, int64_t mult): +cdef inline bint _is_multiple(i8 us, i8 mult): return us % mult == 0 def apply_offset(ndarray[object] values, object offset): cdef: Py_ssize_t i, n = len(values) - ndarray[int64_t] new_values + ndarray[i8] new_values object boxed result = np.empty(n, dtype='M8[ns]') @@ -393,7 +414,7 @@ def apply_offset(ndarray[object] values, object offset): # shadows the python class, where we do any heavy lifting. cdef class _Timestamp(datetime): cdef readonly: - int64_t value, nanosecond + i8 value, nanosecond object offset # frequency reference def __hash__(self): @@ -523,7 +544,8 @@ cdef PyTypeObject* ts_type = Timestamp cdef inline bint is_timestamp(object o): - return Py_TYPE(o) == ts_type # isinstance(o, Timestamp) + cdef bint isa = PyObject_TypeCheck(o, ts_type) + return isa cdef class _NaT(_Timestamp): @@ -546,9 +568,7 @@ cdef class _NaT(_Timestamp): return False - - -def _delta_to_nanoseconds(delta): +cpdef i8 _delta_to_nanoseconds(delta): try: delta = delta.delta except: @@ -562,19 +582,21 @@ def _delta_to_nanoseconds(delta): cdef class _TSObject: cdef: pandas_datetimestruct dts # pandas_datetimestruct - int64_t value # numpy dt64 + i8 value # numpy dt64 object tzinfo property value: def __get__(self): return self.value -cpdef _get_utcoffset(tzinfo, obj): + +cpdef object _get_utcoffset(object tzinfo, object obj): try: return tzinfo._utcoffset except AttributeError: return tzinfo.utcoffset(obj) + # helper to extract datetime and int64 from several different possibilities cdef convert_to_tsobject(object ts, object tz): """ @@ -660,6 +682,7 @@ cdef convert_to_tsobject(object ts, object tz): return obj + cdef inline void _localize_tso(_TSObject obj, object tz): if _is_utc(tz): obj.tzinfo = tz @@ -689,28 +712,27 @@ cdef inline void _localize_tso(_TSObject obj, object tz): obj.tzinfo = tz._tzinfos[inf] -def get_timezone(tz): +cpdef object get_timezone(object tz): return _get_zone(tz) + cdef inline bint _is_utc(object tz): return tz is UTC or isinstance(tz, _du_utc) + cdef inline object _get_zone(object tz): if _is_utc(tz): return 'UTC' else: try: - zone = tz.zone - if zone is None: - return tz - return zone + return tz.zone except AttributeError: return tz -# cdef int64_t _NS_LOWER_BOUND = -9223285636854775809LL -# cdef int64_t _NS_UPPER_BOUND = -9223372036854775807LL +# cdef i8 _NS_LOWER_BOUND = -9223285636854775809LL +# cdef i8 _NS_UPPER_BOUND = -9223372036854775807LL -cdef inline _check_dts_bounds(int64_t value, pandas_datetimestruct *dts): +cdef inline _check_dts_bounds(i8 value, pandas_datetimestruct *dts): cdef pandas_datetimestruct dts2 if dts.year <= 1677 or dts.year >= 2262: pandas_datetime_to_datetimestruct(value, PANDAS_FR_ns, &dts2) @@ -721,27 +743,19 @@ cdef inline _check_dts_bounds(int64_t value, pandas_datetimestruct *dts): raise ValueError('Out of bounds nanosecond timestamp: %s' % fmt) -# elif isinstance(ts, _Timestamp): -# tmp = ts -# obj.value = (<_Timestamp> ts).value -# obj.dtval = -# elif isinstance(ts, object): -# # If all else fails -# obj.value = _dtlike_to_datetime64(ts, &obj.dts) -# obj.dtval = _dts_to_pydatetime(&obj.dts) -def datetime_to_datetime64(ndarray[object] values): +cpdef tuple datetime_to_datetime64(ndarray[object] values): cdef: Py_ssize_t i, n = len(values) object val, inferred_tz = None - ndarray[int64_t] iresult pandas_datetimestruct dts _TSObject _ts + ndarray result = np.empty(n, dtype='M8[ns]') + ndarray[i8] iresult = result.view('i8') - result = np.empty(n, dtype='M8[ns]') - iresult = result.view('i8') for i in range(n): val = values[i] + if util._checknull(val): iresult[i] = iNaT elif PyDateTime_Check(val): @@ -766,12 +780,12 @@ def datetime_to_datetime64(ndarray[object] values): return result, inferred_tz -def array_to_datetime(ndarray[object] values, raise_=False, dayfirst=False, - format=None, utc=None): +cpdef ndarray array_to_datetime(ndarray[object] values, raise_=False, + dayfirst=False, format=None, utc=None): cdef: Py_ssize_t i, n = len(values) object val - ndarray[int64_t] iresult + ndarray[i8] iresult ndarray[object] oresult pandas_datetimestruct dts bint utc_convert = bool(utc) @@ -849,6 +863,7 @@ def array_to_datetime(ndarray[object] values, raise_=False, dayfirst=False, return oresult + cdef inline _get_datetime64_nanos(object val): cdef: pandas_datetimestruct dts @@ -868,17 +883,16 @@ cdef inline _get_datetime64_nanos(object val): return ival -def cast_to_nanoseconds(ndarray arr): +cpdef ndarray[i8] cast_to_nanoseconds(ndarray arr): cdef: Py_ssize_t i, n = arr.size - ndarray[int64_t] ivalues, iresult + ndarray[i8] ivalues, iresult + ndarray result PANDAS_DATETIMEUNIT unit pandas_datetimestruct dts - - shape = ( arr).shape + tuple shape = ( arr).shape ivalues = arr.view(np.int64).ravel() - result = np.empty(shape, dtype='M8[ns]') iresult = result.ravel().view(np.int64) @@ -896,23 +910,24 @@ def cast_to_nanoseconds(ndarray arr): # Conversion routines -def pydt_to_i8(object pydt): +cpdef i8 pydt_to_i8(object pydt): ''' Convert to int64 representation compatible with numpy datetime64; converts to UTC ''' cdef: - _TSObject ts + _TSObject ts = convert_to_tsobject(pydt, None) + i8 value = ts.value + + return value - ts = convert_to_tsobject(pydt, None) - return ts.value -def i8_to_pydt(int64_t i8, object tzinfo = None): +def i8_to_pydt(i8 i, object tzinfo = None): ''' Inverse of pydt_to_i8 ''' - return Timestamp(i8) + return Timestamp(i) #---------------------------------------------------------------------- # time zone conversion helpers @@ -925,11 +940,12 @@ try: except: have_pytz = False -def tz_convert(ndarray[int64_t] vals, object tz1, object tz2): + +cpdef ndarray[i8] tz_convert(ndarray[i8] vals, object tz1, object tz2): cdef: - ndarray[int64_t] utc_dates, result, trans, deltas + ndarray[i8] utc_dates, result, trans, deltas Py_ssize_t i, pos, n = len(vals) - int64_t v, offset + i8 v, offset pandas_datetimestruct dts if not have_pytz: @@ -1000,11 +1016,12 @@ def tz_convert(ndarray[int64_t] vals, object tz1, object tz2): return result -def tz_convert_single(int64_t val, object tz1, object tz2): + +cpdef i8 tz_convert_single(i8 val, object tz1, object tz2): cdef: - ndarray[int64_t] trans, deltas + ndarray[i8] trans, deltas Py_ssize_t pos - int64_t v, offset, utc_date + i8 v, offset, utc_date pandas_datetimestruct dts if not have_pytz: @@ -1050,6 +1067,7 @@ def tz_convert_single(int64_t val, object tz1, object tz2): trans_cache = {} utc_offset_cache = {} + def _get_transitions(tz): """ Get UTC times of DST transitions @@ -1074,6 +1092,7 @@ def _get_transitions(tz): trans_cache[tz] = arr return trans_cache[tz] + def _get_deltas(tz): """ Get UTC offsets in microseconds corresponding to DST transitions @@ -1095,30 +1114,31 @@ def _get_deltas(tz): return utc_offset_cache[tz] -cdef double total_seconds(object td): # Python 2.6 compat + +cdef i8 total_seconds(object td): # Python 2.6 compat return ((td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) // 10**6) -def tot_seconds(td): + +cpdef i8 tot_seconds(object td): return total_seconds(td) -cpdef ndarray _unbox_utcoffsets(object transinfo): - cdef: - Py_ssize_t i, sz - ndarray[int64_t] arr - sz = len(transinfo) - arr = np.empty(sz, dtype='i8') +cpdef ndarray[i8] _unbox_utcoffsets(object transinfo): + cdef: + Py_ssize_t i, sz = len(transinfo) + ndarray[i8] arr = np.empty(sz, dtype='i8') + i8 billion = 1000000000 for i in range(sz): - arr[i] = int(total_seconds(transinfo[i][0])) * 1000000000 + arr[i] = total_seconds(transinfo[i][0]) * billion return arr @cython.boundscheck(False) @cython.wraparound(False) -def tz_localize_to_utc(ndarray[int64_t] vals, object tz): +cpdef ndarray[i8] tz_localize_to_utc(ndarray[i8] vals, object tz): """ Localize tzinfo-naive DateRange to given time zone (using pytz). If there are ambiguities in the values, raise AmbiguousTimeError. @@ -1128,11 +1148,11 @@ def tz_localize_to_utc(ndarray[int64_t] vals, object tz): localized : DatetimeIndex """ cdef: - ndarray[int64_t] trans, deltas, idx_shifted + ndarray[i8] trans, deltas, idx_shifted Py_ssize_t i, idx, pos, ntrans, n = len(vals) - int64_t *tdata - int64_t v, left, right - ndarray[int64_t] result, result_a, result_b + i8 *tdata + i8 v, left, right + ndarray[i8] result, result_a, result_b pandas_datetimestruct dts # Vectorized version of DstTzInfo.localize @@ -1158,7 +1178,7 @@ def tz_localize_to_utc(ndarray[int64_t] vals, object tz): trans = _get_transitions(tz) # transition dates deltas = _get_deltas(tz) # utc offsets - tdata = trans.data + tdata = trans.data ntrans = len(trans) result_a = np.empty(n, dtype=np.int64) @@ -1209,7 +1229,8 @@ def tz_localize_to_utc(ndarray[int64_t] vals, object tz): return result -cdef _ensure_int64(object arr): + +cdef ndarray[i8] _ensure_int64(object arr): if util.is_array(arr): if ( arr).descr.type_num == NPY_INT64: return arr @@ -1219,7 +1240,7 @@ cdef _ensure_int64(object arr): return np.array(arr, dtype=np.int64) -cdef inline bisect_right_i8(int64_t *data, int64_t val, Py_ssize_t n): +cdef inline Py_ssize_t bisect_right_i8(i8 *data, i8 val, Py_ssize_t n): cdef Py_ssize_t pivot, left = 0, right = n # edge cases @@ -1242,8 +1263,7 @@ cdef inline bisect_right_i8(int64_t *data, int64_t val, Py_ssize_t n): # Accessors #---------------------------------------------------------------------- - -def build_field_sarray(ndarray[int64_t] dtindex): +def build_field_sarray(ndarray[i8] dtindex): ''' Datetime as int64 representation to a structured array of fields ''' @@ -1251,7 +1271,7 @@ def build_field_sarray(ndarray[int64_t] dtindex): Py_ssize_t i, count = 0 int isleap pandas_datetimestruct dts - ndarray[int32_t] years, months, days, hours, minutes, seconds, mus + ndarray[i4] years, months, days, hours, minutes, seconds, mus count = len(dtindex) @@ -1285,26 +1305,29 @@ def build_field_sarray(ndarray[int64_t] dtindex): return out -def get_time_micros(ndarray[int64_t] dtindex): + +cpdef ndarray[i8] get_time_micros(ndarray[i8] dtindex): ''' Datetime as int64 representation to a structured array of fields ''' cdef: Py_ssize_t i, n = len(dtindex) pandas_datetimestruct dts - ndarray[int64_t] micros - - micros = np.empty(n, dtype=np.int64) + ndarray[i8] micros = np.empty(n, dtype=np.int64) + i8 secs_per_min = 60 + i8 secs_per_hour = secs_per_min * secs_per_min + i8 us_per_sec = 1000000 for i in range(n): pandas_datetime_to_datetimestruct(dtindex[i], PANDAS_FR_ns, &dts) - micros[i] = 1000000LL * (dts.hour * 60 * 60 + - 60 * dts.min + dts.sec) + dts.us + micros[i] = us_per_sec * (dts.hour * secs_per_hour + secs_per_min * + dts.min + dts.sec) + dts.us return micros + @cython.wraparound(False) -def get_date_field(ndarray[int64_t] dtindex, object field): +def get_date_field(ndarray[i8] dtindex, object field): ''' Given a int64-based datetime index, extract the year, month, etc., field and return an array of these values. @@ -1312,8 +1335,8 @@ def get_date_field(ndarray[int64_t] dtindex, object field): cdef: _TSObject ts Py_ssize_t i, count = 0 - ndarray[int32_t] out - ndarray[int32_t, ndim=2] _month_offset + ndarray[i8] out + ndarray[i4, ndim=2] _month_offset int isleap pandas_datetimestruct dts @@ -1323,11 +1346,13 @@ def get_date_field(ndarray[int64_t] dtindex, object field): dtype=np.int32 ) count = len(dtindex) - out = np.empty(count, dtype='i4') + out = np.empty(count, dtype='i8') if field == 'Y': for i in range(count): - if dtindex[i] == NPY_NAT: out[i] = -1; continue + if dtindex[i] == NPY_NAT: + out[i] = -1 + continue pandas_datetime_to_datetimestruct(dtindex[i], PANDAS_FR_ns, &dts) out[i] = dts.year @@ -1426,19 +1451,20 @@ def get_date_field(ndarray[int64_t] dtindex, object field): raise ValueError("Field %s not supported" % field) -cdef inline int m8_weekday(int64_t val): +cdef inline int m8_weekday(i8 val): ts = convert_to_tsobject(val, None) return ts_dayofweek(ts) -cdef int64_t DAY_NS = 86400000000000LL +cdef i8 DAY_NS = 86400000000000LL -def date_normalize(ndarray[int64_t] stamps, tz=None): + +cpdef ndarray[i8] date_normalize(ndarray[i8] stamps, tz=None): cdef: Py_ssize_t i, n = len(stamps) pandas_datetimestruct dts _TSObject tso - ndarray[int64_t] result = np.empty(n, dtype=np.int64) + ndarray[i8] result = np.empty(n, dtype=np.int64) if tz is not None: tso = _TSObject() @@ -1455,11 +1481,12 @@ def date_normalize(ndarray[int64_t] stamps, tz=None): return result -cdef _normalize_local(ndarray[int64_t] stamps, object tz): + +cdef ndarray[i8] _normalize_local(ndarray[i8] stamps, object tz): cdef: Py_ssize_t n = len(stamps) - ndarray[int64_t] result = np.empty(n, dtype=np.int64) - ndarray[int64_t] trans, deltas, pos + ndarray[i8] result = np.empty(n, dtype=np.int64) + ndarray[i8] trans, deltas, pos pandas_datetimestruct dts if _is_utc(tz): @@ -1511,7 +1538,8 @@ cdef _normalize_local(ndarray[int64_t] stamps, object tz): return result -cdef inline int64_t _normalized_stamp(pandas_datetimestruct *dts): + +cdef inline i8 _normalized_stamp(pandas_datetimestruct *dts): dts.hour = 0 dts.min = 0 dts.sec = 0 @@ -1519,7 +1547,7 @@ cdef inline int64_t _normalized_stamp(pandas_datetimestruct *dts): return pandas_datetimestruct_to_datetime(PANDAS_FR_ns, dts) -cdef inline void m8_populate_tsobject(int64_t stamp, _TSObject tso, object tz): +cdef inline void m8_populate_tsobject(i8 stamp, _TSObject tso, object tz): tso.value = stamp pandas_datetime_to_datetimestruct(tso.value, PANDAS_FR_ns, &tso.dts) @@ -1527,7 +1555,7 @@ cdef inline void m8_populate_tsobject(int64_t stamp, _TSObject tso, object tz): _localize_tso(tso, tz) -def dates_normalized(ndarray[int64_t] stamps, tz=None): +cpdef bint dates_normalized(ndarray[i8] stamps, tz=None): cdef: Py_ssize_t i, n = len(stamps) pandas_datetimestruct dts @@ -1565,26 +1593,29 @@ def dates_normalized(ndarray[int64_t] stamps, tz=None): # Some general helper functions #---------------------------------------------------------------------- -def isleapyear(int64_t year): +cpdef bint isleapyear(i8 year): return is_leapyear(year) -def monthrange(int64_t year, int64_t month): + +cpdef tuple monthrange(i8 year, i8 month): cdef: - int64_t days - int64_t day_of_week + i8 days + i8 day_of_week if month < 1 or month > 12: raise ValueError("bad month number 0; must be 1-12") - days = days_per_month_table[is_leapyear(year)][month-1] + days = days_per_month_table[is_leapyear(year)][month - 1] + + return dayofweek(year, month, 1), days - return (dayofweek(year, month, 1), days) -cdef inline int64_t ts_dayofweek(_TSObject ts): - return dayofweek(ts.dts.year, ts.dts.month, ts.dts.day) +cdef inline i8 ts_dayofweek(_TSObject ts): + cdef i8 result = dayofweek(ts.dts.year, ts.dts.month, ts.dts.day) + return result -cpdef normalize_date(object dt): +cpdef object normalize_date(object dt): ''' Normalize datetime.datetime value to midnight. Returns datetime.date as a datetime.datetime at midnight @@ -1600,12 +1631,13 @@ cpdef normalize_date(object dt): else: raise TypeError('Unrecognized type: %s' % type(dt)) -cdef ndarray[int64_t] localize_dt64arr_to_period(ndarray[int64_t] stamps, - int freq, object tz): + +cdef ndarray[i8] localize_dt64arr_to_period(ndarray[i8] stamps, int freq, + object tz): cdef: Py_ssize_t n = len(stamps) - ndarray[int64_t] result = np.empty(n, dtype=np.int64) - ndarray[int64_t] trans, deltas, pos + ndarray[i8] result = np.empty(n, dtype=np.int64) + ndarray[i8] trans, deltas, pos pandas_datetimestruct dts if not have_pytz: @@ -1618,7 +1650,8 @@ cdef ndarray[int64_t] localize_dt64arr_to_period(ndarray[int64_t] stamps, continue pandas_datetime_to_datetimestruct(stamps[i], PANDAS_FR_ns, &dts) result[i] = get_period_ordinal(dts.year, dts.month, dts.day, - dts.hour, dts.min, dts.sec, freq) + dts.hour, dts.min, dts.sec, dts.us, + freq) elif _is_tzlocal(tz): for i in range(n): @@ -1633,7 +1666,8 @@ cdef ndarray[int64_t] localize_dt64arr_to_period(ndarray[int64_t] stamps, pandas_datetime_to_datetimestruct(stamps[i] + delta, PANDAS_FR_ns, &dts) result[i] = get_period_ordinal(dts.year, dts.month, dts.day, - dts.hour, dts.min, dts.sec, freq) + dts.hour, dts.min, dts.sec, dts.us, + freq) else: # Adjust datetime64 timestamp, recompute datetimestruct trans = _get_transitions(tz) @@ -1652,7 +1686,9 @@ cdef ndarray[int64_t] localize_dt64arr_to_period(ndarray[int64_t] stamps, pandas_datetime_to_datetimestruct(stamps[i] + deltas[0], PANDAS_FR_ns, &dts) result[i] = get_period_ordinal(dts.year, dts.month, dts.day, - dts.hour, dts.min, dts.sec, freq) + dts.hour, dts.min, dts.sec, + dts.us, + freq) else: for i in range(n): if stamps[i] == NPY_NAT: @@ -1661,70 +1697,76 @@ cdef ndarray[int64_t] localize_dt64arr_to_period(ndarray[int64_t] stamps, pandas_datetime_to_datetimestruct(stamps[i] + deltas[pos[i]], PANDAS_FR_ns, &dts) result[i] = get_period_ordinal(dts.year, dts.month, dts.day, - dts.hour, dts.min, dts.sec, freq) + dts.hour, dts.min, dts.sec, + dts.us, freq) return result cdef extern from "period.h": ctypedef struct date_info: - int64_t absdate - double abstime - double second - int minute - int hour - int day - int month - int quarter - int year - int day_of_week - int day_of_year - int calendar + i8 absdate + i8 abstime + + i8 attosecond + i8 femtosecond + i8 picosecond + i8 nanosecond + i8 microsecond + i8 second + i8 minute + i8 hour + i8 day + i8 month + i8 quarter + i8 year + i8 day_of_week + i8 day_of_year + i8 calendar ctypedef struct asfreq_info: - int from_week_end - int to_week_end - - int from_a_year_end - int to_a_year_end - - int from_q_year_end - int to_q_year_end - - ctypedef int64_t (*freq_conv_func)(int64_t, char, asfreq_info*) - - int64_t asfreq(int64_t dtordinal, int freq1, int freq2, char relation) except INT32_MIN - freq_conv_func get_asfreq_func(int fromFreq, int toFreq) - void get_asfreq_info(int fromFreq, int toFreq, asfreq_info *af_info) - - int64_t get_period_ordinal(int year, int month, int day, - int hour, int minute, int second, - int freq) except INT32_MIN - - int64_t get_python_ordinal(int64_t period_ordinal, int freq) except INT32_MIN - - int get_date_info(int64_t ordinal, int freq, date_info *dinfo) except INT32_MIN - double getAbsTime(int, int64_t, int64_t) - - int pyear(int64_t ordinal, int freq) except INT32_MIN - int pqyear(int64_t ordinal, int freq) except INT32_MIN - int pquarter(int64_t ordinal, int freq) except INT32_MIN - int pmonth(int64_t ordinal, int freq) except INT32_MIN - int pday(int64_t ordinal, int freq) except INT32_MIN - int pweekday(int64_t ordinal, int freq) except INT32_MIN - int pday_of_week(int64_t ordinal, int freq) except INT32_MIN - int pday_of_year(int64_t ordinal, int freq) except INT32_MIN - int pweek(int64_t ordinal, int freq) except INT32_MIN - int phour(int64_t ordinal, int freq) except INT32_MIN - int pminute(int64_t ordinal, int freq) except INT32_MIN - int psecond(int64_t ordinal, int freq) except INT32_MIN + i8 from_week_end + i8 to_week_end + + i8 from_a_year_end + i8 to_a_year_end + + i8 from_q_year_end + i8 to_q_year_end + + ctypedef i8 (*freq_conv_func)(i8, char*, asfreq_info*) + + i8 asfreq(i8 ordinal, i8 freq1, i8 freq2, char* relation) except INT64_MIN + freq_conv_func get_asfreq_func(i8 fromFreq, i8 toFreq) + void get_asfreq_info(i8 fromFreq, i8 toFreq, asfreq_info *af_info) + + i8 get_period_ordinal(i8 year, i8 month, i8 day, i8 hour, i8 minute, + i8 second, i8 microsecond, i8 freq) except INT64_MIN + + i8 get_python_ordinal(i8 period_ordinal, i8 freq) except INT64_MIN + + i8 get_date_info(i8 ordinal, i8 freq, date_info *dinfo) except INT64_MIN + + i8 pyear(i8 ordinal, i8 freq) except INT64_MIN + i8 pqyear(i8 ordinal, i8 freq) except INT64_MIN + i8 pquarter(i8 ordinal, i8 freq) except INT64_MIN + i8 pmonth(i8 ordinal, i8 freq) except INT64_MIN + i8 pday(i8 ordinal, i8 freq) except INT64_MIN + i8 pweekday(i8 ordinal, i8 freq) except INT64_MIN + i8 pday_of_week(i8 ordinal, i8 freq) except INT64_MIN + i8 pday_of_year(i8 ordinal, i8 freq) except INT64_MIN + i8 pweek(i8 ordinal, i8 freq) except INT64_MIN + i8 phour(i8 ordinal, i8 freq) except INT64_MIN + i8 pminute(i8 ordinal, i8 freq) except INT64_MIN + i8 psecond(i8 ordinal, i8 freq) except INT64_MIN + i8 pmicrosecond(i8 ordinal, i8 freq) except INT64_MIN char *c_strftime(date_info *dinfo, char *fmt) - int get_yq(int64_t ordinal, int freq, int *quarter, int *year) + i8 get_yq(i8 ordinal, i8 freq, i8 *quarter, i8 *year) # Period logic #---------------------------------------------------------------------- -cdef inline int64_t apply_mult(int64_t period_ord, int64_t mult): +cdef inline i8 apply_mult(i8 period_ord, i8 mult): """ Get freq+multiple ordinal value from corresponding freq-only ordinal value. For example, 5min ordinal will be 1/5th the 1min ordinal (rounding down to @@ -1735,7 +1777,8 @@ cdef inline int64_t apply_mult(int64_t period_ord, int64_t mult): return (period_ord - 1) // mult -cdef inline int64_t remove_mult(int64_t period_ord_w_mult, int64_t mult): + +cdef inline i8 remove_mult(i8 period_ord_w_mult, i8 mult): """ Get freq-only ordinal value from corresponding freq+multiple ordinal. """ @@ -1744,13 +1787,15 @@ cdef inline int64_t remove_mult(int64_t period_ord_w_mult, int64_t mult): return period_ord_w_mult * mult + 1; -def dt64arr_to_periodarr(ndarray[int64_t] dtarr, int freq, tz=None): + +cpdef ndarray[i8] dt64arr_to_periodarr(ndarray[i8] dtarr, int freq, + object tz=None): """ Convert array of datetime64 values (passed in as 'i8' dtype) to a set of periods corresponding to desired frequency, per period convention. """ cdef: - ndarray[int64_t] out + ndarray[i8] out Py_ssize_t i, l pandas_datetimestruct dts @@ -1762,63 +1807,54 @@ def dt64arr_to_periodarr(ndarray[int64_t] dtarr, int freq, tz=None): for i in range(l): pandas_datetime_to_datetimestruct(dtarr[i], PANDAS_FR_ns, &dts) out[i] = get_period_ordinal(dts.year, dts.month, dts.day, - dts.hour, dts.min, dts.sec, freq) + dts.hour, dts.min, dts.sec, dts.us, + freq) else: out = localize_dt64arr_to_period(dtarr, freq, tz) return out -def periodarr_to_dt64arr(ndarray[int64_t] periodarr, int freq): + +cpdef ndarray[i8] periodarr_to_dt64arr(ndarray[i8] periodarr, int freq): """ Convert array to datetime64 values from a set of ordinals corresponding to periods per period convention. """ cdef: - ndarray[int64_t] out - Py_ssize_t i, l - - l = len(periodarr) - - out = np.empty(l, dtype='i8') + Py_ssize_t i, l = len(periodarr) + ndarray[i8] out = np.empty(l, dtype='i8') for i in range(l): out[i] = period_ordinal_to_dt64(periodarr[i], freq) return out -cdef char START = 'S' -cdef char END = 'E' -cpdef int64_t period_asfreq(int64_t period_ordinal, int freq1, int freq2, - bint end): +cpdef i8 period_asfreq(i8 period_ordinal, int freq1, int freq2, + char* relation): """ Convert period ordinal from one frequency to another, and if upsampling, choose to use start ('S') or end ('E') of period. """ - cdef: - int64_t retval + cdef i8 retval = asfreq(period_ordinal, freq1, freq2, relation) - if end: - retval = asfreq(period_ordinal, freq1, freq2, END) - else: - retval = asfreq(period_ordinal, freq1, freq2, START) - - if retval == INT32_MIN: + if retval == INT64_MIN: raise ValueError('Frequency conversion failed') return retval -def period_asfreq_arr(ndarray[int64_t] arr, int freq1, int freq2, bint end): + +cpdef ndarray[i8] period_asfreq_arr(ndarray[i8] arr, int freq1, int freq2, + char* relation): """ Convert int64-array of period ordinals from one frequency to another, and if upsampling, choose to use start ('S') or end ('E') of period. """ cdef: - ndarray[int64_t] result + ndarray[i8] result Py_ssize_t i, n freq_conv_func func asfreq_info finfo - int64_t val, ordinal - char relation + i8 val, ordinal n = len(arr) result = np.empty(n, dtype=np.int64) @@ -1826,27 +1862,21 @@ def period_asfreq_arr(ndarray[int64_t] arr, int freq1, int freq2, bint end): func = get_asfreq_func(freq1, freq2) get_asfreq_info(freq1, freq2, &finfo) - if end: - relation = END - else: - relation = START - for i in range(n): val = func(arr[i], relation, &finfo) - if val == INT32_MIN: + if val == INT64_MIN: raise ValueError("Unable to convert to desired frequency.") result[i] = val return result -def period_ordinal(int y, int m, int d, int h, int min, int s, int freq): - cdef: - int64_t ordinal - return get_period_ordinal(y, m, d, h, min, s, freq) +cpdef i8 period_ordinal(i8 y, i8 m, i8 d, i8 h, i8 min, i8 s, i8 us, i8 freq): + cdef i8 ordinal = get_period_ordinal(y, m, d, h, min, s, us, freq) + return ordinal -cpdef int64_t period_ordinal_to_dt64(int64_t ordinal, int freq): +cpdef i8 period_ordinal_to_dt64(i8 ordinal, int freq): cdef: pandas_datetimestruct dts date_info dinfo @@ -1858,12 +1888,14 @@ cpdef int64_t period_ordinal_to_dt64(int64_t ordinal, int freq): dts.day = dinfo.day dts.hour = dinfo.hour dts.min = dinfo.minute - dts.sec = int(dinfo.second) - dts.us = dts.ps = 0 + dts.sec = dinfo.second + dts.us = dinfo.microsecond + dts.ps = 0 return pandas_datetimestruct_to_datetime(PANDAS_FR_ns, &dts) -def period_format(int64_t value, int freq, object fmt=None): + +cpdef object period_format(i8 value, int freq, object fmt=None): cdef: int freq_group @@ -1876,8 +1908,8 @@ def period_format(int64_t value, int freq, object fmt=None): elif freq_group == 3000: # FR_MTH fmt = b'%Y-%m' elif freq_group == 4000: # WK - left = period_asfreq(value, freq, 6000, 0) - right = period_asfreq(value, freq, 6000, 1) + left = period_asfreq(value, freq, 6000, 'S') + right = period_asfreq(value, freq, 6000, 'E') return '%s/%s' % (period_format(left, 6000), period_format(right, 6000)) elif (freq_group == 5000 # BUS @@ -1889,26 +1921,31 @@ def period_format(int64_t value, int freq, object fmt=None): fmt = b'%Y-%m-%d %H:%M' elif freq_group == 9000: # SEC fmt = b'%Y-%m-%d %H:%M:%S' + elif freq_group == 10000: # USEC + fmt = b'%Y-%m-%d %H:%M:%S.%u' else: raise ValueError('Unknown freq: %d' % freq) return _period_strftime(value, freq, fmt) -cdef list extra_fmts = [(b"%q", b"^`AB`^"), - (b"%f", b"^`CD`^"), - (b"%F", b"^`EF`^")] +cdef tuple extra_fmts = ((b"%q", b"^`AB`^"), + (b"%f", b"^`CD`^"), + (b"%F", b"^`EF`^"), + (b"%u", b"^`GH`^")) + -cdef list str_extra_fmts = ["^`AB`^", "^`CD`^", "^`EF`^"] +cdef tuple str_extra_fmts = ("^`AB`^", "^`CD`^", "^`EF`^", "^`GH`^") -cdef _period_strftime(int64_t value, int freq, object fmt): + +cdef object _period_strftime(i8 value, int freq, object fmt): cdef: Py_ssize_t i date_info dinfo char *formatted object pat, repl, result list found_pat = [False] * len(extra_fmts) - int year, quarter + i8 year, quarter if PyUnicode_Check(fmt): fmt = fmt.encode('utf-8') @@ -1937,6 +1974,8 @@ cdef _period_strftime(int64_t value, int freq, object fmt): repl = '%.2d' % (year % 100) elif i == 2: repl = '%d' % year + elif i == 3: + repl = '%.6u' % dinfo.microsecond result = result.replace(str_extra_fmts[i], repl) @@ -1948,22 +1987,19 @@ cdef _period_strftime(int64_t value, int freq, object fmt): # period accessors -ctypedef int (*accessor)(int64_t ordinal, int freq) except INT32_MIN +ctypedef i8 (*accessor)(i8 ordinal, i8 freq) except INT64_MIN + -def get_period_field(int code, int64_t value, int freq): +cpdef i8 get_period_field(int code, i8 value, int freq): cdef accessor f = _get_accessor_func(code) return f(value, freq) -def get_period_field_arr(int code, ndarray[int64_t] arr, int freq): - cdef: - Py_ssize_t i, sz - ndarray[int64_t] out - accessor f - - f = _get_accessor_func(code) - sz = len(arr) - out = np.empty(sz, dtype=np.int64) +cpdef ndarray[i8] get_period_field_arr(int code, ndarray[i8] arr, int freq): + cdef: + Py_ssize_t i, sz = len(arr) + ndarray[i8] out = np.empty(sz, dtype=np.int64) + accessor f = _get_accessor_func(code) for i in range(sz): out[i] = f(arr[i], freq) @@ -1971,7 +2007,6 @@ def get_period_field_arr(int code, ndarray[int64_t] arr, int freq): return out - cdef accessor _get_accessor_func(int code): if code == 0: return &pyear @@ -1995,14 +2030,16 @@ cdef accessor _get_accessor_func(int code): return &pday_of_year elif code == 10: return &pweekday + elif code == 11: + return &pmicrosecond else: raise ValueError('Unrecognized code: %s' % code) -def extract_ordinals(ndarray[object] values, freq): +cpdef ndarray[i8] extract_ordinals(ndarray[object] values, freq): cdef: Py_ssize_t i, n = len(values) - ndarray[int64_t] ordinals = np.empty(n, dtype=np.int64) + ndarray[i8] ordinals = np.empty(n, dtype=np.int64) object p for i in range(n): @@ -2013,7 +2050,8 @@ def extract_ordinals(ndarray[object] values, freq): return ordinals -cpdef resolution(ndarray[int64_t] stamps, tz=None): + +cpdef int resolution(ndarray[i8] stamps, object tz=None): cdef: Py_ssize_t i, n = len(stamps) pandas_datetimestruct dts @@ -2022,23 +2060,29 @@ cpdef resolution(ndarray[int64_t] stamps, tz=None): if tz is not None: if isinstance(tz, basestring): tz = pytz.timezone(tz) + return _reso_local(stamps, tz) else: for i in range(n): if stamps[i] == NPY_NAT: continue + pandas_datetime_to_datetimestruct(stamps[i], PANDAS_FR_ns, &dts) curr_reso = _reso_stamp(&dts) + if curr_reso < reso: reso = curr_reso + return reso + US_RESO = 0 S_RESO = 1 T_RESO = 2 H_RESO = 3 D_RESO = 4 + cdef inline int _reso_stamp(pandas_datetimestruct *dts): if dts.us != 0: return US_RESO @@ -2050,30 +2094,35 @@ cdef inline int _reso_stamp(pandas_datetimestruct *dts): return H_RESO return D_RESO -cdef _reso_local(ndarray[int64_t] stamps, object tz): + +cdef int _reso_local(ndarray[i8] stamps, object tz): cdef: Py_ssize_t n = len(stamps) int reso = D_RESO, curr_reso - ndarray[int64_t] trans, deltas, pos + ndarray[i8] trans, deltas, pos pandas_datetimestruct dts + i8 billion = 1000000000 if _is_utc(tz): for i in range(n): if stamps[i] == NPY_NAT: continue + pandas_datetime_to_datetimestruct(stamps[i], PANDAS_FR_ns, &dts) curr_reso = _reso_stamp(&dts) + if curr_reso < reso: reso = curr_reso elif _is_tzlocal(tz): for i in range(n): if stamps[i] == NPY_NAT: continue + pandas_datetime_to_datetimestruct(stamps[i], PANDAS_FR_ns, &dts) dt = datetime(dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.us, tz) - delta = int(total_seconds(_get_utcoffset(tz, dt))) * 1000000000 + delta = total_seconds(_get_utcoffset(tz, dt)) * billion pandas_datetime_to_datetimestruct(stamps[i] + delta, PANDAS_FR_ns, &dts) curr_reso = _reso_stamp(&dts) @@ -2084,8 +2133,10 @@ cdef _reso_local(ndarray[int64_t] stamps, object tz): trans = _get_transitions(tz) deltas = _get_deltas(tz) _pos = trans.searchsorted(stamps, side='right') - 1 + if _pos.dtype != np.int64: _pos = _pos.astype(np.int64) + pos = _pos # statictzinfo @@ -2102,9 +2153,11 @@ cdef _reso_local(ndarray[int64_t] stamps, object tz): for i in range(n): if stamps[i] == NPY_NAT: continue + pandas_datetime_to_datetimestruct(stamps[i] + deltas[pos[i]], PANDAS_FR_ns, &dts) curr_reso = _reso_stamp(&dts) + if curr_reso < reso: reso = curr_reso