Skip to content

Commit 3fe94a0

Browse files
committed
BUG: Correctly localize naive ts strings with Series and datetimetz dtype (#17415)
Add whatsnew Fix lint error Rebase and move whatsnew note Move whatsnew and add tests
1 parent 99d384d commit 3fe94a0

File tree

3 files changed

+22
-8
lines changed

3 files changed

+22
-8
lines changed

doc/source/whatsnew/v0.22.0.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ Conversion
263263
- Adding a ``Period`` object to a ``datetime`` or ``Timestamp`` object will now correctly raise a ``TypeError`` (:issue:`17983`)
264264
- Fixed a bug where ``FY5253`` date offsets could incorrectly raise an ``AssertionError`` in arithmetic operatons (:issue:`14774`)
265265
- Bug in :meth:`Index.astype` with a categorical dtype where the resultant index is not converted to a :class:`CategoricalIndex` for all types of index (:issue:`18630`)
266-
266+
- Bug in localization of a naive, datetime string in a ``Series`` constructor with a ``datetime[ns, timezone]`` dtype (:issue:`174151`)
267267

268268
Indexing
269269
^^^^^^^^

pandas/core/dtypes/cast.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
is_integer_dtype,
2121
is_datetime_or_timedelta_dtype,
2222
is_bool_dtype, is_scalar,
23-
_string_dtypes,
23+
is_string_dtype, _string_dtypes,
2424
pandas_dtype,
2525
_ensure_int8, _ensure_int16,
2626
_ensure_int32, _ensure_int64,
@@ -1003,12 +1003,18 @@ def maybe_cast_to_datetime(value, dtype, errors='raise'):
10031003
if is_datetime64:
10041004
value = to_datetime(value, errors=errors)._values
10051005
elif is_datetime64tz:
1006-
# input has to be UTC at this point, so just
1007-
# localize
1008-
value = (to_datetime(value, errors=errors)
1009-
.tz_localize('UTC')
1010-
.tz_convert(dtype.tz)
1011-
)
1006+
# This block can be simplified once PR #17413 is
1007+
# complete
1008+
is_dt_string = is_string_dtype(value)
1009+
value = to_datetime(value, errors=errors)
1010+
if is_dt_string:
1011+
# Strings here are naive, so directly localize
1012+
value = value.tz_localize(dtype.tz)
1013+
else:
1014+
# Numeric values are UTC at this point,
1015+
# so localize and convert
1016+
value = (value.tz_localize('UTC')
1017+
.tz_convert(dtype.tz))
10121018
elif is_timedelta64:
10131019
value = to_timedelta(value, errors=errors)._values
10141020
except (AttributeError, ValueError, TypeError):

pandas/tests/series/test_constructors.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,14 @@ def test_constructor_with_datetime_tz(self):
688688
expected = Series(pd.DatetimeIndex(['NaT', 'NaT'], tz='US/Eastern'))
689689
assert_series_equal(s, expected)
690690

691+
@pytest.mark.parametrize('arg, dtype',
692+
['2013-01-01 00:00:00', pd.NaT, np.nan, None])
693+
def test_constructor_with_naive_string_and_datetimetz_dtype(self, arg):
694+
# GH 17415: With naive string
695+
result = Series([arg], dtype='datetime64[ns, CET]')
696+
expected = Series([pd.Timestamp(arg, tz='CET')])
697+
assert_series_equal(result, expected)
698+
691699
def test_construction_interval(self):
692700
# construction from interval & array of intervals
693701
index = IntervalIndex.from_breaks(np.arange(3), closed='right')

0 commit comments

Comments
 (0)