Skip to content

Commit 32b8cd2

Browse files
authored
ENH: infer resolution in array_to_datetime_with_tz (#55822)
1 parent 365448d commit 32b8cd2

File tree

3 files changed

+53
-2
lines changed

3 files changed

+53
-2
lines changed

pandas/_libs/tslib.pyx

+21
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,8 @@ def array_to_datetime_with_tz(
693693
object item
694694
int64_t ival
695695
_TSObject tsobj
696+
bint infer_reso = creso == NPY_DATETIMEUNIT.NPY_FR_GENERIC
697+
DatetimeParseState state = DatetimeParseState(creso)
696698

697699
for i in range(n):
698700
# Analogous to `item = values[i]`
@@ -707,6 +709,9 @@ def array_to_datetime_with_tz(
707709
item, tz=tz, unit="ns", dayfirst=dayfirst, yearfirst=yearfirst, nanos=0
708710
)
709711
if tsobj.value != NPY_NAT:
712+
state.update_creso(tsobj.creso)
713+
if infer_reso:
714+
creso = state.creso
710715
tsobj.ensure_reso(creso, item, round_ok=True)
711716
ival = tsobj.value
712717

@@ -715,4 +720,20 @@ def array_to_datetime_with_tz(
715720

716721
cnp.PyArray_MultiIter_NEXT(mi)
717722

723+
if infer_reso:
724+
if state.creso_ever_changed:
725+
# We encountered mismatched resolutions, need to re-parse with
726+
# the correct one.
727+
return array_to_datetime_with_tz(values, tz=tz, creso=creso)
728+
729+
# Otherwise we can use the single reso that we encountered and avoid
730+
# a second pass.
731+
abbrev = npy_unit_to_abbrev(creso)
732+
result = result.view(f"M8[{abbrev}]")
733+
elif creso == NPY_DATETIMEUNIT.NPY_FR_GENERIC:
734+
# We didn't find any non-NaT to infer from, default to "ns"
735+
result = result.view("M8[ns]")
736+
else:
737+
abbrev = npy_unit_to_abbrev(creso)
738+
result = result.view(f"M8[{abbrev}]")
718739
return result

pandas/core/arrays/datetimes.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2241,14 +2241,14 @@ def _sequence_to_dt64(
22412241
data = data.astype(np.int64)
22422242
elif tz is not None and ambiguous == "raise":
22432243
obj_data = np.asarray(data, dtype=object)
2244-
i8data = tslib.array_to_datetime_with_tz(
2244+
result = tslib.array_to_datetime_with_tz(
22452245
obj_data,
22462246
tz=tz,
22472247
dayfirst=dayfirst,
22482248
yearfirst=yearfirst,
22492249
creso=abbrev_to_npy_unit(out_unit),
22502250
)
2251-
return i8data.view(out_dtype), tz, None
2251+
return result, tz, None
22522252
else:
22532253
# data comes back here as either i8 to denote UTC timestamps
22542254
# or M8[ns] to denote wall times

pandas/tests/tslibs/test_array_to_datetime.py

+30
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,43 @@
1010
import pytest
1111

1212
from pandas._libs import (
13+
NaT,
1314
iNaT,
1415
tslib,
1516
)
17+
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
1618

1719
from pandas import Timestamp
1820
import pandas._testing as tm
1921

22+
creso_infer = NpyDatetimeUnit.NPY_FR_GENERIC.value
23+
24+
25+
class TestArrayToDatetimeWithTZResolutionInference:
26+
def test_array_to_datetime_with_tz_resolution(self):
27+
tz = tzoffset("custom", 3600)
28+
vals = np.array(["2016-01-01 02:03:04.567", NaT], dtype=object)
29+
res = tslib.array_to_datetime_with_tz(vals, tz, False, False, creso_infer)
30+
assert res.dtype == "M8[ms]"
31+
32+
vals2 = np.array([datetime(2016, 1, 1, 2, 3, 4), NaT], dtype=object)
33+
res2 = tslib.array_to_datetime_with_tz(vals2, tz, False, False, creso_infer)
34+
assert res2.dtype == "M8[us]"
35+
36+
vals3 = np.array([NaT, np.datetime64(12345, "s")], dtype=object)
37+
res3 = tslib.array_to_datetime_with_tz(vals3, tz, False, False, creso_infer)
38+
assert res3.dtype == "M8[s]"
39+
40+
def test_array_to_datetime_with_tz_resolution_all_nat(self):
41+
tz = tzoffset("custom", 3600)
42+
vals = np.array(["NaT"], dtype=object)
43+
res = tslib.array_to_datetime_with_tz(vals, tz, False, False, creso_infer)
44+
assert res.dtype == "M8[ns]"
45+
46+
vals2 = np.array([NaT, NaT], dtype=object)
47+
res2 = tslib.array_to_datetime_with_tz(vals2, tz, False, False, creso_infer)
48+
assert res2.dtype == "M8[ns]"
49+
2050

2151
@pytest.mark.parametrize(
2252
"data,expected",

0 commit comments

Comments
 (0)