diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index 17ed5f211..c9e6d9986 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -8,16 +8,24 @@ from datetime import ( from time import struct_time from typing import ( ClassVar, + Literal, TypeVar, + Union, overload, ) import numpy as np -from pandas import Index +from pandas import ( + DatetimeIndex, + Index, + TimedeltaIndex, +) from pandas.core.series import ( Series, + TimedeltaSeries, TimestampSeries, ) +from typing_extensions import TypeAlias from pandas._libs.tslibs import ( BaseOffset, @@ -25,21 +33,28 @@ from pandas._libs.tslibs import ( Tick, Timedelta, ) -from pandas._typing import np_ndarray_bool +from pandas._typing import ( + np_ndarray_bool, + npt, +) _DatetimeT = TypeVar("_DatetimeT", bound=datetime) - -def integer_op_not_supported(obj: object) -> TypeError: ... +_Ambiguous: TypeAlias = Union[bool, Literal["raise", "NaT"]] +_Nonexistent: TypeAlias = Union[ + Literal["raise", "NaT", "shift_backward", "shift_forward"], Timedelta, timedelta +] class Timestamp(datetime): min: ClassVar[Timestamp] max: ClassVar[Timestamp] resolution: ClassVar[Timedelta] - value: int # np.int64 + value: int def __new__( cls: type[_DatetimeT], ts_input: np.integer | float | str | _date | datetime | np.datetime64 = ..., + # Freq is deprecated but is left in to allow code like Timestamp(2000,1,1) + # Removing it would make the other arguments position only freq: int | str | BaseOffset | None = ..., tz: str | _tzinfo | int | None = ..., unit: str | int | None = ..., @@ -53,7 +68,7 @@ class Timestamp(datetime): nanosecond: int | None = ..., tzinfo: _tzinfo | None = ..., *, - fold: int | None = ..., + fold: Literal[0, 1] | None = ..., ) -> _DatetimeT: ... # GH 46171 # While Timestamp can return pd.NaT, having the constructor return @@ -73,6 +88,8 @@ class Timestamp(datetime): @property def microsecond(self) -> int: ... @property + def nanosecond(self) -> int: ... + @property def tzinfo(self) -> _tzinfo | None: ... @property def tz(self) -> _tzinfo | None: ... @@ -80,7 +97,7 @@ class Timestamp(datetime): def fold(self) -> int: ... @classmethod def fromtimestamp( - cls: type[_DatetimeT], t: float, tz: _tzinfo | None = ... + cls: type[_DatetimeT], t: float, tz: _tzinfo | str | None = ... ) -> _DatetimeT: ... @classmethod def utcfromtimestamp(cls: type[_DatetimeT], ts: float) -> _DatetimeT: ... @@ -90,7 +107,8 @@ class Timestamp(datetime): def fromordinal( cls: type[_DatetimeT], ordinal: int, - freq: str | BaseOffset | None = ..., + # freq produces a FutureWarning about being deprecated in a future version + freq: None = ..., tz: _tzinfo | str | None = ..., ) -> _DatetimeT: ... @classmethod @@ -111,17 +129,21 @@ class Timestamp(datetime): def date(self) -> _date: ... def time(self) -> _time: ... def timetz(self) -> _time: ... - def replace( + # Override since fold is more precise than datetime.replace(fold:int) + # Here it is restricted to be 0 or 1 using a Literal + # Violation of Liskov substitution principle + def replace( # type:ignore[override] self, - year: int = ..., - month: int = ..., - day: int = ..., - hour: int = ..., - minute: int = ..., - second: int = ..., - microsecond: int = ..., + year: int | None = ..., + month: int | None = ..., + day: int | None = ..., + hour: int | None = ..., + minute: int | None = ..., + second: int | None = ..., + microsecond: int | None = ..., tzinfo: _tzinfo | None = ..., - fold: int = ..., + *, + fold: Literal[0, 1] | None = ..., ) -> Timestamp: ... def astimezone(self: _DatetimeT, tz: _tzinfo | None = ...) -> _DatetimeT: ... def ctime(self) -> str: ... @@ -131,45 +153,86 @@ class Timestamp(datetime): def utcoffset(self) -> timedelta | None: ... def tzname(self) -> str | None: ... def dst(self) -> timedelta | None: ... + # Mypy complains Forward operator "" is not callable, so ignore misc + # for le, lt ge and gt @overload # type: ignore[override] - def __le__(self, other: datetime) -> bool: ... + def __le__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload - def __le__(self, other: Index) -> np_ndarray_bool: ... + def __le__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload - def __le__(self, other: TimestampSeries) -> Series[bool]: ... + def __le__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... @overload # type: ignore[override] - def __lt__(self, other: datetime) -> bool: ... + def __lt__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload - def __lt__(self, other: Index) -> np_ndarray_bool: ... + def __lt__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload - def __lt__(self, other: TimestampSeries) -> Series[bool]: ... + def __lt__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... @overload # type: ignore[override] - def __ge__(self, other: datetime) -> bool: ... + def __ge__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload - def __ge__(self, other: Index) -> np_ndarray_bool: ... + def __ge__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload - def __ge__(self, other: TimestampSeries) -> Series[bool]: ... + def __ge__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... @overload # type: ignore[override] - def __gt__(self, other: datetime) -> bool: ... + def __gt__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload - def __gt__(self, other: Index) -> np_ndarray_bool: ... + def __gt__(self, other: Index | npt.NDArray[np.datetime64]) -> np_ndarray_bool: ... @overload - def __gt__(self, other: TimestampSeries) -> Series[bool]: ... + def __gt__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... # error: Signature of "__add__" incompatible with supertype "date"/"datetime" @overload # type: ignore[override] - def __add__(self, other: np.ndarray) -> np.ndarray: ... + def __add__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.datetime64]: ... @overload def __add__( self: _DatetimeT, other: timedelta | np.timedelta64 | Tick ) -> _DatetimeT: ... + @overload + def __add__( + self, other: TimedeltaSeries | Series[Timedelta] + ) -> TimestampSeries: ... + @overload + def __add__(self, other: TimedeltaIndex) -> DatetimeIndex: ... + @overload def __radd__(self: _DatetimeT, other: timedelta) -> _DatetimeT: ... + @overload + def __radd__(self, other: TimedeltaIndex) -> DatetimeIndex: ... + @overload + def __radd__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.datetime64]: ... + # TODO: test dt64 @overload # type: ignore[override] - def __sub__(self, other: datetime) -> Timedelta: ... + def __sub__(self, other: Timestamp | datetime | np.datetime64) -> Timedelta: ... @overload def __sub__( self: _DatetimeT, other: timedelta | np.timedelta64 | Tick ) -> _DatetimeT: ... - def __hash__(self) -> int: ... + @overload + def __sub__(self, other: TimedeltaIndex) -> DatetimeIndex: ... + @overload + def __sub__(self, other: TimedeltaSeries) -> TimestampSeries: ... + @overload + def __sub__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.datetime64]: ... + @overload + def __eq__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] + @overload + def __eq__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... # type: ignore[misc] + @overload + def __eq__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... # type: ignore[misc] + @overload + def __eq__(self, other: object) -> Literal[False]: ... + @overload + def __ne__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] + @overload + def __ne__(self, other: TimestampSeries | Series[Timestamp]) -> Series[bool]: ... # type: ignore[misc] + @overload + def __ne__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... # type: ignore[misc] + @overload + def __ne__(self, other: object) -> Literal[True]: ... def weekday(self) -> int: ... def isoweekday(self) -> int: ... def isocalendar(self) -> tuple[int, int, int]: ... @@ -198,19 +261,28 @@ class Timestamp(datetime): def tz_localize( self: _DatetimeT, tz: _tzinfo | str | None, - ambiguous: str = ..., - nonexistent: str = ..., + ambiguous: _Ambiguous = ..., + nonexistent: _Nonexistent = ..., ) -> _DatetimeT: ... def normalize(self: _DatetimeT) -> _DatetimeT: ... # TODO: round/floor/ceil could return NaT? def round( - self: _DatetimeT, freq: str, ambiguous: bool | str = ..., nonexistent: str = ... + self: _DatetimeT, + freq: str, + ambiguous: _Ambiguous = ..., + nonexistent: _Nonexistent = ..., ) -> _DatetimeT: ... def floor( - self: _DatetimeT, freq: str, ambiguous: bool | str = ..., nonexistent: str = ... + self: _DatetimeT, + freq: str, + ambiguous: _Ambiguous = ..., + nonexistent: _Nonexistent = ..., ) -> _DatetimeT: ... def ceil( - self: _DatetimeT, freq: str, ambiguous: bool | str = ..., nonexistent: str = ... + self: _DatetimeT, + freq: str, + ambiguous: _Ambiguous = ..., + nonexistent: _Nonexistent = ..., ) -> _DatetimeT: ... def day_name(self, locale: str | None = ...) -> str: ... def month_name(self, locale: str | None = ...) -> str: ... @@ -223,12 +295,12 @@ class Timestamp(datetime): @property def dayofyear(self) -> int: ... @property + def weekofyear(self) -> int: ... + @property def quarter(self) -> int: ... @property def week(self) -> int: ... - def to_numpy( - self, dtype: np.dtype | None = ..., copy: bool = ... - ) -> np.datetime64: ... + def to_numpy(self) -> np.datetime64: ... @property def days_in_month(self) -> int: ... @property diff --git a/pandas-stubs/core/algorithms.pyi b/pandas-stubs/core/algorithms.pyi index 4ac2621a1..4582c3184 100644 --- a/pandas-stubs/core/algorithms.pyi +++ b/pandas-stubs/core/algorithms.pyi @@ -4,7 +4,6 @@ from typing import ( ) import numpy as np -import pandas as pd from pandas import ( Categorical, CategoricalIndex, diff --git a/pandas-stubs/core/arrays/arrow/dtype.pyi b/pandas-stubs/core/arrays/arrow/dtype.pyi index dc27fff7c..041012a7a 100644 --- a/pandas-stubs/core/arrays/arrow/dtype.pyi +++ b/pandas-stubs/core/arrays/arrow/dtype.pyi @@ -1,4 +1,3 @@ -import numpy as np import pyarrow as pa from pandas.core.dtypes.base import StorageExtensionDtype diff --git a/pandas-stubs/core/arrays/numpy_.pyi b/pandas-stubs/core/arrays/numpy_.pyi index f44e5a6af..535b1905d 100644 --- a/pandas-stubs/core/arrays/numpy_.pyi +++ b/pandas-stubs/core/arrays/numpy_.pyi @@ -1,4 +1,3 @@ -import numpy as np from numpy.lib.mixins import NDArrayOperatorsMixin from pandas.core.arrays.base import ( ExtensionArray, diff --git a/pandas-stubs/core/dtypes/common.pyi b/pandas-stubs/core/dtypes/common.pyi index 3da5a0091..3156f1508 100644 --- a/pandas-stubs/core/dtypes/common.pyi +++ b/pandas-stubs/core/dtypes/common.pyi @@ -1,6 +1,5 @@ from typing import Union -import numpy as np import pandas as pd from typing_extensions import TypeAlias diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index 7d49cf35b..d82f70c33 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -110,7 +110,6 @@ from pandas._typing import ( num, ) -from pandas.io.formats import format as fmt from pandas.io.formats.style import Styler from pandas.plotting import PlotAccessor diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index 0cc15a2b9..3dff35b2c 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -15,7 +15,6 @@ from matplotlib.axes import ( Axes as PlotAxes, SubplotBase as AxesSubplot, ) -import numpy as np from pandas.core.frame import DataFrame from pandas.core.generic import NDFrame from pandas.core.groupby.groupby import ( # , get_groupby as get_groupby diff --git a/pandas-stubs/core/indexes/interval.pyi b/pandas-stubs/core/indexes/interval.pyi index 339f99053..dd5ef8510 100644 --- a/pandas-stubs/core/indexes/interval.pyi +++ b/pandas-stubs/core/indexes/interval.pyi @@ -1,4 +1,3 @@ -import datetime as dt from typing import ( Any, Hashable, diff --git a/pandas-stubs/core/indexes/numeric.pyi b/pandas-stubs/core/indexes/numeric.pyi index 5e927327e..95715a83a 100644 --- a/pandas-stubs/core/indexes/numeric.pyi +++ b/pandas-stubs/core/indexes/numeric.pyi @@ -1,6 +1,5 @@ from typing import Iterable -import numpy as np from pandas.core.indexes.base import Index from pandas._typing import np_ndarray_int64 diff --git a/pandas-stubs/core/ops/dispatch.pyi b/pandas-stubs/core/ops/dispatch.pyi index 0a69d985a..b283ba29e 100644 --- a/pandas-stubs/core/ops/dispatch.pyi +++ b/pandas-stubs/core/ops/dispatch.pyi @@ -1,5 +1,3 @@ -import numpy as np - from pandas.core.dtypes.generic import ABCSeries def should_extension_dispatch(left: ABCSeries, right) -> bool: ... diff --git a/pandas-stubs/core/tools/datetimes.pyi b/pandas-stubs/core/tools/datetimes.pyi index fa32eceff..6cc504f7d 100644 --- a/pandas-stubs/core/tools/datetimes.pyi +++ b/pandas-stubs/core/tools/datetimes.pyi @@ -10,7 +10,6 @@ from typing import ( ) import numpy as np -import pandas as pd from pandas import ( Index, Timestamp, diff --git a/pandas-stubs/core/tools/timedeltas.pyi b/pandas-stubs/core/tools/timedeltas.pyi index 5f6817b8f..ed1818348 100644 --- a/pandas-stubs/core/tools/timedeltas.pyi +++ b/pandas-stubs/core/tools/timedeltas.pyi @@ -4,7 +4,6 @@ from typing import ( overload, ) -import pandas as pd from pandas import Index from pandas.core.indexes.timedeltas import TimedeltaIndex from pandas.core.series import ( diff --git a/pandas-stubs/core/window/expanding.pyi b/pandas-stubs/core/window/expanding.pyi index 1c3b164ff..04df37896 100644 --- a/pandas-stubs/core/window/expanding.pyi +++ b/pandas-stubs/core/window/expanding.pyi @@ -4,7 +4,6 @@ from typing import ( overload, ) -import numpy as np from pandas import ( DataFrame, Series, diff --git a/pandas-stubs/core/window/rolling.pyi b/pandas-stubs/core/window/rolling.pyi index de3eb8357..9830b01d3 100644 --- a/pandas-stubs/core/window/rolling.pyi +++ b/pandas-stubs/core/window/rolling.pyi @@ -5,7 +5,6 @@ from typing import ( overload, ) -import numpy as np from pandas import ( DataFrame, Series, diff --git a/pandas-stubs/io/clipboards.pyi b/pandas-stubs/io/clipboards.pyi index a57c5ecab..cb8449902 100644 --- a/pandas-stubs/io/clipboards.pyi +++ b/pandas-stubs/io/clipboards.pyi @@ -8,7 +8,6 @@ from typing import ( overload, ) -import numpy as np from pandas.core.frame import DataFrame from pandas.core.indexes.base import Index from pandas.core.series import Series diff --git a/pandas-stubs/io/formats/format.pyi b/pandas-stubs/io/formats/format.pyi index 0305a2886..c26fbcf2f 100644 --- a/pandas-stubs/io/formats/format.pyi +++ b/pandas-stubs/io/formats/format.pyi @@ -1,5 +1,3 @@ -import numpy as np - class EngFormatter: ENG_PREFIXES = ... accuracy = ... diff --git a/pandas-stubs/io/parsers/readers.pyi b/pandas-stubs/io/parsers/readers.pyi index 14db44693..cf2d7d3f1 100644 --- a/pandas-stubs/io/parsers/readers.pyi +++ b/pandas-stubs/io/parsers/readers.pyi @@ -16,7 +16,6 @@ from pandas.core.frame import DataFrame from pandas.core.indexes.base import Index from pandas.core.series import Series -import pandas._libs.lib as lib from pandas._typing import ( CompressionOptions, CSVEngine, diff --git a/pandas-stubs/io/pytables.pyi b/pandas-stubs/io/pytables.pyi index 4dcaea325..41719e389 100644 --- a/pandas-stubs/io/pytables.pyi +++ b/pandas-stubs/io/pytables.pyi @@ -7,7 +7,6 @@ from typing import ( overload, ) -import numpy as np from pandas import ( DataFrame, Series, diff --git a/pandas-stubs/io/sas/sas7bdat.pyi b/pandas-stubs/io/sas/sas7bdat.pyi index fdb0a556a..1db480959 100644 --- a/pandas-stubs/io/sas/sas7bdat.pyi +++ b/pandas-stubs/io/sas/sas7bdat.pyi @@ -1,5 +1,3 @@ -import numpy as np -import pandas as pd from pandas import DataFrame from pandas.io.sas.sasreader import ReaderBase diff --git a/pandas-stubs/io/stata.pyi b/pandas-stubs/io/stata.pyi index 86c8b0825..aca173e87 100644 --- a/pandas-stubs/io/stata.pyi +++ b/pandas-stubs/io/stata.pyi @@ -8,9 +8,6 @@ from typing import ( overload, ) -import numpy as np -import numpy.typing as npt -import pandas as pd from pandas.core.frame import DataFrame from pandas._typing import ( diff --git a/pyproject.toml b/pyproject.toml index 457323444..db5eb825d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ types-pytz = ">= 2022.1.1" mypy = "==0.971" pyarrow = ">=9.0.0" pytest = ">=7.1.2" -pyright = ">=1.1.266" +pyright = ">=1.1.278" poethepoet = "0.16.0" loguru = ">=0.6.0" pandas = "1.5.1" @@ -58,6 +58,7 @@ tabulate = ">=0.8.10" jinja2 = "^3.1" scipy = ">=1.9.1" SQLAlchemy = "^1.4.41" +types-python-dateutil = ">=2.8.19" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tests/test_scalars.py b/tests/test_scalars.py index 6139bb74f..799277d0c 100644 --- a/tests/test_scalars.py +++ b/tests/test_scalars.py @@ -1,10 +1,17 @@ from __future__ import annotations import datetime as dt -from typing import TYPE_CHECKING +from typing import ( + TYPE_CHECKING, + Any, + Optional, +) +import dateutil.tz import numpy as np +from numpy import typing as npt import pandas as pd +import pytz from typing_extensions import ( TypeAlias, assert_type, @@ -15,26 +22,623 @@ NaTType, ) +from tests import check + +from pandas.tseries.offsets import Day + if TYPE_CHECKING: from pandas.core.series import ( OffsetSeries, PeriodSeries, TimedeltaSeries, + TimestampSeries, ) from pandas._typing import np_ndarray_bool else: - import numpy.typing as npt np_ndarray_bool = npt.NDArray[np.bool_] + TimedeltaSeries = pd.Series + TimestampSeries = pd.Series PeriodSeries: TypeAlias = pd.Series - TimedeltaSeries: TypeAlias = pd.Series OffsetSeries: TypeAlias = pd.Series -from tests import check +def test_timestamp_construction() -> None: -from pandas.tseries.offsets import Day + check(assert_type(pd.Timestamp("2000-1-1"), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.Timestamp("2000-1-1", tz="US/Pacific"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type( + pd.Timestamp("2000-1-1", tz=pytz.timezone("US/Eastern")), pd.Timestamp + ), + pd.Timestamp, + ) + check( + assert_type(pd.Timestamp("2000-1-1", tz=dateutil.tz.UTC), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type( + pd.Timestamp( + year=2000, + month=1, + day=1, + hour=1, + minute=1, + second=1, + microsecond=1, + nanosecond=1, + ), + pd.Timestamp, + ), + pd.Timestamp, + ) + check(assert_type(pd.Timestamp(1, unit="D"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(1, unit="h"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(1, unit="m"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(1, unit="s"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(1, unit="ms"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(1, unit="us"), pd.Timestamp), pd.Timestamp) + check( + assert_type( + pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27, fold=0), + pd.Timestamp, + ), + pd.Timestamp, + ) + check( + assert_type( + pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27, fold=1), + pd.Timestamp, + ), + pd.Timestamp, + ) + check( + assert_type( + pd.Timestamp( + year=2000, + month=1, + day=1, + hour=1, + minute=1, + second=1, + microsecond=1, + nanosecond=1, + tzinfo=dt.timezone(offset=dt.timedelta(hours=6), name="EST"), + ), + pd.Timestamp, + ), + pd.Timestamp, + ) + + +def test_timestamp_properties() -> None: + ts = pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27) + + check(assert_type(ts, pd.Timestamp), pd.Timestamp) + check(assert_type(ts.asm8, np.datetime64), np.datetime64) + check(assert_type(ts.day_of_week, int), int) + check(assert_type(ts.day_of_year, int), int) + check(assert_type(ts.dayofweek, int), int) + check(assert_type(ts.dayofyear, int), int) + check(assert_type(ts.days_in_month, int), int) + check(assert_type(ts.daysinmonth, int), int) + check(assert_type(ts.is_leap_year, bool), bool) + check(assert_type(ts.is_month_end, bool), bool) + check(assert_type(ts.is_month_start, bool), bool) + check(assert_type(ts.is_quarter_end, bool), bool) + check(assert_type(ts.is_quarter_start, bool), bool) + check(assert_type(ts.is_year_end, bool), bool) + check(assert_type(ts.is_year_start, bool), bool) + check(assert_type(ts.quarter, int), int) + check(assert_type(ts.tz, Optional[dt.tzinfo]), type(None)) + check(assert_type(ts.week, int), int) + check(assert_type(ts.weekofyear, int), int) + check(assert_type(ts.day, int), int) + check(assert_type(ts.fold, int), int) + check(assert_type(ts.hour, int), int) + check(assert_type(ts.microsecond, int), int) + check(assert_type(ts.minute, int), int) + check(assert_type(ts.month, int), int) + check(assert_type(ts.nanosecond, int), int) + check(assert_type(ts.second, int), int) + check(assert_type(ts.tzinfo, Optional[dt.tzinfo]), type(None)) + check(assert_type(ts.value, int), int) + check(assert_type(ts.year, int), int) + + +def test_timestamp_add_sub() -> None: + ts = pd.Timestamp("2000-1-1") + np_td64_arr: npt.NDArray[np.timedelta64] = np.array([1, 2], dtype="timedelta64[ns]") + + as_pd_timedelta = pd.Timedelta(days=1) + as_dt_timedelta = dt.timedelta(days=1) + as_offset = 3 * Day() + as_timedelta_index = pd.TimedeltaIndex([1, 2, 3], "D") + as_timedelta_series = pd.Series(as_timedelta_index) + check(assert_type(as_timedelta_series, TimedeltaSeries), pd.Series) + as_np_ndarray_td64 = np_td64_arr + + check(assert_type(ts + as_pd_timedelta, pd.Timestamp), pd.Timestamp) + check(assert_type(as_pd_timedelta + ts, pd.Timestamp), pd.Timestamp) + + check(assert_type(ts + as_dt_timedelta, pd.Timestamp), pd.Timestamp) + check(assert_type(as_dt_timedelta + ts, pd.Timestamp), pd.Timestamp) + + check(assert_type(ts + as_offset, pd.Timestamp), pd.Timestamp) + check(assert_type(as_offset + ts, pd.Timestamp), pd.Timestamp) + + check(assert_type(ts + as_timedelta_index, pd.DatetimeIndex), pd.DatetimeIndex) + check(assert_type(as_timedelta_index + ts, pd.DatetimeIndex), pd.DatetimeIndex) + + check( + assert_type(ts + as_timedelta_series, TimestampSeries), pd.Series, pd.Timestamp + ) + check( + assert_type(as_timedelta_series + ts, TimestampSeries), pd.Series, pd.Timestamp + ) + + check( + assert_type(ts + as_np_ndarray_td64, npt.NDArray[np.datetime64]), + np.ndarray, + np.datetime64, + ) + check( + assert_type( + as_np_ndarray_td64 + ts, + npt.NDArray[np.datetime64], + ), + np.ndarray, + np.datetime64, + ) + + # Reverse order is not possible for all of these + check(assert_type(ts - as_pd_timedelta, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - as_dt_timedelta, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - as_offset, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - as_timedelta_index, pd.DatetimeIndex), pd.DatetimeIndex) + check( + assert_type(ts - as_timedelta_series, TimestampSeries), pd.Series, pd.Timestamp + ) + check( + assert_type(ts - as_np_ndarray_td64, npt.NDArray[np.datetime64]), + np.ndarray, + np.datetime64, + ) + + +def test_timestamp_cmp() -> None: + ts = pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27) + + np_dt64_arr: npt.NDArray[np.datetime64] = np.array( + [1, 2, 3], dtype="datetime64[ns]" + ) + + c_timestamp = ts + c_np_dt64 = np.datetime64(1, "ns") + c_dt_datetime = dt.datetime(year=2000, month=1, day=1) + c_datetimeindex = pd.DatetimeIndex(["2000-1-1"]) + c_np_ndarray_dt64 = np_dt64_arr + # Typing provided since there is no way to get a Series[Timestamp], + # which is a different type from a TimestampSeries + c_series_dt64: pd.Series[pd.Timestamp] = pd.Series( + [1, 2, 3], dtype="datetime64[ns]" + ) + c_series_timestamp = pd.Series(pd.DatetimeIndex(["2000-1-1"])) + check(assert_type(c_series_timestamp, TimestampSeries), pd.Series, pd.Timestamp) + # Use xor to ensure one is True and the other is False + # Correctness ensures since tested to be bools + gt = check(assert_type(ts > c_timestamp, bool), bool) + lte = check(assert_type(ts <= c_timestamp, bool), bool) + assert gt != lte + + gt = check(assert_type(ts > c_np_dt64, bool), bool) + lte = check(assert_type(ts <= c_np_dt64, bool), bool) + assert gt != lte + + gt = check(assert_type(ts > c_dt_datetime, bool), bool) + lte = check(assert_type(ts <= c_dt_datetime, bool), bool) + assert gt != lte + + check(assert_type(ts > c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(ts <= c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) + + check(assert_type(ts > c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(ts <= c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) + + check(assert_type(ts > c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts <= c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) + + check(assert_type(ts > c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts <= c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + + check(assert_type(c_np_dt64 > ts, Any), np.bool_) + check(assert_type(c_np_dt64 <= ts, Any), np.bool_) + + gt = check(assert_type(c_dt_datetime > ts, bool), bool) + lte = check(assert_type(c_dt_datetime <= ts, bool), bool) + assert gt != lte + + check(assert_type(c_datetimeindex > ts, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_datetimeindex <= ts, np_ndarray_bool), np.ndarray, np.bool_) + + check(assert_type(c_np_ndarray_dt64 > ts, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_np_ndarray_dt64 <= ts, np_ndarray_bool), np.ndarray, np.bool_) + + check(assert_type(c_series_dt64 > ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c_series_dt64 <= ts, "pd.Series[bool]"), pd.Series, bool) + + gte = check(assert_type(ts >= c_timestamp, bool), bool) + lt = check(assert_type(ts < c_timestamp, bool), bool) + assert gte != lt + + gte = check(assert_type(ts >= c_np_dt64, bool), bool) + lt = check(assert_type(ts < c_np_dt64, bool), bool) + assert gte != lt + + gte = check(assert_type(ts >= c_dt_datetime, bool), bool) + lt = check(assert_type(ts < c_dt_datetime, bool), bool) + assert gte != lt + + check(assert_type(ts >= c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(ts < c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_) + + check(assert_type(ts >= c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(ts < c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_) + + check(assert_type(ts >= c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts < c_series_timestamp, "pd.Series[bool]"), pd.Series, bool) + + check(assert_type(ts >= c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts < c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + + gte = check(assert_type(c_dt_datetime >= ts, bool), bool) + lt = check(assert_type(c_dt_datetime < ts, bool), bool) + assert gte != lt + + check(assert_type(c_np_dt64 >= ts, Any), np.bool_) + check(assert_type(c_np_dt64 < ts, Any), np.bool_) + + check(assert_type(c_datetimeindex >= ts, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_datetimeindex < ts, np_ndarray_bool), np.ndarray, np.bool_) + + check(assert_type(c_np_ndarray_dt64 >= ts, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_np_ndarray_dt64 < ts, np_ndarray_bool), np.ndarray, np.bool_) + + check(assert_type(c_series_dt64 >= ts, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(c_series_dt64 < ts, "pd.Series[bool]"), pd.Series, bool) + + eq = check(assert_type(ts == c_timestamp, bool), bool) + ne = check(assert_type(ts != c_timestamp, bool), bool) + assert eq != ne + + eq = check(assert_type(ts == c_np_dt64, bool), bool) + ne = check(assert_type(ts != c_np_dt64, bool), bool) + assert eq != ne + + eq = check(assert_type(ts == c_dt_datetime, bool), bool) + ne = check(assert_type(ts != c_dt_datetime, bool), bool) + assert eq != ne + + eq_arr = check( + assert_type(ts == c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_arr = check( + assert_type(ts != c_datetimeindex, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_arr != ne_arr).all() + + eq_arr = check( + assert_type(ts == c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_arr = check( + assert_type(ts != c_np_ndarray_dt64, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_arr != ne_arr).all() + + eq_s = check( + assert_type(ts == c_series_timestamp, "pd.Series[bool]"), pd.Series, bool + ) + ne_s = check( + assert_type(ts != c_series_timestamp, "pd.Series[bool]"), pd.Series, bool + ) + assert (eq_s != ne_s).all() + + eq_s = check(assert_type(ts == c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + ne_s = check(assert_type(ts != c_series_dt64, "pd.Series[bool]"), pd.Series, bool) + assert (eq_s != ne_s).all() + + +def test_timestamp_eq_ne_rhs() -> None: + # These test equality using the LHS objects __eq__ and __ne__ methods + # The tests are retained for completeness, but are not strictly necessary + ts = pd.Timestamp(year=2000, month=3, day=24, hour=12, minute=27) + + np_dt64_arr: npt.NDArray[np.datetime64] = np.array( + [1, 2, 3], dtype="datetime64[ns]" + ) + + c_np_dt64 = np.datetime64(1, "ns") + c_dt_datetime = dt.datetime(year=2000, month=1, day=1) + c_datetimeindex = pd.DatetimeIndex(["2000-1-1"]) + c_np_ndarray_dt64 = np_dt64_arr + c_series_dt64: pd.Series[pd.Timestamp] = pd.Series( + [1, 2, 3], dtype="datetime64[ns]" + ) + + eq_a = check(assert_type(c_np_dt64 == ts, Any), np.bool_) + ne_a = check(assert_type(c_np_dt64 != ts, Any), np.bool_) + assert eq_a != ne_a + + eq = check(assert_type(c_dt_datetime == ts, bool), bool) + ne = check(assert_type(c_dt_datetime != ts, bool), bool) + assert eq != ne + + eq_arr = check( + assert_type(c_datetimeindex == ts, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_arr = check( + assert_type(c_datetimeindex != ts, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_arr != ne_arr).all() + + eq_a = check(assert_type(c_np_ndarray_dt64 != ts, Any), np.ndarray, np.bool_) + ne_a = check(assert_type(c_np_ndarray_dt64 == ts, Any), np.ndarray, np.bool_) + assert (eq_a != ne_a).all() + + eq_s = check(assert_type(c_series_dt64 == ts, "pd.Series[bool]"), pd.Series, bool) + ne_s = check(assert_type(c_series_dt64 != ts, "pd.Series[bool]"), pd.Series, bool) + assert (eq_s != ne_s).all() + + +def test_timestamp_types_init() -> None: + check(assert_type(pd.Timestamp("2021-03-01T12"), pd.Timestamp), pd.Timestamp) + check(assert_type(pd.Timestamp(dt.date(2021, 3, 15)), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.Timestamp(dt.datetime(2021, 3, 10, 12)), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(pd.Timestamp(pd.Timestamp("2021-03-01T12")), pd.Timestamp), + pd.Timestamp, + ) + check(assert_type(pd.Timestamp(1515590000.1, unit="s"), pd.Timestamp), pd.Timestamp) + check( + assert_type( + pd.Timestamp(1515590000.1, unit="s", tz="US/Pacific"), pd.Timestamp + ), + pd.Timestamp, + ) + check( + assert_type(pd.Timestamp(1515590000100000000), pd.Timestamp), pd.Timestamp + ) # plain integer (nanosecond) + check(assert_type(pd.Timestamp(2021, 3, 10, 12), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.Timestamp(year=2021, month=3, day=10, hour=12), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type( + pd.Timestamp(year=2021, month=3, day=10, hour=12, tz="US/Pacific"), + pd.Timestamp, + ), + pd.Timestamp, + ) + + +def test_timestamp_misc_methods() -> None: + ts = pd.Timestamp("2021-03-01T12") + check(assert_type(ts, pd.Timestamp), pd.Timestamp) + + check(assert_type(ts.to_numpy(), np.datetime64), np.datetime64) + + check(assert_type(pd.Timestamp.fromtimestamp(432.54), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.Timestamp.fromtimestamp(432.54, tz="US/Pacific"), pd.Timestamp), + pd.Timestamp, + ) + check(assert_type(pd.Timestamp.fromordinal(700000), pd.Timestamp), pd.Timestamp) + check( + assert_type(pd.Timestamp.fromordinal(700000, tz="US/Pacific"), pd.Timestamp), + pd.Timestamp, + ) + + ts2 = ts.replace( + year=2020, + month=2, + day=2, + hour=12, + minute=21, + second=21, + microsecond=12, + tzinfo=dateutil.tz.UTC, + fold=0, + ) + check(assert_type(ts2, pd.Timestamp), pd.Timestamp) + check(assert_type(ts.tz_localize("US/Pacific", False), pd.Timestamp), pd.Timestamp) + check(assert_type(ts.tz_localize("US/Pacific", True), pd.Timestamp), pd.Timestamp) + check(assert_type(ts.tz_localize("US/Pacific", "NaT"), pd.Timestamp), pd.Timestamp) + check( + assert_type(ts.tz_localize("US/Pacific", "raise"), pd.Timestamp), pd.Timestamp + ) + + check( + assert_type( + ts.tz_localize("US/Pacific", nonexistent="shift_forward"), pd.Timestamp + ), + pd.Timestamp, + ) + check( + assert_type( + ts.tz_localize("US/Pacific", nonexistent="shift_backward"), pd.Timestamp + ), + pd.Timestamp, + ) + check( + assert_type(ts.tz_localize("US/Pacific", nonexistent="NaT"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts.tz_localize("US/Pacific", nonexistent="raise"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type( + ts.tz_localize("US/Pacific", nonexistent=pd.Timedelta("1D")), pd.Timestamp + ), + pd.Timestamp, + ) + + check(assert_type(ts2.round("1S"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.round("1S", ambiguous="raise"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.round("1S", ambiguous=True), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.round("1S", ambiguous=False), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.round("1S", ambiguous="NaT"), pd.Timestamp), pd.Timestamp) + + check( + assert_type(ts2.round("2H", nonexistent="shift_forward"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.round("2H", nonexistent="shift_backward"), pd.Timestamp), + pd.Timestamp, + ) + check(assert_type(ts2.round("2H", nonexistent="NaT"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.round("2H", nonexistent="raise"), pd.Timestamp), pd.Timestamp) + check( + assert_type(ts2.round("2H", nonexistent=pd.Timedelta(24, "H")), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.round("2H", nonexistent=dt.timedelta(hours=24)), pd.Timestamp), + pd.Timestamp, + ) + + check(assert_type(ts2.ceil("1S"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.ceil("1S", ambiguous="raise"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.ceil("1S", ambiguous=True), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.ceil("1S", ambiguous=False), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.ceil("1S", ambiguous="NaT"), pd.Timestamp), pd.Timestamp) + + check( + assert_type(ts2.ceil("2H", nonexistent="shift_forward"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.ceil("2H", nonexistent="shift_backward"), pd.Timestamp), + pd.Timestamp, + ) + check(assert_type(ts2.ceil("2H", nonexistent="NaT"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.ceil("2H", nonexistent="raise"), pd.Timestamp), pd.Timestamp) + check( + assert_type(ts2.ceil("2H", nonexistent=pd.Timedelta(24, "H")), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.ceil("2H", nonexistent=dt.timedelta(hours=24)), pd.Timestamp), + pd.Timestamp, + ) + + check(assert_type(ts2.floor("1S"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.floor("1S", ambiguous="raise"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.floor("1S", ambiguous=True), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.floor("1S", ambiguous=False), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.floor("1S", ambiguous="NaT"), pd.Timestamp), pd.Timestamp) + + check( + assert_type(ts2.floor("2H", nonexistent="shift_forward"), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.floor("2H", nonexistent="shift_backward"), pd.Timestamp), + pd.Timestamp, + ) + check(assert_type(ts2.floor("2H", nonexistent="NaT"), pd.Timestamp), pd.Timestamp) + check(assert_type(ts2.floor("2H", nonexistent="raise"), pd.Timestamp), pd.Timestamp) + check( + assert_type(ts2.floor("2H", nonexistent=pd.Timedelta(24, "H")), pd.Timestamp), + pd.Timestamp, + ) + check( + assert_type(ts2.floor("2H", nonexistent=dt.timedelta(hours=24)), pd.Timestamp), + pd.Timestamp, + ) + + +def test_timestamp_types_arithmetic() -> None: + ts: pd.Timestamp = pd.to_datetime("2021-03-01") + ts2: pd.Timestamp = pd.to_datetime("2021-01-01") + delta: pd.Timedelta = pd.to_timedelta("1 day") + + check(assert_type(ts - ts2, pd.Timedelta), pd.Timedelta) + check(assert_type(ts + delta, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - delta, pd.Timestamp), pd.Timestamp) + check(assert_type(ts - dt.datetime(2021, 1, 3), pd.Timedelta), pd.Timedelta) + + +def test_timestamp_types_comparison() -> None: + ts: pd.Timestamp = pd.to_datetime("2021-03-01") + ts2: pd.Timestamp = pd.to_datetime("2021-01-01") + + check(assert_type(ts < ts2, bool), bool) + check(assert_type(ts > ts2, bool), bool) + + +def test_types_timestamp_series_comparisons() -> None: + # GH 27 + df = pd.DataFrame(["2020-01-01", "2019-01-01"]) + tss = pd.to_datetime(df[0], format="%Y-%m-%d") + ts = pd.to_datetime("2019-02-01", format="%Y-%m-%d") + tssr = tss <= ts + tssr2 = tss >= ts + tssr3 = tss == ts + check(assert_type(tssr, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(tssr2, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(tssr3, "pd.Series[bool]"), pd.Series, bool) + # GH 265 + data = pd.date_range("2022-01-01", "2022-01-31", freq="D") + s = pd.Series(data) + ts2 = pd.Timestamp("2022-01-15") + check(assert_type(s, TimestampSeries), pd.Series, pd.Timestamp) + check(assert_type(ts2 <= s, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts2 >= s, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts2 < s, "pd.Series[bool]"), pd.Series, bool) + check(assert_type(ts2 > s, "pd.Series[bool]"), pd.Series, bool) + + +def test_timestamp_types_pydatetime() -> None: + ts: pd.Timestamp = pd.Timestamp("2021-03-01T12") + check(assert_type(ts.to_pydatetime(), dt.datetime), dt.datetime) + check(assert_type(ts.to_pydatetime(False), dt.datetime), dt.datetime) + check(assert_type(ts.to_pydatetime(warn=True), dt.datetime), dt.datetime) + + +def test_timestamp_dateoffset_arithmetic() -> None: + ts = pd.Timestamp("2022-03-18") + do = pd.DateOffset(days=366) + check(assert_type(ts + do, pd.Timestamp), pd.Timestamp) + + +def test_todatetime_fromnumpy() -> None: + # GH 72 + t1 = np.datetime64("2022-07-04 02:30") + check(assert_type(pd.to_datetime(t1), pd.Timestamp), pd.Timestamp) + + +def test_timestamp_combine() -> None: + ts = pd.Timestamp("2022-03-18") + # mypy and pyright disagree from actual type due to inheritance. + # Same issue with some timedelta ops + check( + assert_type( + ts.combine(dt.date(2000, 1, 1), dt.time(12, 21, 21, 12)), dt.datetime + ), + pd.Timestamp, + ) def test_period_construction() -> None: