diff --git a/pandas/_libs/tslibs/dtypes.pxd b/pandas/_libs/tslibs/dtypes.pxd index 356bd9dc3d7a0..6e41a55f30929 100644 --- a/pandas/_libs/tslibs/dtypes.pxd +++ b/pandas/_libs/tslibs/dtypes.pxd @@ -8,7 +8,6 @@ cdef NPY_DATETIMEUNIT abbrev_to_npy_unit(str abbrev) cdef NPY_DATETIMEUNIT freq_group_code_to_npy_unit(int freq) nogil cpdef int64_t periods_per_day(NPY_DATETIMEUNIT reso=*) except? -1 cpdef int64_t periods_per_second(NPY_DATETIMEUNIT reso) except? -1 -cdef int64_t get_conversion_factor(NPY_DATETIMEUNIT from_unit, NPY_DATETIMEUNIT to_unit) except? -1 cdef dict attrname_to_abbrevs diff --git a/pandas/_libs/tslibs/dtypes.pyx b/pandas/_libs/tslibs/dtypes.pyx index 01616666bba3f..a0a7ab90ebb30 100644 --- a/pandas/_libs/tslibs/dtypes.pyx +++ b/pandas/_libs/tslibs/dtypes.pyx @@ -4,7 +4,10 @@ cimport cython from enum import Enum -from pandas._libs.tslibs.np_datetime cimport NPY_DATETIMEUNIT +from pandas._libs.tslibs.np_datetime cimport ( + NPY_DATETIMEUNIT, + get_conversion_factor, +) cdef class PeriodDtypeBase: @@ -386,83 +389,11 @@ cpdef int64_t periods_per_day(NPY_DATETIMEUNIT reso=NPY_DATETIMEUNIT.NPY_FR_ns) """ How many of the given time units fit into a single day? """ - cdef: - int64_t day_units - - if reso == NPY_DATETIMEUNIT.NPY_FR_ps: - # pico is the smallest unit for which we don't overflow, so - # we exclude femto and atto - day_units = 24 * 3600 * 1_000_000_000_000 - elif reso == NPY_DATETIMEUNIT.NPY_FR_ns: - day_units = 24 * 3600 * 1_000_000_000 - elif reso == NPY_DATETIMEUNIT.NPY_FR_us: - day_units = 24 * 3600 * 1_000_000 - elif reso == NPY_DATETIMEUNIT.NPY_FR_ms: - day_units = 24 * 3600 * 1_000 - elif reso == NPY_DATETIMEUNIT.NPY_FR_s: - day_units = 24 * 3600 - elif reso == NPY_DATETIMEUNIT.NPY_FR_m: - day_units = 24 * 60 - elif reso == NPY_DATETIMEUNIT.NPY_FR_h: - day_units = 24 - elif reso == NPY_DATETIMEUNIT.NPY_FR_D: - day_units = 1 - else: - raise NotImplementedError(reso) - return day_units + return get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_D, reso) cpdef int64_t periods_per_second(NPY_DATETIMEUNIT reso) except? -1: - if reso == NPY_DATETIMEUNIT.NPY_FR_ns: - return 1_000_000_000 - elif reso == NPY_DATETIMEUNIT.NPY_FR_us: - return 1_000_000 - elif reso == NPY_DATETIMEUNIT.NPY_FR_ms: - return 1_000 - elif reso == NPY_DATETIMEUNIT.NPY_FR_s: - return 1 - else: - raise NotImplementedError(reso) - - -@cython.overflowcheck(True) -cdef int64_t get_conversion_factor(NPY_DATETIMEUNIT from_unit, NPY_DATETIMEUNIT to_unit) except? -1: - """ - Find the factor by which we need to multiply to convert from from_unit to to_unit. - """ - if ( - from_unit == NPY_DATETIMEUNIT.NPY_FR_GENERIC - or to_unit == NPY_DATETIMEUNIT.NPY_FR_GENERIC - ): - raise ValueError("unit-less resolutions are not supported") - if from_unit > to_unit: - raise ValueError - - if from_unit == to_unit: - return 1 - - if from_unit == NPY_DATETIMEUNIT.NPY_FR_W: - return 7 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_D, to_unit) - elif from_unit == NPY_DATETIMEUNIT.NPY_FR_D: - return 24 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_h, to_unit) - elif from_unit == NPY_DATETIMEUNIT.NPY_FR_h: - return 60 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_m, to_unit) - elif from_unit == NPY_DATETIMEUNIT.NPY_FR_m: - return 60 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_s, to_unit) - elif from_unit == NPY_DATETIMEUNIT.NPY_FR_s: - return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ms, to_unit) - elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ms: - return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_us, to_unit) - elif from_unit == NPY_DATETIMEUNIT.NPY_FR_us: - return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ns, to_unit) - elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ns: - return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ps, to_unit) - elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ps: - return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_fs, to_unit) - elif from_unit == NPY_DATETIMEUNIT.NPY_FR_fs: - return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_as, to_unit) - else: - raise ValueError(from_unit, to_unit) + return get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_s, reso) cdef dict _reso_str_map = { diff --git a/pandas/_libs/tslibs/np_datetime.pxd b/pandas/_libs/tslibs/np_datetime.pxd index 290483a741fe7..420d83909a78d 100644 --- a/pandas/_libs/tslibs/np_datetime.pxd +++ b/pandas/_libs/tslibs/np_datetime.pxd @@ -102,6 +102,7 @@ cpdef cnp.ndarray astype_overflowsafe( cnp.dtype dtype, # ndarray[datetime64[anyunit]] bint copy=*, ) +cdef int64_t get_conversion_factor(NPY_DATETIMEUNIT from_unit, NPY_DATETIMEUNIT to_unit) except? -1 cdef bint cmp_dtstructs(npy_datetimestruct* left, npy_datetimestruct* right, int op) cdef get_implementation_bounds( diff --git a/pandas/_libs/tslibs/np_datetime.pyx b/pandas/_libs/tslibs/np_datetime.pyx index 692b4430fa577..494eb5da7e107 100644 --- a/pandas/_libs/tslibs/np_datetime.pyx +++ b/pandas/_libs/tslibs/np_datetime.pyx @@ -1,3 +1,4 @@ +cimport cython from cpython.datetime cimport ( PyDateTime_DATE_GET_HOUR, PyDateTime_DATE_GET_MICROSECOND, @@ -450,3 +451,43 @@ cdef int op_to_op_code(op): return Py_GE if op is operator.gt: return Py_GT + + +@cython.overflowcheck(True) +cdef int64_t get_conversion_factor(NPY_DATETIMEUNIT from_unit, NPY_DATETIMEUNIT to_unit) except? -1: + """ + Find the factor by which we need to multiply to convert from from_unit to to_unit. + """ + if ( + from_unit == NPY_DATETIMEUNIT.NPY_FR_GENERIC + or to_unit == NPY_DATETIMEUNIT.NPY_FR_GENERIC + ): + raise ValueError("unit-less resolutions are not supported") + if from_unit > to_unit: + raise ValueError + + if from_unit == to_unit: + return 1 + + if from_unit == NPY_DATETIMEUNIT.NPY_FR_W: + return 7 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_D, to_unit) + elif from_unit == NPY_DATETIMEUNIT.NPY_FR_D: + return 24 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_h, to_unit) + elif from_unit == NPY_DATETIMEUNIT.NPY_FR_h: + return 60 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_m, to_unit) + elif from_unit == NPY_DATETIMEUNIT.NPY_FR_m: + return 60 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_s, to_unit) + elif from_unit == NPY_DATETIMEUNIT.NPY_FR_s: + return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ms, to_unit) + elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ms: + return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_us, to_unit) + elif from_unit == NPY_DATETIMEUNIT.NPY_FR_us: + return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ns, to_unit) + elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ns: + return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ps, to_unit) + elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ps: + return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_fs, to_unit) + elif from_unit == NPY_DATETIMEUNIT.NPY_FR_fs: + return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_as, to_unit) + else: + raise ValueError(from_unit, to_unit) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index fef2a317a4f26..c64a9fb4d9c36 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -35,10 +35,7 @@ from pandas._libs.tslibs.conversion cimport ( cast_from_unit, precision_from_unit, ) -from pandas._libs.tslibs.dtypes cimport ( - get_conversion_factor, - npy_unit_to_abbrev, -) +from pandas._libs.tslibs.dtypes cimport npy_unit_to_abbrev from pandas._libs.tslibs.nattype cimport ( NPY_NAT, c_NaT as NaT, @@ -50,6 +47,7 @@ from pandas._libs.tslibs.np_datetime cimport ( NPY_FR_ns, cmp_dtstructs, cmp_scalar, + get_conversion_factor, get_datetime64_unit, get_timedelta64_value, get_unit_from_dtype, diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index ae3ce46cbc3c8..3cf9c9bcda538 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -54,7 +54,6 @@ from pandas._libs.tslibs.conversion cimport ( maybe_localize_tso, ) from pandas._libs.tslibs.dtypes cimport ( - get_conversion_factor, npy_unit_to_abbrev, periods_per_day, periods_per_second, @@ -83,6 +82,7 @@ from pandas._libs.tslibs.np_datetime cimport ( NPY_FR_ns, cmp_dtstructs, cmp_scalar, + get_conversion_factor, get_datetime64_unit, get_datetime64_value, get_unit_from_dtype,