From 3c4e54ec8c0fbf8d6b4b1b570d04f700a7dca0ed Mon Sep 17 00:00:00 2001 From: Patrick Hoefler <61934744+phofl@users.noreply.github.com> Date: Thu, 23 Feb 2023 11:09:55 +0000 Subject: [PATCH] Revert "REF: de-duplicate precision_from_unit (#51483)" This reverts commit d08d4510db5e79b8e65b35174a3bc3a968bb9189. --- pandas/_libs/tslibs/conversion.pyx | 49 ++++++++++++++++++++++------- pandas/_libs/tslibs/np_datetime.pyx | 2 -- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx index 18ea6bbb0a257..03a53b1b451e9 100644 --- a/pandas/_libs/tslibs/conversion.pyx +++ b/pandas/_libs/tslibs/conversion.pyx @@ -37,7 +37,6 @@ from pandas._libs.tslibs.np_datetime cimport ( NPY_FR_us, check_dts_bounds, convert_reso, - get_conversion_factor, get_datetime64_unit, get_datetime64_value, get_implementation_bounds, @@ -84,9 +83,9 @@ TD64NS_DTYPE = np.dtype("m8[ns]") # Unit Conversion Helpers cdef int64_t cast_from_unit( - object ts, - str unit, - NPY_DATETIMEUNIT out_reso=NPY_FR_ns + object ts, + str unit, + NPY_DATETIMEUNIT out_reso=NPY_FR_ns ) except? -1: """ Return a casting of the unit represented to nanoseconds @@ -107,6 +106,10 @@ cdef int64_t cast_from_unit( m, p = precision_from_unit(unit, out_reso) + # just give me the unit back + if ts is None: + return m + if unit in ["Y", "M"]: if is_float_object(ts) and not ts.is_integer(): # GH#47267 it is clear that 2 "M" corresponds to 1970-02-01, @@ -145,8 +148,8 @@ cdef int64_t cast_from_unit( cpdef inline (int64_t, int) precision_from_unit( - str unit, - NPY_DATETIMEUNIT out_reso=NPY_DATETIMEUNIT.NPY_FR_ns, + str unit, + NPY_DATETIMEUNIT out_reso=NPY_DATETIMEUNIT.NPY_FR_ns, ): """ Return a casting of the unit represented to nanoseconds + the precision @@ -159,14 +162,38 @@ cpdef inline (int64_t, int) precision_from_unit( """ cdef: int64_t m + int64_t multiplier int p NPY_DATETIMEUNIT reso = abbrev_to_npy_unit(unit) - if reso == NPY_DATETIMEUNIT.NPY_FR_GENERIC: - reso = NPY_FR_ns - - m = get_conversion_factor(reso, out_reso) - + multiplier = periods_per_second(out_reso) + + if reso == NPY_DATETIMEUNIT.NPY_FR_Y: + # each 400 years we have 97 leap years, for an average of 97/400=.2425 + # extra days each year. We get 31556952 by writing + # 3600*24*365.2425=31556952 + m = multiplier * 31556952 + elif reso == NPY_DATETIMEUNIT.NPY_FR_M: + # 2629746 comes from dividing the "Y" case by 12. + m = multiplier * 2629746 + elif reso == NPY_DATETIMEUNIT.NPY_FR_W: + m = multiplier * 3600 * 24 * 7 + elif reso == NPY_DATETIMEUNIT.NPY_FR_D: + m = multiplier * 3600 * 24 + elif reso == NPY_DATETIMEUNIT.NPY_FR_h: + m = multiplier * 3600 + elif reso == NPY_DATETIMEUNIT.NPY_FR_m: + m = multiplier * 60 + elif reso == NPY_DATETIMEUNIT.NPY_FR_s: + m = multiplier + elif reso == NPY_DATETIMEUNIT.NPY_FR_ms: + m = multiplier // 1_000 + elif reso == NPY_DATETIMEUNIT.NPY_FR_us: + m = multiplier // 1_000_000 + elif reso == NPY_DATETIMEUNIT.NPY_FR_ns or reso == NPY_DATETIMEUNIT.NPY_FR_GENERIC: + m = multiplier // 1_000_000_000 + else: + raise ValueError(f"cannot cast unit {unit}") p = log10(m) # number of digits in 'm' minus 1 return m, p diff --git a/pandas/_libs/tslibs/np_datetime.pyx b/pandas/_libs/tslibs/np_datetime.pyx index d9aac87384952..aa3411385595b 100644 --- a/pandas/_libs/tslibs/np_datetime.pyx +++ b/pandas/_libs/tslibs/np_datetime.pyx @@ -571,8 +571,6 @@ cdef int64_t get_conversion_factor( 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("Converting from M or Y units is not supported.") cdef int64_t convert_reso(