7575from pandas .core .construction import extract_array
7676from pandas .core .indexes .base import Index
7777from pandas .core .indexes .datetimes import DatetimeIndex
78+
7879if TYPE_CHECKING :
7980 from collections .abc import (
8081 Callable ,
@@ -478,72 +479,78 @@ def _array_strptime_with_fallback(
478479 return Index (result , dtype = result .dtype , name = name )
479480
480481
481-
482-
483-
484482def _to_datetime_with_unit (arg , unit , name , utc : bool , errors : str ) -> DatetimeIndex :
485483 """
486484 to_datetime specialized to the case where a 'unit' is passed.
487- Fixes a bug where scalar out-of-bounds values were not raising
488- an error consistently.
489485 """
490- import pdb ; pdb .set_trace ()
491-
492- # Ensure we handle both array-likes and scalars the same way.
493- # extract_array can return a scalar if 'arg' is scalar-like;
494- # so we force everything into at least 1D shape.
495486 arg = extract_array (arg , extract_numpy = True )
487+ # Fix GH#60677
488+ # Ensure scalar and array-like both become arrays
489+ # (so both paths use the same code).
496490 arg = np .atleast_1d (arg )
497491
498492 # GH#30050 pass an ndarray to tslib.array_to_datetime
499493 # because it expects an ndarray argument
500494 if isinstance (arg , IntegerArray ):
501- # For IntegerArray, we can directly convert
502495 arr = arg .astype (f"datetime64[{ unit } ]" )
503496 tz_parsed = None
504-
505497 else :
506- # Now we have a guaranteed ndarray
507498 arg = np .asarray (arg )
508499
509500 if arg .dtype .kind in "iu" :
510501 # Note we can't do "f" here because that could induce unwanted
511- # rounding GH#14156, GH#20445
502+ # rounding GH#14156, GH#20445
503+ # Fix GH#60677
504+ # ------------------------------------------------
505+ # A) **Check for uint64 values above int64 max**
506+ # so we don't accidentally wrap around to -1, etc.
507+ # ------------------------------------------------
508+ if arg .dtype .kind == "u" : # unsigned
509+ above_max = arg > np .iinfo (np .int64 ).max
510+ if above_max .any ():
511+ if errors == "raise" :
512+ raise OutOfBoundsDatetime (
513+ "Cannot convert uint64 values above"
514+ f"{ np .iinfo (np .int64 ).max } "
515+ "to a 64-bit signed datetime64[ns]."
516+ )
517+ else :
518+ # For errors != "raise" (e.g. "coerce" or "ignore"),
519+ # we can replace out-of-range entries with NaN (-> NaT),
520+ # then switch to the fallback object path:
521+ arg = arg .astype (object )
522+ arg [above_max ] = np .nan
523+ return _to_datetime_with_unit (arg , unit , name , utc , errors )
524+
525+ # ------------------------------------------------
526+ # B) Proceed with normal numeric -> datetime logic
527+ # ------------------------------------------------
512528 arr = arg .astype (f"datetime64[{ unit } ]" , copy = False )
513529 try :
514530 arr = astype_overflowsafe (arr , np .dtype ("M8[ns]" ), copy = False )
515531 except OutOfBoundsDatetime :
516532 if errors == "raise" :
517533 raise
518- # errors != "raise" => coerce to object and retry
519534 arg = arg .astype (object )
520535 return _to_datetime_with_unit (arg , unit , name , utc , errors )
521536 tz_parsed = None
522537
523538 elif arg .dtype .kind == "f" :
524- # Floating dtypes
525539 with np .errstate (over = "raise" ):
526540 try :
527541 arr = cast_from_unit_vectorized (arg , unit = unit )
528542 except OutOfBoundsDatetime as err :
529543 if errors != "raise" :
530- # coerce to object and retry
531544 return _to_datetime_with_unit (
532- arg .astype (object ),
533- unit ,
534- name ,
535- utc ,
536- errors ,
545+ arg .astype (object ), unit , name , utc , errors
537546 )
538547 raise OutOfBoundsDatetime (
539548 f"cannot convert input with unit '{ unit } '"
540549 ) from err
541550
542551 arr = arr .view ("M8[ns]" )
543552 tz_parsed = None
544-
545553 else :
546- # Fallback: treat as object dtype
547554 arg = arg .astype (object , copy = False )
548555 arr , tz_parsed = tslib .array_to_datetime (
549556 arg ,
@@ -553,22 +560,21 @@ def _to_datetime_with_unit(arg, unit, name, utc: bool, errors: str) -> DatetimeI
553560 creso = NpyDatetimeUnit .NPY_FR_ns .value ,
554561 )
555562
556- # Construct a DatetimeIndex from the array
557563 result = DatetimeIndex (arr , name = name )
558564
559- # May need to localize result to parsed tz or convert to UTC if requested
565+ # GH#23758: We may still need to localize the result with tz
566+ # GH#25546: Apply tz_parsed first (from arg), then tz (from caller)
567+ # result will be naive but in UTC
560568 result = result .tz_localize ("UTC" ).tz_convert (tz_parsed )
561569
562570 if utc :
563571 if result .tz is None :
564572 result = result .tz_localize ("utc" )
565573 else :
566574 result = result .tz_convert ("utc" )
567-
568575 return result
569576
570577
571-
572578def _adjust_to_origin (arg , origin , unit ):
573579 """
574580 Helper function for to_datetime.
0 commit comments