Skip to content

Commit 2500a23

Browse files
authored
DEPR: treating dt64 as UTC in Timestamp constructor (#42288)
1 parent 0a9cfcf commit 2500a23

File tree

4 files changed

+37
-0
lines changed

4 files changed

+37
-0
lines changed

doc/source/whatsnew/v1.4.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ Deprecations
150150
- Deprecated :meth:`Index.is_type_compatible` (:issue:`42113`)
151151
- Deprecated ``method`` argument in :meth:`Index.get_loc`, use ``index.get_indexer([label], method=...)`` instead (:issue:`42269`)
152152
- Deprecated treating integer keys in :meth:`Series.__setitem__` as positional when the index is a :class:`Float64Index` not containing the key, a :class:`IntervalIndex` with no entries containing the key, or a :class:`MultiIndex` with leading :class:`Float64Index` level not containing the key (:issue:`33469`)
153+
- Deprecated treating ``numpy.datetime64`` objects as UTC times when passed to the :class:`Timestamp` constructor along with a timezone. In a future version, these will be treated as wall-times. To retain the old behavior, use ``Timestamp(dt64).tz_localize("UTC").tz_convert(tz)`` (:issue:`24559`)
153154
-
154155

155156
.. ---------------------------------------------------------------------------

pandas/_libs/tslibs/timestamps.pyx

+13
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,19 @@ class Timestamp(_Timestamp):
13291329
"the tz parameter. Use tz_convert instead.")
13301330

13311331
tzobj = maybe_get_tz(tz)
1332+
if tzobj is not None and is_datetime64_object(ts_input):
1333+
# GH#24559, GH#42288 In the future we will treat datetime64 as
1334+
# wall-time (consistent with DatetimeIndex)
1335+
warnings.warn(
1336+
"In a future version, when passing a np.datetime64 object and "
1337+
"a timezone to Timestamp, the datetime64 will be interpreted "
1338+
"as a wall time, not a UTC time. To interpret as a UTC time, "
1339+
"use `Timestamp(dt64).tz_localize('UTC').tz_convert(tz)`",
1340+
FutureWarning,
1341+
stacklevel=1,
1342+
)
1343+
# Once this deprecation is enforced, we can do
1344+
# return Timestamp(ts_input).tz_localize(tzobj)
13321345
ts = convert_to_tsobject(ts_input, tzobj, unit, 0, 0, nanosecond or 0)
13331346

13341347
if ts.value == NPY_NAT:

pandas/core/arrays/datetimes.py

+5
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,11 @@ def _check_compatible_with(self, other, setitem: bool = False):
509509
# Descriptive Properties
510510

511511
def _box_func(self, x) -> Timestamp | NaTType:
512+
if isinstance(x, np.datetime64):
513+
# GH#42228
514+
# Argument 1 to "signedinteger" has incompatible type "datetime64";
515+
# expected "Union[SupportsInt, Union[str, bytes], SupportsIndex]"
516+
x = np.int64(x) # type: ignore[arg-type]
512517
ts = Timestamp(x, tz=self.tz)
513518
# Non-overlapping identity check (left operand type: "Timestamp",
514519
# right operand type: "NaTType")

pandas/tests/scalar/timestamp/test_constructors.py

+18
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,24 @@
2424

2525

2626
class TestTimestampConstructors:
27+
def test_constructor_datetime64_with_tz(self):
28+
# GH#42288, GH#24559
29+
dt = np.datetime64("1970-01-01 05:00:00")
30+
tzstr = "UTC+05:00"
31+
32+
msg = "interpreted as a wall time"
33+
with tm.assert_produces_warning(FutureWarning, match=msg):
34+
ts = Timestamp(dt, tz=tzstr)
35+
36+
# Check that we match the old behavior
37+
alt = Timestamp(dt).tz_localize("UTC").tz_convert(tzstr)
38+
assert ts == alt
39+
40+
# Check that we *don't* match the future behavior
41+
assert ts.hour != 5
42+
expected_future = Timestamp(dt).tz_localize(tzstr)
43+
assert ts != expected_future
44+
2745
def test_constructor(self):
2846
base_str = "2014-07-01 09:00"
2947
base_dt = datetime(2014, 7, 1, 9)

0 commit comments

Comments
 (0)