Skip to content

Commit 0da4703

Browse files
jbrockmendelPuneethaPai
authored andcommitted
REF: put cast_from_unit in conversion to de-circularize cimports (#34287)
1 parent a7dcfc6 commit 0da4703

File tree

6 files changed

+84
-83
lines changed

6 files changed

+84
-83
lines changed

pandas/_libs/tslib.pyx

+5-3
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,18 @@ from pandas._libs.tslibs.np_datetime import OutOfBoundsDatetime
4141

4242
from pandas._libs.tslibs.parsing import parse_datetime_string
4343

44-
from pandas._libs.tslibs.timedeltas cimport cast_from_unit
4544
from pandas._libs.tslibs.timezones cimport (
4645
get_dst_info,
4746
is_utc,
4847
is_tzlocal,
4948
utc_pytz as UTC,
5049
)
5150
from pandas._libs.tslibs.conversion cimport (
52-
_TSObject, convert_datetime_to_tsobject,
53-
get_datetime64_nanos)
51+
_TSObject,
52+
cast_from_unit,
53+
convert_datetime_to_tsobject,
54+
get_datetime64_nanos,
55+
)
5456

5557
from pandas._libs.tslibs.nattype cimport (
5658
NPY_NAT,

pandas/_libs/tslibs/conversion.pxd

+1
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ cdef _TSObject convert_datetime_to_tsobject(datetime ts, object tz,
2323
cdef int64_t get_datetime64_nanos(object val) except? -1
2424

2525
cpdef datetime localize_pydatetime(datetime dt, object tz)
26+
cdef int64_t cast_from_unit(object ts, str unit) except? -1

pandas/_libs/tslibs/conversion.pyx

+75-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ from pandas._libs.tslibs.np_datetime import OutOfBoundsDatetime
2525
from pandas._libs.tslibs.util cimport (
2626
is_datetime64_object, is_integer_object, is_float_object)
2727

28-
from pandas._libs.tslibs.timedeltas cimport cast_from_unit
2928
from pandas._libs.tslibs.timezones cimport (
3029
is_utc, is_tzlocal, is_fixed_offset, get_utcoffset, get_dst_info,
3130
get_timezone, maybe_get_tz, tz_compare,
@@ -55,7 +54,78 @@ TD64NS_DTYPE = np.dtype('m8[ns]')
5554

5655

5756
# ----------------------------------------------------------------------
58-
# Misc Helpers
57+
# Unit Conversion Helpers
58+
59+
cdef inline int64_t cast_from_unit(object ts, str unit) except? -1:
60+
""" return a casting of the unit represented to nanoseconds
61+
round the fractional part of a float to our precision, p """
62+
cdef:
63+
int64_t m
64+
int p
65+
66+
m, p = precision_from_unit(unit)
67+
68+
# just give me the unit back
69+
if ts is None:
70+
return m
71+
72+
# cast the unit, multiply base/frace separately
73+
# to avoid precision issues from float -> int
74+
base = <int64_t>ts
75+
frac = ts - base
76+
if p:
77+
frac = round(frac, p)
78+
return <int64_t>(base * m) + <int64_t>(frac * m)
79+
80+
81+
cpdef inline object precision_from_unit(str unit):
82+
"""
83+
Return a casting of the unit represented to nanoseconds + the precision
84+
to round the fractional part.
85+
86+
Notes
87+
-----
88+
The caller is responsible for ensuring that the default value of "ns"
89+
takes the place of None.
90+
"""
91+
cdef:
92+
int64_t m
93+
int p
94+
95+
if unit == "Y":
96+
m = 1_000_000_000 * 31556952
97+
p = 9
98+
elif unit == "M":
99+
m = 1_000_000_000 * 2629746
100+
p = 9
101+
elif unit == "W":
102+
m = 1_000_000_000 * 3600 * 24 * 7
103+
p = 9
104+
elif unit == "D" or unit == "d":
105+
m = 1_000_000_000 * 3600 * 24
106+
p = 9
107+
elif unit == "h":
108+
m = 1_000_000_000 * 3600
109+
p = 9
110+
elif unit == "m":
111+
m = 1_000_000_000 * 60
112+
p = 9
113+
elif unit == "s":
114+
m = 1_000_000_000
115+
p = 9
116+
elif unit == "ms":
117+
m = 1_000_000
118+
p = 6
119+
elif unit == "us":
120+
m = 1000
121+
p = 3
122+
elif unit == "ns" or unit is None:
123+
m = 1
124+
p = 0
125+
else:
126+
raise ValueError(f"cannot cast unit {unit}")
127+
return m, p
128+
59129

60130
cdef inline int64_t get_datetime64_nanos(object val) except? -1:
61131
"""
@@ -155,6 +225,9 @@ def ensure_timedelta64ns(arr: ndarray, copy: bool=True):
155225
# TODO: check for overflows when going from a lower-resolution to nanos
156226

157227

228+
# ----------------------------------------------------------------------
229+
230+
158231
@cython.boundscheck(False)
159232
@cython.wraparound(False)
160233
def datetime_to_datetime64(ndarray[object] values):

pandas/_libs/tslibs/timedeltas.pxd

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from numpy cimport int64_t
22

33
# Exposed for tslib, not intended for outside use.
4-
cdef int64_t cast_from_unit(object ts, str unit) except? -1
54
cpdef int64_t delta_to_nanoseconds(delta) except? -1
65
cdef convert_to_timedelta64(object ts, object unit)

pandas/_libs/tslibs/timedeltas.pyx

+1-72
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ from pandas._libs.tslibs.util cimport (
2323

2424
from pandas._libs.tslibs.base cimport ABCTimedelta, ABCTimestamp
2525

26-
from pandas._libs.tslibs.ccalendar cimport DAY_NANOS
26+
from pandas._libs.tslibs.conversion cimport cast_from_unit
2727

2828
from pandas._libs.tslibs.np_datetime cimport (
2929
cmp_scalar, td64_to_tdstruct, pandas_timedeltastruct)
@@ -260,77 +260,6 @@ def array_to_timedelta64(object[:] values, unit='ns', errors='raise'):
260260
return iresult.base # .base to access underlying np.ndarray
261261

262262

263-
cpdef inline object precision_from_unit(str unit):
264-
"""
265-
Return a casting of the unit represented to nanoseconds + the precision
266-
to round the fractional part.
267-
268-
Notes
269-
-----
270-
The caller is responsible for ensuring that the default value of "ns"
271-
takes the place of None.
272-
"""
273-
cdef:
274-
int64_t m
275-
int p
276-
277-
if unit == 'Y':
278-
m = 1000000000 * 31556952
279-
p = 9
280-
elif unit == 'M':
281-
m = 1000000000 * 2629746
282-
p = 9
283-
elif unit == 'W':
284-
m = DAY_NANOS * 7
285-
p = 9
286-
elif unit == 'D' or unit == 'd':
287-
m = DAY_NANOS
288-
p = 9
289-
elif unit == 'h':
290-
m = 1000000000 * 3600
291-
p = 9
292-
elif unit == 'm':
293-
m = 1000000000 * 60
294-
p = 9
295-
elif unit == 's':
296-
m = 1000000000
297-
p = 9
298-
elif unit == 'ms':
299-
m = 1000000
300-
p = 6
301-
elif unit == 'us':
302-
m = 1000
303-
p = 3
304-
elif unit == 'ns' or unit is None:
305-
m = 1
306-
p = 0
307-
else:
308-
raise ValueError(f"cannot cast unit {unit}")
309-
return m, p
310-
311-
312-
cdef inline int64_t cast_from_unit(object ts, str unit) except? -1:
313-
""" return a casting of the unit represented to nanoseconds
314-
round the fractional part of a float to our precision, p """
315-
cdef:
316-
int64_t m
317-
int p
318-
319-
m, p = precision_from_unit(unit)
320-
321-
# just give me the unit back
322-
if ts is None:
323-
return m
324-
325-
# cast the unit, multiply base/frace separately
326-
# to avoid precision issues from float -> int
327-
base = <int64_t>ts
328-
frac = ts - base
329-
if p:
330-
frac = round(frac, p)
331-
return <int64_t>(base * m) + <int64_t>(frac * m)
332-
333-
334263
cdef inline int64_t parse_timedelta_string(str ts) except? -1:
335264
"""
336265
Parse a regular format timedelta string. Return an int64_t (in ns)

pandas/core/arrays/timedeltas.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,9 @@
55

66
from pandas._libs import lib, tslibs
77
from pandas._libs.tslibs import NaT, Period, Timedelta, Timestamp, iNaT
8+
from pandas._libs.tslibs.conversion import precision_from_unit
89
from pandas._libs.tslibs.fields import get_timedelta_field
9-
from pandas._libs.tslibs.timedeltas import (
10-
array_to_timedelta64,
11-
parse_timedelta_unit,
12-
precision_from_unit,
13-
)
10+
from pandas._libs.tslibs.timedeltas import array_to_timedelta64, parse_timedelta_unit
1411
from pandas.compat.numpy import function as nv
1512

1613
from pandas.core.dtypes.common import (

0 commit comments

Comments
 (0)