Skip to content

Commit d915cf7

Browse files
committed
Raise ValueError when tz-aware differs in input
Just like `to_datetime` when `format` is not passed, we should raise a `ValueError` if the input contains some tz-aware objects and some naive objects. The change is to identify if the `format` expects tz-aware objects (check for `"%z"` and `"%Z"`) and then compare this expectation with the `tzinfo` of each object. This modification includes relevant tests. Signed-off-by: Antonio Ossa Guerra <aaossa@uc.cl>
1 parent f649643 commit d915cf7

File tree

2 files changed

+23
-1
lines changed

2 files changed

+23
-1
lines changed

pandas/_libs/tslibs/strptime.pyx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ def array_strptime(ndarray[object] values, str fmt, bint exact=True, errors='rai
128128
result_timezone = np.empty(n, dtype='object')
129129

130130
dts.us = dts.ps = dts.as = 0
131+
expect_tz_aware = "%z" in fmt or "%Z" in fmt
131132

132133
for i in range(n):
133134
val = values[i]
@@ -144,6 +145,10 @@ def array_strptime(ndarray[object] values, str fmt, bint exact=True, errors='rai
144145
else:
145146
iresult[i] = pydatetime_to_dt64(val, &dts)
146147
check_dts_bounds(&dts)
148+
if val.tzinfo is None and expect_tz_aware:
149+
raise ValueError("Cannot mix tz-aware with tz-naive values")
150+
elif val.tzinfo is not None and not expect_tz_aware:
151+
raise ValueError("Cannot mix tz-aware with tz-naive values")
147152
result_timezone[i] = val.tzinfo
148153
continue
149154
else:

pandas/tests/tools/test_to_datetime.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,10 +680,27 @@ def test_to_datetime_includes_tz_dtype_on_pydatetime_and_timestamp(self, value):
680680
# Localized value
681681
america_santiago = pytz.timezone("America/Santiago")
682682
result_no_format = to_datetime([america_santiago.localize(value)])
683-
result_with_format = to_datetime([america_santiago.localize(value)], format="%m-%d-%Y")
683+
result_with_format = to_datetime([america_santiago.localize(value)], format="%m-%d-%Y %z")
684684
tm.assert_equal(result_with_format.dtype.tz, america_santiago)
685685
tm.assert_equal(result_no_format, result_with_format)
686686

687+
@pytest.mark.parametrize("value", [datetime(2010, 1, 2, 12, 13, 16), Timestamp("2010-01-02 12:13:17")])
688+
def test_to_datetime_mixing_naive_tzaware_raises(self, value):
689+
# GH 49298
690+
msg = "Cannot mix tz-aware with tz-naive values"
691+
america_santiago = pytz.timezone("America/Santiago")
692+
# Fail if format expects tz but input is not localized
693+
with pytest.raises(ValueError, match=msg):
694+
to_datetime([value], format="%m-%d-%Y %z")
695+
# Fail if format does not expect tz but input is localized
696+
with pytest.raises(ValueError, match=msg):
697+
to_datetime([america_santiago.localize(value)], format="%m-%d-%Y")
698+
# Mixed input should fail in both cases
699+
with pytest.raises(ValueError, match=msg):
700+
to_datetime([value, america_santiago.localize(value)], format="%m-%d-%Y %z")
701+
with pytest.raises(ValueError, match=msg):
702+
to_datetime([value, america_santiago.localize(value)], format="%m-%d-%Y")
703+
687704
def test_to_datetime_pydatetime(self):
688705
actual = to_datetime(datetime(2008, 1, 15))
689706
assert actual == datetime(2008, 1, 15)

0 commit comments

Comments
 (0)