|
5 | 5 | from __future__ import annotations
|
6 | 6 |
|
7 | 7 | from contextlib import suppress
|
8 |
| -from datetime import datetime, timedelta |
| 8 | +from datetime import date, datetime, timedelta |
9 | 9 | from typing import (
|
10 | 10 | TYPE_CHECKING,
|
11 | 11 | Any,
|
@@ -549,16 +549,46 @@ def maybe_promote(dtype: np.dtype, fill_value=np.nan):
|
549 | 549 |
|
550 | 550 | # returns tuple of (dtype, fill_value)
|
551 | 551 | if issubclass(dtype.type, np.datetime64):
|
552 |
| - if isinstance(fill_value, datetime) and fill_value.tzinfo is not None: |
553 |
| - # Trying to insert tzaware into tznaive, have to cast to object |
554 |
| - dtype = np.dtype(np.object_) |
555 |
| - elif is_integer(fill_value) or is_float(fill_value): |
556 |
| - dtype = np.dtype(np.object_) |
557 |
| - else: |
| 552 | + inferred, fv = infer_dtype_from_scalar(fill_value, pandas_dtype=True) |
| 553 | + if inferred == dtype: |
| 554 | + return dtype, fv |
| 555 | + |
| 556 | + # TODO(2.0): once this deprecation is enforced, this whole case |
| 557 | + # becomes equivalent to: |
| 558 | + # dta = DatetimeArray._from_sequence([], dtype="M8[ns]") |
| 559 | + # try: |
| 560 | + # fv = dta._validate_setitem_value(fill_value) |
| 561 | + # return dta.dtype, fv |
| 562 | + # except (ValueError, TypeError): |
| 563 | + # return np.dtype(object), fill_value |
| 564 | + if isinstance(fill_value, date) and not isinstance(fill_value, datetime): |
| 565 | + # deprecate casting of date object to match infer_dtype_from_scalar |
| 566 | + # and DatetimeArray._validate_setitem_value |
558 | 567 | try:
|
559 |
| - fill_value = Timestamp(fill_value).to_datetime64() |
560 |
| - except (TypeError, ValueError): |
561 |
| - dtype = np.dtype(np.object_) |
| 568 | + fv = Timestamp(fill_value).to_datetime64() |
| 569 | + except OutOfBoundsDatetime: |
| 570 | + pass |
| 571 | + else: |
| 572 | + warnings.warn( |
| 573 | + "Using a `date` object for fill_value with `datetime64[ns]` " |
| 574 | + "dtype is deprecated. In a future version, this will be cast " |
| 575 | + "to object dtype. Pass `fill_value=Timestamp(date_obj)` instead.", |
| 576 | + FutureWarning, |
| 577 | + stacklevel=7, |
| 578 | + ) |
| 579 | + return dtype, fv |
| 580 | + elif isinstance(fill_value, str): |
| 581 | + try: |
| 582 | + # explicitly wrap in str to convert np.str_ |
| 583 | + fv = Timestamp(str(fill_value)) |
| 584 | + except (ValueError, TypeError): |
| 585 | + pass |
| 586 | + else: |
| 587 | + if fv.tz is None: |
| 588 | + return dtype, fv.asm8 |
| 589 | + |
| 590 | + return np.dtype(object), fill_value |
| 591 | + |
562 | 592 | elif issubclass(dtype.type, np.timedelta64):
|
563 | 593 | if (
|
564 | 594 | is_integer(fill_value)
|
@@ -723,13 +753,13 @@ def infer_dtype_from_scalar(val, pandas_dtype: bool = False) -> Tuple[DtypeObj,
|
723 | 753 |
|
724 | 754 | if val is NaT or val.tz is None:
|
725 | 755 | dtype = np.dtype("M8[ns]")
|
| 756 | + val = val.to_datetime64() |
726 | 757 | else:
|
727 | 758 | if pandas_dtype:
|
728 | 759 | dtype = DatetimeTZDtype(unit="ns", tz=val.tz)
|
729 | 760 | else:
|
730 | 761 | # return datetimetz as object
|
731 | 762 | return np.dtype(object), val
|
732 |
| - val = val.value |
733 | 763 |
|
734 | 764 | elif isinstance(val, (np.timedelta64, timedelta)):
|
735 | 765 | try:
|
|
0 commit comments