@@ -108,22 +108,41 @@ cdef int64_t cast_from_unit(object ts, str unit) except? -1:
108108 if ts is None :
109109 return m
110110
111- if unit in [" Y" , " M" ] and is_float_object(ts) and not ts.is_integer():
112- # GH#47267 it is clear that 2 "M" corresponds to 1970-02-01,
113- # but not clear what 2.5 "M" corresponds to, so we will
114- # disallow that case.
115- raise ValueError (
116- f" Conversion of non-round float with unit={unit} "
117- " is ambiguous"
118- )
111+ if unit in [" Y" , " M" ]:
112+ if is_float_object(ts) and not ts.is_integer():
113+ # GH#47267 it is clear that 2 "M" corresponds to 1970-02-01,
114+ # but not clear what 2.5 "M" corresponds to, so we will
115+ # disallow that case.
116+ raise ValueError (
117+ f" Conversion of non-round float with unit={unit} "
118+ " is ambiguous"
119+ )
120+ # GH#47266 go through np.datetime64 to avoid weird results e.g. with "Y"
121+ # and 150 we'd get 2120-01-01 09:00:00
122+ if is_float_object(ts):
123+ ts = int (ts)
124+ dt64obj = np.datetime64(ts, unit)
125+ return get_datetime64_nanos(dt64obj, NPY_FR_ns)
119126
120127 # cast the unit, multiply base/frace separately
121128 # to avoid precision issues from float -> int
122- base = < int64_t> ts
129+ try :
130+ base = < int64_t> ts
131+ except OverflowError as err:
132+ raise OutOfBoundsDatetime(
133+ f" cannot convert input {ts} with the unit '{unit}'"
134+ ) from err
135+
123136 frac = ts - base
124137 if p:
125138 frac = round (frac, p)
126- return < int64_t> (base * m) + < int64_t> (frac * m)
139+
140+ try :
141+ return < int64_t> (base * m) + < int64_t> (frac * m)
142+ except OverflowError as err:
143+ raise OutOfBoundsDatetime(
144+ f" cannot convert input {ts} with the unit '{unit}'"
145+ ) from err
127146
128147
129148cpdef inline (int64_t, int ) precision_from_unit(str unit):
@@ -278,25 +297,13 @@ cdef _TSObject convert_to_tsobject(object ts, tzinfo tz, str unit,
278297 if ts == NPY_NAT:
279298 obj.value = NPY_NAT
280299 else :
281- if unit in [" Y" , " M" ]:
282- # GH#47266 cast_from_unit leads to weird results e.g. with "Y"
283- # and 150 we'd get 2120-01-01 09:00:00
284- ts = np.datetime64(ts, unit)
285- return convert_to_tsobject(ts, tz, None , False , False )
286-
287- ts = ts * cast_from_unit(None , unit)
300+ ts = cast_from_unit(ts, unit)
288301 obj.value = ts
289302 pandas_datetime_to_datetimestruct(ts, NPY_FR_ns, & obj.dts)
290303 elif is_float_object(ts):
291304 if ts != ts or ts == NPY_NAT:
292305 obj.value = NPY_NAT
293306 else :
294- if unit in [" Y" , " M" ]:
295- if ts == int (ts):
296- # GH#47266 Avoid cast_from_unit, which would give weird results
297- # e.g. with "Y" and 150.0 we'd get 2120-01-01 09:00:00
298- return convert_to_tsobject(int (ts), tz, unit, False , False )
299-
300307 ts = cast_from_unit(ts, unit)
301308 obj.value = ts
302309 pandas_datetime_to_datetimestruct(ts, NPY_FR_ns, & obj.dts)
0 commit comments