Skip to content

Commit e479c04

Browse files
POC using proper logic
1 parent fb67db4 commit e479c04

File tree

2 files changed

+56
-8
lines changed

2 files changed

+56
-8
lines changed

pandas/_libs/tslibs/timedeltas.pyx

Lines changed: 41 additions & 0 deletions
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

Lines changed: 15 additions & 8 deletions
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):
@@ -999,10 +1006,10 @@ def objects_to_td64ns(data, unit="ns", errors="raise"):
9991006
----------
10001007
data : ndarray or Index
10011008
unit : str, default "ns"
1002-
The timedelta unit to treat integers as multiples of.
1003-
errors : {"raise", "coerce", "ignore"}, default "raise"
1004-
How to handle elements that cannot be converted to timedelta64[ns].
1005-
See ``pandas.to_timedelta`` for details.
1009+
The timedelta unit to treat integers as array_to_timedelta64
1010+
errors : {"raise", "coerce", "ignore"}, defaarray_to_timedelta64
1011+
How to handle elements that cannot be coarray_to_timedelta64
1012+
See ``pandas.to_timedelta`` for details.array_to_timedelta64
10061013
10071014
Returns
10081015
-------

0 commit comments

Comments
 (0)