@@ -439,7 +439,7 @@ def first_non_null(values: ndarray) -> int:
439
439
@ cython.wraparound (False )
440
440
@ cython.boundscheck (False )
441
441
cpdef array_to_datetime(
442
- ndarray[ object ] values,
442
+ ndarray values, # object dtype, arbitrary ndim
443
443
str errors = " raise" ,
444
444
bint dayfirst = False ,
445
445
bint yearfirst = False ,
@@ -478,7 +478,7 @@ cpdef array_to_datetime(
478
478
tzinfo or None
479
479
"""
480
480
cdef:
481
- Py_ssize_t i, n = len ( values)
481
+ Py_ssize_t i, n = values.size
482
482
object val, tz
483
483
ndarray[int64_t] iresult
484
484
npy_datetimestruct dts
@@ -498,15 +498,18 @@ cpdef array_to_datetime(
498
498
datetime py_dt
499
499
tzinfo tz_out = None
500
500
bint found_tz = False , found_naive = False
501
+ cnp.broadcast mi
501
502
502
503
# specify error conditions
503
504
assert is_raise or is_ignore or is_coerce
504
505
505
- result = np.empty(n, dtype = " M8[ns]" )
506
- iresult = result.view(" i8" )
506
+ result = np.empty((< object > values).shape, dtype = " M8[ns]" )
507
+ mi = cnp.PyArray_MultiIterNew2(result, values)
508
+ iresult = result.view(" i8" ).ravel()
507
509
508
510
for i in range (n):
509
- val = values[i]
511
+ # Analogous to `val = values[i]`
512
+ val = < object > (< PyObject** > cnp.PyArray_MultiIter_DATA(mi, 1 ))[0 ]
510
513
511
514
try :
512
515
if checknull_with_nat_and_na(val):
@@ -524,7 +527,7 @@ cpdef array_to_datetime(
524
527
found_tz,
525
528
utc_convert,
526
529
)
527
- result [i] = parse_pydatetime(val, & dts, utc_convert)
530
+ iresult [i] = parse_pydatetime(val, & dts, utc_convert)
528
531
529
532
elif PyDate_Check(val):
530
533
iresult[i] = pydate_to_dt64(val, & dts)
@@ -559,6 +562,7 @@ cpdef array_to_datetime(
559
562
560
563
if len (val) == 0 or val in nat_strings:
561
564
iresult[i] = NPY_NAT
565
+ cnp.PyArray_MultiIter_NEXT(mi)
562
566
continue
563
567
564
568
string_to_dts_failed = string_to_dts(
@@ -569,6 +573,7 @@ cpdef array_to_datetime(
569
573
# An error at this point is a _parsing_ error
570
574
# specifically _not_ OutOfBoundsDatetime
571
575
if parse_today_now(val, & iresult[i], utc):
576
+ cnp.PyArray_MultiIter_NEXT(mi)
572
577
continue
573
578
574
579
py_dt = parse_datetime_string(val,
@@ -614,10 +619,13 @@ cpdef array_to_datetime(
614
619
else :
615
620
raise TypeError (f" {type(val)} is not convertible to datetime" )
616
621
622
+ cnp.PyArray_MultiIter_NEXT(mi)
623
+
617
624
except OutOfBoundsDatetime as ex:
618
625
ex.args = (f" {ex}, at position {i}" ,)
619
626
if is_coerce:
620
627
iresult[i] = NPY_NAT
628
+ cnp.PyArray_MultiIter_NEXT(mi)
621
629
continue
622
630
elif is_raise:
623
631
raise
@@ -627,6 +635,7 @@ cpdef array_to_datetime(
627
635
ex.args = (f" {ex}, at position {i}" ,)
628
636
if is_coerce:
629
637
iresult[i] = NPY_NAT
638
+ cnp.PyArray_MultiIter_NEXT(mi)
630
639
continue
631
640
elif is_raise:
632
641
raise
@@ -650,7 +659,7 @@ cpdef array_to_datetime(
650
659
651
660
@ cython.wraparound (False )
652
661
@ cython.boundscheck (False )
653
- cdef ndarray[ object ] ignore_errors_out_of_bounds_fallback(ndarray[ object ] values):
662
+ cdef ndarray ignore_errors_out_of_bounds_fallback(ndarray values):
654
663
"""
655
664
Fallback for array_to_datetime if an OutOfBoundsDatetime is raised
656
665
and errors == "ignore"
@@ -664,27 +673,36 @@ cdef ndarray[object] ignore_errors_out_of_bounds_fallback(ndarray[object] values
664
673
ndarray[object]
665
674
"""
666
675
cdef:
667
- Py_ssize_t i, n = len ( values)
676
+ Py_ssize_t i, n = values.size
668
677
object val
678
+ cnp.broadcast mi
679
+ ndarray[object ] oresult
680
+ ndarray oresult_nd
669
681
670
- oresult = cnp.PyArray_EMPTY(values.ndim, values.shape, cnp.NPY_OBJECT, 0 )
682
+ oresult_nd = cnp.PyArray_EMPTY(values.ndim, values.shape, cnp.NPY_OBJECT, 0 )
683
+ mi = cnp.PyArray_MultiIterNew2(oresult_nd, values)
684
+ oresult = oresult_nd.ravel()
671
685
672
686
for i in range (n):
673
- val = values[i]
687
+ # Analogous to `val = values[i]`
688
+ val = < object > (< PyObject** > cnp.PyArray_MultiIter_DATA(mi, 1 ))[0 ]
674
689
675
690
# set as nan except if its a NaT
676
691
if checknull_with_nat_and_na(val):
677
692
if isinstance (val, float ):
678
693
oresult[i] = np.nan
679
694
else :
680
- oresult[i] = NaT
695
+ oresult[i] = < object > NaT
681
696
elif is_datetime64_object(val):
682
697
if get_datetime64_value(val) == NPY_NAT:
683
- oresult[i] = NaT
698
+ oresult[i] = < object > NaT
684
699
else :
685
700
oresult[i] = val.item()
686
701
else :
687
702
oresult[i] = val
703
+
704
+ cnp.PyArray_MultiIter_NEXT(mi)
705
+
688
706
return oresult
689
707
690
708
@@ -719,24 +737,30 @@ cdef _array_to_datetime_object(
719
737
Literal[None]
720
738
"""
721
739
cdef:
722
- Py_ssize_t i, n = len ( values)
740
+ Py_ssize_t i, n = values.size
723
741
object val
724
742
bint is_ignore = errors == " ignore"
725
743
bint is_coerce = errors == " coerce"
726
744
bint is_raise = errors == " raise"
745
+ ndarray oresult_nd
727
746
ndarray[object ] oresult
728
747
npy_datetimestruct dts
748
+ cnp.broadcast mi
729
749
730
750
assert is_raise or is_ignore or is_coerce
731
751
732
- oresult = cnp.PyArray_EMPTY(values.ndim, values.shape, cnp.NPY_OBJECT, 0 )
752
+ oresult_nd = cnp.PyArray_EMPTY(values.ndim, values.shape, cnp.NPY_OBJECT, 0 )
753
+ mi = cnp.PyArray_MultiIterNew2(oresult_nd, values)
754
+ oresult = oresult_nd.ravel()
733
755
734
756
# We return an object array and only attempt to parse:
735
757
# 1) NaT or NaT-like values
736
758
# 2) datetime strings, which we return as datetime.datetime
737
759
# 3) special strings - "now" & "today"
738
760
for i in range (n):
739
- val = values[i]
761
+ # Analogous to: val = values[i]
762
+ val = < object > (< PyObject** > cnp.PyArray_MultiIter_DATA(mi, 1 ))[0 ]
763
+
740
764
if checknull_with_nat_and_na(val) or PyDateTime_Check(val):
741
765
# GH 25978. No need to parse NaT-like or datetime-like vals
742
766
oresult[i] = val
@@ -747,6 +771,7 @@ cdef _array_to_datetime_object(
747
771
748
772
if len (val) == 0 or val in nat_strings:
749
773
oresult[i] = " NaT"
774
+ cnp.PyArray_MultiIter_NEXT(mi)
750
775
continue
751
776
try :
752
777
oresult[i] = parse_datetime_string(val, dayfirst = dayfirst,
@@ -757,6 +782,7 @@ cdef _array_to_datetime_object(
757
782
ex.args = (f" {ex}, at position {i}" , )
758
783
if is_coerce:
759
784
oresult[i] = < object > NaT
785
+ cnp.PyArray_MultiIter_NEXT(mi)
760
786
continue
761
787
if is_raise:
762
788
raise
@@ -765,7 +791,10 @@ cdef _array_to_datetime_object(
765
791
if is_raise:
766
792
raise
767
793
return values, None
768
- return oresult, None
794
+
795
+ cnp.PyArray_MultiIter_NEXT(mi)
796
+
797
+ return oresult_nd, None
769
798
770
799
771
800
def array_to_datetime_with_tz (ndarray values , tzinfo tz ):
0 commit comments