1
1
import numpy as np
2
2
3
3
cimport numpy as cnp
4
+ from libc.math cimport log10
4
5
from numpy cimport (
5
6
int32_t,
6
7
int64_t,
@@ -81,7 +82,11 @@ TD64NS_DTYPE = np.dtype("m8[ns]")
81
82
# ----------------------------------------------------------------------
82
83
# Unit Conversion Helpers
83
84
84
- cdef int64_t cast_from_unit(object ts, str unit) except ? - 1 :
85
+ cdef int64_t cast_from_unit(
86
+ object ts,
87
+ str unit,
88
+ NPY_DATETIMEUNIT out_reso = NPY_FR_ns
89
+ ) except ? - 1 :
85
90
"""
86
91
Return a casting of the unit represented to nanoseconds
87
92
round the fractional part of a float to our precision, p.
@@ -99,7 +104,7 @@ cdef int64_t cast_from_unit(object ts, str unit) except? -1:
99
104
int64_t m
100
105
int p
101
106
102
- m, p = precision_from_unit(unit)
107
+ m, p = precision_from_unit(unit, out_reso )
103
108
104
109
# just give me the unit back
105
110
if ts is None :
@@ -119,7 +124,7 @@ cdef int64_t cast_from_unit(object ts, str unit) except? -1:
119
124
if is_float_object(ts):
120
125
ts = int (ts)
121
126
dt64obj = np.datetime64(ts, unit)
122
- return get_datetime64_nanos(dt64obj, NPY_FR_ns )
127
+ return get_datetime64_nanos(dt64obj, out_reso )
123
128
124
129
# cast the unit, multiply base/frac separately
125
130
# to avoid precision issues from float -> int
@@ -142,7 +147,10 @@ cdef int64_t cast_from_unit(object ts, str unit) except? -1:
142
147
) from err
143
148
144
149
145
- cpdef inline (int64_t, int ) precision_from_unit(str unit):
150
+ cpdef inline (int64_t, int ) precision_from_unit(
151
+ str unit,
152
+ NPY_DATETIMEUNIT out_reso = NPY_DATETIMEUNIT.NPY_FR_ns,
153
+ ):
146
154
"""
147
155
Return a casting of the unit represented to nanoseconds + the precision
148
156
to round the fractional part.
@@ -154,45 +162,39 @@ cpdef inline (int64_t, int) precision_from_unit(str unit):
154
162
"""
155
163
cdef:
156
164
int64_t m
165
+ int64_t multiplier
157
166
int p
158
167
NPY_DATETIMEUNIT reso = abbrev_to_npy_unit(unit)
159
168
169
+ multiplier = periods_per_second(out_reso)
170
+
160
171
if reso == NPY_DATETIMEUNIT.NPY_FR_Y:
161
172
# each 400 years we have 97 leap years, for an average of 97/400=.2425
162
173
# extra days each year. We get 31556952 by writing
163
174
# 3600*24*365.2425=31556952
164
- m = 1 _000_000_000 * 31556952
165
- p = 9
175
+ m = multiplier * 31556952
166
176
elif reso == NPY_DATETIMEUNIT.NPY_FR_M:
167
177
# 2629746 comes from dividing the "Y" case by 12.
168
- m = 1 _000_000_000 * 2629746
169
- p = 9
178
+ m = multiplier * 2629746
170
179
elif reso == NPY_DATETIMEUNIT.NPY_FR_W:
171
- m = 1 _000_000_000 * 3600 * 24 * 7
172
- p = 9
180
+ m = multiplier * 3600 * 24 * 7
173
181
elif reso == NPY_DATETIMEUNIT.NPY_FR_D:
174
- m = 1 _000_000_000 * 3600 * 24
175
- p = 9
182
+ m = multiplier * 3600 * 24
176
183
elif reso == NPY_DATETIMEUNIT.NPY_FR_h:
177
- m = 1 _000_000_000 * 3600
178
- p = 9
184
+ m = multiplier * 3600
179
185
elif reso == NPY_DATETIMEUNIT.NPY_FR_m:
180
- m = 1 _000_000_000 * 60
181
- p = 9
186
+ m = multiplier * 60
182
187
elif reso == NPY_DATETIMEUNIT.NPY_FR_s:
183
- m = 1 _000_000_000
184
- p = 9
188
+ m = multiplier
185
189
elif reso == NPY_DATETIMEUNIT.NPY_FR_ms:
186
- m = 1 _000_000
187
- p = 6
190
+ m = multiplier // 1 _000
188
191
elif reso == NPY_DATETIMEUNIT.NPY_FR_us:
189
- m = 1000
190
- p = 3
192
+ m = multiplier // 1 _000_000
191
193
elif reso == NPY_DATETIMEUNIT.NPY_FR_ns or reso == NPY_DATETIMEUNIT.NPY_FR_GENERIC:
192
- m = 1
193
- p = 0
194
+ m = multiplier // 1 _000_000_000
194
195
else :
195
196
raise ValueError (f" cannot cast unit {unit}" )
197
+ p = < int > log10(m) # number of digits in 'm' minus 1
196
198
return m, p
197
199
198
200
@@ -294,9 +296,14 @@ cdef _TSObject convert_to_tsobject(object ts, tzinfo tz, str unit,
294
296
if ts == NPY_NAT:
295
297
obj.value = NPY_NAT
296
298
else :
297
- ts = cast_from_unit(ts, unit)
299
+ if unit is None :
300
+ unit = " ns"
301
+ in_reso = abbrev_to_npy_unit(unit)
302
+ reso = get_supported_reso(in_reso)
303
+ ts = cast_from_unit(ts, unit, reso)
298
304
obj.value = ts
299
- pandas_datetime_to_datetimestruct(ts, NPY_FR_ns, & obj.dts)
305
+ obj.creso = reso
306
+ pandas_datetime_to_datetimestruct(ts, reso, & obj.dts)
300
307
elif is_float_object(ts):
301
308
if ts != ts or ts == NPY_NAT:
302
309
obj.value = NPY_NAT
0 commit comments