Skip to content

Commit 1f8cf19

Browse files
authored
REF: avoid python-space calls in _get_dst_hours (#46436)
1 parent 2d6a2c3 commit 1f8cf19

File tree

1 file changed

+26
-16
lines changed

1 file changed

+26
-16
lines changed

pandas/_libs/tslibs/tzconversion.pyx

+26-16
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ from cpython.datetime cimport (
1515

1616
import_datetime()
1717

18-
from dateutil.tz import tzutc
1918
import numpy as np
2019
import pytz
2120

@@ -40,7 +39,6 @@ from pandas._libs.tslibs.np_datetime cimport (
4039
)
4140
from pandas._libs.tslibs.timezones cimport (
4241
get_dst_info,
43-
get_utcoffset,
4442
is_fixed_offset,
4543
is_tzlocal,
4644
is_utc,
@@ -194,6 +192,8 @@ timedelta-like}
194192
result_b[:] = NPY_NAT
195193

196194
for i in range(n):
195+
# This loops resembles the "Find the two best possibilities" block
196+
# in pytz's DstTZInfo.localize method.
197197
val = vals[i]
198198
if val == NPY_NAT:
199199
continue
@@ -339,27 +339,37 @@ cdef inline str _render_tstamp(int64_t val):
339339

340340
cdef ndarray[int64_t] _get_dst_hours(
341341
# vals only needed here to potential render an exception message
342-
ndarray[int64_t] vals,
342+
const int64_t[:] vals,
343343
ndarray[int64_t] result_a,
344344
ndarray[int64_t] result_b,
345345
):
346346
cdef:
347-
Py_ssize_t n = vals.shape[0]
348-
ndarray[uint8_t, cast=True] both_nat, both_eq
347+
Py_ssize_t i, n = vals.shape[0]
348+
ndarray[uint8_t, cast=True] mismatch
349349
ndarray[int64_t] delta, dst_hours
350-
ndarray trans_idx, grp, a_idx, b_idx, one_diff
350+
ndarray[intp_t] switch_idxs, trans_idx, grp, a_idx, b_idx, one_diff
351351
list trans_grp
352+
intp_t switch_idx
353+
int64_t left, right
352354

353355
dst_hours = np.empty(n, dtype=np.int64)
354356
dst_hours[:] = NPY_NAT
355357

356-
# Get the ambiguous hours (given the above, these are the hours
357-
# where result_a != result_b and neither of them are NAT)
358-
both_nat = np.logical_and(result_a != NPY_NAT, result_b != NPY_NAT)
359-
both_eq = result_a == result_b
360-
trans_idx = np.squeeze(np.nonzero(np.logical_and(both_nat, ~both_eq)))
358+
mismatch = np.zeros(n, dtype=bool)
359+
360+
for i in range(n):
361+
left = result_a[i]
362+
right = result_b[i]
363+
364+
# Get the ambiguous hours (given the above, these are the hours
365+
# where result_a != result_b and neither of them are NAT)
366+
if left != right and left != NPY_NAT and right != NPY_NAT:
367+
mismatch[i] = 1
368+
369+
trans_idx = mismatch.nonzero()[0]
370+
361371
if trans_idx.size == 1:
362-
stamp = _render_tstamp(vals[trans_idx])
372+
stamp = _render_tstamp(vals[trans_idx[0]])
363373
raise pytz.AmbiguousTimeError(
364374
f"Cannot infer dst time from {stamp} as there "
365375
"are no repeated times"
@@ -385,14 +395,14 @@ cdef ndarray[int64_t] _get_dst_hours(
385395

386396
# Find the index for the switch and pull from a for dst and b
387397
# for standard
388-
switch_idx = (delta <= 0).nonzero()[0]
389-
if switch_idx.size > 1:
398+
switch_idxs = (delta <= 0).nonzero()[0]
399+
if switch_idxs.size > 1:
390400
raise pytz.AmbiguousTimeError(
391-
f"There are {switch_idx.size} dst switches when "
401+
f"There are {switch_idxs.size} dst switches when "
392402
"there should only be 1."
393403
)
394404

395-
switch_idx = switch_idx[0] + 1 # TODO: declare type for switch_idx
405+
switch_idx = switch_idxs[0] + 1
396406
# Pull the only index and adjust
397407
a_idx = grp[:switch_idx]
398408
b_idx = grp[switch_idx:]

0 commit comments

Comments
 (0)