Skip to content

Commit 39b15aa

Browse files
POC using proper logic
1 parent fb67db4 commit 39b15aa

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

pandas/_libs/tslibs/timedeltas.pyx

+41
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,47 @@ def array_to_timedelta64(object[:] values, unit='ns', errors='raise'):
246246
return iresult.base # .base to access underlying np.ndarray
247247

248248

249+
def precision_from_unit(object unit):
250+
cdef:
251+
int64_t m
252+
int p
253+
254+
if unit == 'Y':
255+
m = 1000000000L * 31556952
256+
p = 9
257+
elif unit == 'M':
258+
m = 1000000000L * 2629746
259+
p = 9
260+
elif unit == 'W':
261+
m = 1000000000L * DAY_SECONDS * 7
262+
p = 9
263+
elif unit == 'D' or unit == 'd':
264+
m = 1000000000L * DAY_SECONDS
265+
p = 9
266+
elif unit == 'h':
267+
m = 1000000000L * 3600
268+
p = 9
269+
elif unit == 'm':
270+
m = 1000000000L * 60
271+
p = 9
272+
elif unit == 's':
273+
m = 1000000000L
274+
p = 9
275+
elif unit == 'ms':
276+
m = 1000000L
277+
p = 6
278+
elif unit == 'us':
279+
m = 1000L
280+
p = 3
281+
elif unit == 'ns' or unit is None:
282+
m = 1L
283+
p = 0
284+
else:
285+
raise ValueError("cannot cast unit {unit}".format(unit=unit))
286+
287+
return m, p
288+
289+
249290
cdef inline int64_t cast_from_unit(object ts, object unit) except? -1:
250291
""" return a casting of the unit represented to nanoseconds
251292
round the fractional part of a float to our precision, p """

pandas/core/arrays/timedeltas.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from pandas._libs.tslibs import NaT, Timedelta, Timestamp, iNaT
1212
from pandas._libs.tslibs.fields import get_timedelta_field
1313
from pandas._libs.tslibs.timedeltas import (
14-
array_to_timedelta64, parse_timedelta_unit)
14+
array_to_timedelta64, parse_timedelta_unit, precision_from_unit)
1515
import pandas.compat as compat
1616
from pandas.util._decorators import Appender
1717

@@ -918,9 +918,16 @@ def sequence_to_td64ns(data, copy=False, unit="ns", errors="raise"):
918918
copy = copy and not copy_made
919919

920920
elif is_float_dtype(data.dtype):
921-
# object_to_td64ns has custom logic for float -> int conversion
922-
# to avoid precision issues
923-
data = objects_to_td64ns(data, unit=unit, errors=errors)
921+
# cast the unit, multiply base/frace separately
922+
# to avoid precision issues from float -> int
923+
mask = np.isnan(data)
924+
m, p = precision_from_unit(unit)
925+
base = data.astype(np.int64)
926+
frac = data - base
927+
if p:
928+
frac = np.round(frac, p)
929+
data = (base * m + (frac * m).astype(np.int64)).view('timedelta64[ns]')
930+
data[mask] = iNaT
924931
copy = False
925932

926933
elif is_timedelta64_dtype(data.dtype):

0 commit comments

Comments
 (0)