done
This commit is contained in:
		| @ -0,0 +1,86 @@ | ||||
| import pytest | ||||
|  | ||||
| from pandas._libs.tslibs.dtypes import NpyDatetimeUnit | ||||
| from pandas.errors import OutOfBoundsDatetime | ||||
|  | ||||
| from pandas import Timestamp | ||||
|  | ||||
|  | ||||
| class TestTimestampAsUnit: | ||||
|     def test_as_unit(self): | ||||
|         ts = Timestamp("1970-01-01").as_unit("ns") | ||||
|         assert ts.unit == "ns" | ||||
|  | ||||
|         assert ts.as_unit("ns") is ts | ||||
|  | ||||
|         res = ts.as_unit("us") | ||||
|         assert res._value == ts._value // 1000 | ||||
|         assert res._creso == NpyDatetimeUnit.NPY_FR_us.value | ||||
|  | ||||
|         rt = res.as_unit("ns") | ||||
|         assert rt._value == ts._value | ||||
|         assert rt._creso == ts._creso | ||||
|  | ||||
|         res = ts.as_unit("ms") | ||||
|         assert res._value == ts._value // 1_000_000 | ||||
|         assert res._creso == NpyDatetimeUnit.NPY_FR_ms.value | ||||
|  | ||||
|         rt = res.as_unit("ns") | ||||
|         assert rt._value == ts._value | ||||
|         assert rt._creso == ts._creso | ||||
|  | ||||
|         res = ts.as_unit("s") | ||||
|         assert res._value == ts._value // 1_000_000_000 | ||||
|         assert res._creso == NpyDatetimeUnit.NPY_FR_s.value | ||||
|  | ||||
|         rt = res.as_unit("ns") | ||||
|         assert rt._value == ts._value | ||||
|         assert rt._creso == ts._creso | ||||
|  | ||||
|     def test_as_unit_overflows(self): | ||||
|         # microsecond that would be just out of bounds for nano | ||||
|         us = 9223372800000000 | ||||
|         ts = Timestamp._from_value_and_reso(us, NpyDatetimeUnit.NPY_FR_us.value, None) | ||||
|  | ||||
|         msg = "Cannot cast 2262-04-12 00:00:00 to unit='ns' without overflow" | ||||
|         with pytest.raises(OutOfBoundsDatetime, match=msg): | ||||
|             ts.as_unit("ns") | ||||
|  | ||||
|         res = ts.as_unit("ms") | ||||
|         assert res._value == us // 1000 | ||||
|         assert res._creso == NpyDatetimeUnit.NPY_FR_ms.value | ||||
|  | ||||
|     def test_as_unit_rounding(self): | ||||
|         ts = Timestamp(1_500_000)  # i.e. 1500 microseconds | ||||
|         res = ts.as_unit("ms") | ||||
|  | ||||
|         expected = Timestamp(1_000_000)  # i.e. 1 millisecond | ||||
|         assert res == expected | ||||
|  | ||||
|         assert res._creso == NpyDatetimeUnit.NPY_FR_ms.value | ||||
|         assert res._value == 1 | ||||
|  | ||||
|         with pytest.raises(ValueError, match="Cannot losslessly convert units"): | ||||
|             ts.as_unit("ms", round_ok=False) | ||||
|  | ||||
|     def test_as_unit_non_nano(self): | ||||
|         # case where we are going neither to nor from nano | ||||
|         ts = Timestamp("1970-01-02").as_unit("ms") | ||||
|         assert ts.year == 1970 | ||||
|         assert ts.month == 1 | ||||
|         assert ts.day == 2 | ||||
|         assert ts.hour == ts.minute == ts.second == ts.microsecond == ts.nanosecond == 0 | ||||
|  | ||||
|         res = ts.as_unit("s") | ||||
|         assert res._value == 24 * 3600 | ||||
|         assert res.year == 1970 | ||||
|         assert res.month == 1 | ||||
|         assert res.day == 2 | ||||
|         assert ( | ||||
|             res.hour | ||||
|             == res.minute | ||||
|             == res.second | ||||
|             == res.microsecond | ||||
|             == res.nanosecond | ||||
|             == 0 | ||||
|         ) | ||||
| @ -0,0 +1,22 @@ | ||||
| import pytest | ||||
|  | ||||
| from pandas._libs.tslibs import Timestamp | ||||
| from pandas._libs.tslibs.dtypes import NpyDatetimeUnit | ||||
|  | ||||
|  | ||||
| class TestTimestampNormalize: | ||||
|     @pytest.mark.parametrize("arg", ["2013-11-30", "2013-11-30 12:00:00"]) | ||||
|     @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"]) | ||||
|     def test_normalize(self, tz_naive_fixture, arg, unit): | ||||
|         tz = tz_naive_fixture | ||||
|         ts = Timestamp(arg, tz=tz).as_unit(unit) | ||||
|         result = ts.normalize() | ||||
|         expected = Timestamp("2013-11-30", tz=tz) | ||||
|         assert result == expected | ||||
|         assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value | ||||
|  | ||||
|     def test_normalize_pre_epoch_dates(self): | ||||
|         # GH: 36294 | ||||
|         result = Timestamp("1969-01-01 09:00:00").normalize() | ||||
|         expected = Timestamp("1969-01-01 00:00:00") | ||||
|         assert result == expected | ||||
| @ -0,0 +1,193 @@ | ||||
| from datetime import datetime | ||||
|  | ||||
| from dateutil.tz import gettz | ||||
| import numpy as np | ||||
| import pytest | ||||
| import pytz | ||||
|  | ||||
| from pandas._libs.tslibs import ( | ||||
|     OutOfBoundsDatetime, | ||||
|     Timestamp, | ||||
|     conversion, | ||||
| ) | ||||
| from pandas._libs.tslibs.dtypes import NpyDatetimeUnit | ||||
| import pandas.util._test_decorators as td | ||||
|  | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimestampReplace: | ||||
|     def test_replace_out_of_pydatetime_bounds(self): | ||||
|         # GH#50348 | ||||
|         ts = Timestamp("2016-01-01").as_unit("ns") | ||||
|  | ||||
|         msg = "Out of bounds timestamp: 99999-01-01 00:00:00 with frequency 'ns'" | ||||
|         with pytest.raises(OutOfBoundsDatetime, match=msg): | ||||
|             ts.replace(year=99_999) | ||||
|  | ||||
|         ts = ts.as_unit("ms") | ||||
|         result = ts.replace(year=99_999) | ||||
|         assert result.year == 99_999 | ||||
|         assert result._value == Timestamp(np.datetime64("99999-01-01", "ms"))._value | ||||
|  | ||||
|     def test_replace_non_nano(self): | ||||
|         ts = Timestamp._from_value_and_reso( | ||||
|             91514880000000000, NpyDatetimeUnit.NPY_FR_us.value, None | ||||
|         ) | ||||
|         assert ts.to_pydatetime() == datetime(4869, 12, 28) | ||||
|  | ||||
|         result = ts.replace(year=4900) | ||||
|         assert result._creso == ts._creso | ||||
|         assert result.to_pydatetime() == datetime(4900, 12, 28) | ||||
|  | ||||
|     def test_replace_naive(self): | ||||
|         # GH#14621, GH#7825 | ||||
|         ts = Timestamp("2016-01-01 09:00:00") | ||||
|         result = ts.replace(hour=0) | ||||
|         expected = Timestamp("2016-01-01 00:00:00") | ||||
|         assert result == expected | ||||
|  | ||||
|     def test_replace_aware(self, tz_aware_fixture): | ||||
|         tz = tz_aware_fixture | ||||
|         # GH#14621, GH#7825 | ||||
|         # replacing datetime components with and w/o presence of a timezone | ||||
|         ts = Timestamp("2016-01-01 09:00:00", tz=tz) | ||||
|         result = ts.replace(hour=0) | ||||
|         expected = Timestamp("2016-01-01 00:00:00", tz=tz) | ||||
|         assert result == expected | ||||
|  | ||||
|     def test_replace_preserves_nanos(self, tz_aware_fixture): | ||||
|         tz = tz_aware_fixture | ||||
|         # GH#14621, GH#7825 | ||||
|         ts = Timestamp("2016-01-01 09:00:00.000000123", tz=tz) | ||||
|         result = ts.replace(hour=0) | ||||
|         expected = Timestamp("2016-01-01 00:00:00.000000123", tz=tz) | ||||
|         assert result == expected | ||||
|  | ||||
|     def test_replace_multiple(self, tz_aware_fixture): | ||||
|         tz = tz_aware_fixture | ||||
|         # GH#14621, GH#7825 | ||||
|         # replacing datetime components with and w/o presence of a timezone | ||||
|         # test all | ||||
|         ts = Timestamp("2016-01-01 09:00:00.000000123", tz=tz) | ||||
|         result = ts.replace( | ||||
|             year=2015, | ||||
|             month=2, | ||||
|             day=2, | ||||
|             hour=0, | ||||
|             minute=5, | ||||
|             second=5, | ||||
|             microsecond=5, | ||||
|             nanosecond=5, | ||||
|         ) | ||||
|         expected = Timestamp("2015-02-02 00:05:05.000005005", tz=tz) | ||||
|         assert result == expected | ||||
|  | ||||
|     def test_replace_invalid_kwarg(self, tz_aware_fixture): | ||||
|         tz = tz_aware_fixture | ||||
|         # GH#14621, GH#7825 | ||||
|         ts = Timestamp("2016-01-01 09:00:00.000000123", tz=tz) | ||||
|         msg = r"replace\(\) got an unexpected keyword argument" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             ts.replace(foo=5) | ||||
|  | ||||
|     def test_replace_integer_args(self, tz_aware_fixture): | ||||
|         tz = tz_aware_fixture | ||||
|         # GH#14621, GH#7825 | ||||
|         ts = Timestamp("2016-01-01 09:00:00.000000123", tz=tz) | ||||
|         msg = "value must be an integer, received <class 'float'> for hour" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             ts.replace(hour=0.1) | ||||
|  | ||||
|     def test_replace_tzinfo_equiv_tz_localize_none(self): | ||||
|         # GH#14621, GH#7825 | ||||
|         # assert conversion to naive is the same as replacing tzinfo with None | ||||
|         ts = Timestamp("2013-11-03 01:59:59.999999-0400", tz="US/Eastern") | ||||
|         assert ts.tz_localize(None) == ts.replace(tzinfo=None) | ||||
|  | ||||
|     @td.skip_if_windows | ||||
|     def test_replace_tzinfo(self): | ||||
|         # GH#15683 | ||||
|         dt = datetime(2016, 3, 27, 1) | ||||
|         tzinfo = pytz.timezone("CET").localize(dt, is_dst=False).tzinfo | ||||
|  | ||||
|         result_dt = dt.replace(tzinfo=tzinfo) | ||||
|         result_pd = Timestamp(dt).replace(tzinfo=tzinfo) | ||||
|  | ||||
|         # datetime.timestamp() converts in the local timezone | ||||
|         with tm.set_timezone("UTC"): | ||||
|             assert result_dt.timestamp() == result_pd.timestamp() | ||||
|  | ||||
|         assert result_dt == result_pd | ||||
|         assert result_dt == result_pd.to_pydatetime() | ||||
|  | ||||
|         result_dt = dt.replace(tzinfo=tzinfo).replace(tzinfo=None) | ||||
|         result_pd = Timestamp(dt).replace(tzinfo=tzinfo).replace(tzinfo=None) | ||||
|  | ||||
|         # datetime.timestamp() converts in the local timezone | ||||
|         with tm.set_timezone("UTC"): | ||||
|             assert result_dt.timestamp() == result_pd.timestamp() | ||||
|  | ||||
|         assert result_dt == result_pd | ||||
|         assert result_dt == result_pd.to_pydatetime() | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "tz, normalize", | ||||
|         [ | ||||
|             (pytz.timezone("US/Eastern"), lambda x: x.tzinfo.normalize(x)), | ||||
|             (gettz("US/Eastern"), lambda x: x), | ||||
|         ], | ||||
|     ) | ||||
|     def test_replace_across_dst(self, tz, normalize): | ||||
|         # GH#18319 check that 1) timezone is correctly normalized and | ||||
|         # 2) that hour is not incorrectly changed by this normalization | ||||
|         ts_naive = Timestamp("2017-12-03 16:03:30") | ||||
|         ts_aware = conversion.localize_pydatetime(ts_naive, tz) | ||||
|  | ||||
|         # Preliminary sanity-check | ||||
|         assert ts_aware == normalize(ts_aware) | ||||
|  | ||||
|         # Replace across DST boundary | ||||
|         ts2 = ts_aware.replace(month=6) | ||||
|  | ||||
|         # Check that `replace` preserves hour literal | ||||
|         assert (ts2.hour, ts2.minute) == (ts_aware.hour, ts_aware.minute) | ||||
|  | ||||
|         # Check that post-replace object is appropriately normalized | ||||
|         ts2b = normalize(ts2) | ||||
|         assert ts2 == ts2b | ||||
|  | ||||
|     @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"]) | ||||
|     def test_replace_dst_border(self, unit): | ||||
|         # Gh 7825 | ||||
|         t = Timestamp("2013-11-3", tz="America/Chicago").as_unit(unit) | ||||
|         result = t.replace(hour=3) | ||||
|         expected = Timestamp("2013-11-3 03:00:00", tz="America/Chicago") | ||||
|         assert result == expected | ||||
|         assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value | ||||
|  | ||||
|     @pytest.mark.parametrize("fold", [0, 1]) | ||||
|     @pytest.mark.parametrize("tz", ["dateutil/Europe/London", "Europe/London"]) | ||||
|     @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"]) | ||||
|     def test_replace_dst_fold(self, fold, tz, unit): | ||||
|         # GH 25017 | ||||
|         d = datetime(2019, 10, 27, 2, 30) | ||||
|         ts = Timestamp(d, tz=tz).as_unit(unit) | ||||
|         result = ts.replace(hour=1, fold=fold) | ||||
|         expected = Timestamp(datetime(2019, 10, 27, 1, 30)).tz_localize( | ||||
|             tz, ambiguous=not fold | ||||
|         ) | ||||
|         assert result == expected | ||||
|         assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value | ||||
|  | ||||
|     @pytest.mark.parametrize("fold", [0, 1]) | ||||
|     def test_replace_preserves_fold(self, fold): | ||||
|         # GH#37610. Check that replace preserves Timestamp fold property | ||||
|         tz = gettz("Europe/Moscow") | ||||
|  | ||||
|         ts = Timestamp( | ||||
|             year=2009, month=10, day=25, hour=2, minute=30, fold=fold, tzinfo=tz | ||||
|         ) | ||||
|         ts_replaced = ts.replace(second=1) | ||||
|  | ||||
|         assert ts_replaced.fold == fold | ||||
| @ -0,0 +1,383 @@ | ||||
| from hypothesis import ( | ||||
|     given, | ||||
|     strategies as st, | ||||
| ) | ||||
| import numpy as np | ||||
| import pytest | ||||
| import pytz | ||||
|  | ||||
| from pandas._libs import lib | ||||
| from pandas._libs.tslibs import ( | ||||
|     NaT, | ||||
|     OutOfBoundsDatetime, | ||||
|     Timedelta, | ||||
|     Timestamp, | ||||
|     iNaT, | ||||
|     to_offset, | ||||
| ) | ||||
| from pandas._libs.tslibs.dtypes import NpyDatetimeUnit | ||||
| from pandas._libs.tslibs.period import INVALID_FREQ_ERR_MSG | ||||
|  | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimestampRound: | ||||
|     def test_round_division_by_zero_raises(self): | ||||
|         ts = Timestamp("2016-01-01") | ||||
|  | ||||
|         msg = "Division by zero in rounding" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             ts.round("0ns") | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "timestamp, freq, expected", | ||||
|         [ | ||||
|             ("20130101 09:10:11", "D", "20130101"), | ||||
|             ("20130101 19:10:11", "D", "20130102"), | ||||
|             ("20130201 12:00:00", "D", "20130202"), | ||||
|             ("20130104 12:00:00", "D", "20130105"), | ||||
|             ("2000-01-05 05:09:15.13", "D", "2000-01-05 00:00:00"), | ||||
|             ("2000-01-05 05:09:15.13", "h", "2000-01-05 05:00:00"), | ||||
|             ("2000-01-05 05:09:15.13", "s", "2000-01-05 05:09:15"), | ||||
|         ], | ||||
|     ) | ||||
|     def test_round_frequencies(self, timestamp, freq, expected): | ||||
|         dt = Timestamp(timestamp) | ||||
|         result = dt.round(freq) | ||||
|         expected = Timestamp(expected) | ||||
|         assert result == expected | ||||
|  | ||||
|     def test_round_tzaware(self): | ||||
|         dt = Timestamp("20130101 09:10:11", tz="US/Eastern") | ||||
|         result = dt.round("D") | ||||
|         expected = Timestamp("20130101", tz="US/Eastern") | ||||
|         assert result == expected | ||||
|  | ||||
|         dt = Timestamp("20130101 09:10:11", tz="US/Eastern") | ||||
|         result = dt.round("s") | ||||
|         assert result == dt | ||||
|  | ||||
|     def test_round_30min(self): | ||||
|         # round | ||||
|         dt = Timestamp("20130104 12:32:00") | ||||
|         result = dt.round("30Min") | ||||
|         expected = Timestamp("20130104 12:30:00") | ||||
|         assert result == expected | ||||
|  | ||||
|     def test_round_subsecond(self): | ||||
|         # GH#14440 & GH#15578 | ||||
|         result = Timestamp("2016-10-17 12:00:00.0015").round("ms") | ||||
|         expected = Timestamp("2016-10-17 12:00:00.002000") | ||||
|         assert result == expected | ||||
|  | ||||
|         result = Timestamp("2016-10-17 12:00:00.00149").round("ms") | ||||
|         expected = Timestamp("2016-10-17 12:00:00.001000") | ||||
|         assert result == expected | ||||
|  | ||||
|         ts = Timestamp("2016-10-17 12:00:00.0015") | ||||
|         for freq in ["us", "ns"]: | ||||
|             assert ts == ts.round(freq) | ||||
|  | ||||
|         result = Timestamp("2016-10-17 12:00:00.001501031").round("10ns") | ||||
|         expected = Timestamp("2016-10-17 12:00:00.001501030") | ||||
|         assert result == expected | ||||
|  | ||||
|     def test_round_nonstandard_freq(self): | ||||
|         with tm.assert_produces_warning(False): | ||||
|             Timestamp("2016-10-17 12:00:00.001501031").round("1010ns") | ||||
|  | ||||
|     def test_round_invalid_arg(self): | ||||
|         stamp = Timestamp("2000-01-05 05:09:15.13") | ||||
|         with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): | ||||
|             stamp.round("foo") | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "test_input, rounder, freq, expected", | ||||
|         [ | ||||
|             ("2117-01-01 00:00:45", "floor", "15s", "2117-01-01 00:00:45"), | ||||
|             ("2117-01-01 00:00:45", "ceil", "15s", "2117-01-01 00:00:45"), | ||||
|             ( | ||||
|                 "2117-01-01 00:00:45.000000012", | ||||
|                 "floor", | ||||
|                 "10ns", | ||||
|                 "2117-01-01 00:00:45.000000010", | ||||
|             ), | ||||
|             ( | ||||
|                 "1823-01-01 00:00:01.000000012", | ||||
|                 "ceil", | ||||
|                 "10ns", | ||||
|                 "1823-01-01 00:00:01.000000020", | ||||
|             ), | ||||
|             ("1823-01-01 00:00:01", "floor", "1s", "1823-01-01 00:00:01"), | ||||
|             ("1823-01-01 00:00:01", "ceil", "1s", "1823-01-01 00:00:01"), | ||||
|             ("NaT", "floor", "1s", "NaT"), | ||||
|             ("NaT", "ceil", "1s", "NaT"), | ||||
|         ], | ||||
|     ) | ||||
|     def test_ceil_floor_edge(self, test_input, rounder, freq, expected): | ||||
|         dt = Timestamp(test_input) | ||||
|         func = getattr(dt, rounder) | ||||
|         result = func(freq) | ||||
|  | ||||
|         if dt is NaT: | ||||
|             assert result is NaT | ||||
|         else: | ||||
|             expected = Timestamp(expected) | ||||
|             assert result == expected | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "test_input, freq, expected", | ||||
|         [ | ||||
|             ("2018-01-01 00:02:06", "2s", "2018-01-01 00:02:06"), | ||||
|             ("2018-01-01 00:02:00", "2min", "2018-01-01 00:02:00"), | ||||
|             ("2018-01-01 00:04:00", "4min", "2018-01-01 00:04:00"), | ||||
|             ("2018-01-01 00:15:00", "15min", "2018-01-01 00:15:00"), | ||||
|             ("2018-01-01 00:20:00", "20min", "2018-01-01 00:20:00"), | ||||
|             ("2018-01-01 03:00:00", "3h", "2018-01-01 03:00:00"), | ||||
|         ], | ||||
|     ) | ||||
|     @pytest.mark.parametrize("rounder", ["ceil", "floor", "round"]) | ||||
|     def test_round_minute_freq(self, test_input, freq, expected, rounder): | ||||
|         # Ensure timestamps that shouldn't round dont! | ||||
|         # GH#21262 | ||||
|  | ||||
|         dt = Timestamp(test_input) | ||||
|         expected = Timestamp(expected) | ||||
|         func = getattr(dt, rounder) | ||||
|         result = func(freq) | ||||
|         assert result == expected | ||||
|  | ||||
|     @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"]) | ||||
|     def test_ceil(self, unit): | ||||
|         dt = Timestamp("20130101 09:10:11").as_unit(unit) | ||||
|         result = dt.ceil("D") | ||||
|         expected = Timestamp("20130102") | ||||
|         assert result == expected | ||||
|         assert result._creso == dt._creso | ||||
|  | ||||
|     @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"]) | ||||
|     def test_floor(self, unit): | ||||
|         dt = Timestamp("20130101 09:10:11").as_unit(unit) | ||||
|         result = dt.floor("D") | ||||
|         expected = Timestamp("20130101") | ||||
|         assert result == expected | ||||
|         assert result._creso == dt._creso | ||||
|  | ||||
|     @pytest.mark.parametrize("method", ["ceil", "round", "floor"]) | ||||
|     @pytest.mark.parametrize( | ||||
|         "unit", | ||||
|         ["ns", "us", "ms", "s"], | ||||
|     ) | ||||
|     def test_round_dst_border_ambiguous(self, method, unit): | ||||
|         # GH 18946 round near "fall back" DST | ||||
|         ts = Timestamp("2017-10-29 00:00:00", tz="UTC").tz_convert("Europe/Madrid") | ||||
|         ts = ts.as_unit(unit) | ||||
|         # | ||||
|         result = getattr(ts, method)("h", ambiguous=True) | ||||
|         assert result == ts | ||||
|         assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value | ||||
|  | ||||
|         result = getattr(ts, method)("h", ambiguous=False) | ||||
|         expected = Timestamp("2017-10-29 01:00:00", tz="UTC").tz_convert( | ||||
|             "Europe/Madrid" | ||||
|         ) | ||||
|         assert result == expected | ||||
|         assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value | ||||
|  | ||||
|         result = getattr(ts, method)("h", ambiguous="NaT") | ||||
|         assert result is NaT | ||||
|  | ||||
|         msg = "Cannot infer dst time" | ||||
|         with pytest.raises(pytz.AmbiguousTimeError, match=msg): | ||||
|             getattr(ts, method)("h", ambiguous="raise") | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "method, ts_str, freq", | ||||
|         [ | ||||
|             ["ceil", "2018-03-11 01:59:00-0600", "5min"], | ||||
|             ["round", "2018-03-11 01:59:00-0600", "5min"], | ||||
|             ["floor", "2018-03-11 03:01:00-0500", "2h"], | ||||
|         ], | ||||
|     ) | ||||
|     @pytest.mark.parametrize( | ||||
|         "unit", | ||||
|         ["ns", "us", "ms", "s"], | ||||
|     ) | ||||
|     def test_round_dst_border_nonexistent(self, method, ts_str, freq, unit): | ||||
|         # GH 23324 round near "spring forward" DST | ||||
|         ts = Timestamp(ts_str, tz="America/Chicago").as_unit(unit) | ||||
|         result = getattr(ts, method)(freq, nonexistent="shift_forward") | ||||
|         expected = Timestamp("2018-03-11 03:00:00", tz="America/Chicago") | ||||
|         assert result == expected | ||||
|         assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value | ||||
|  | ||||
|         result = getattr(ts, method)(freq, nonexistent="NaT") | ||||
|         assert result is NaT | ||||
|  | ||||
|         msg = "2018-03-11 02:00:00" | ||||
|         with pytest.raises(pytz.NonExistentTimeError, match=msg): | ||||
|             getattr(ts, method)(freq, nonexistent="raise") | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "timestamp", | ||||
|         [ | ||||
|             "2018-01-01 0:0:0.124999360", | ||||
|             "2018-01-01 0:0:0.125000367", | ||||
|             "2018-01-01 0:0:0.125500", | ||||
|             "2018-01-01 0:0:0.126500", | ||||
|             "2018-01-01 12:00:00", | ||||
|             "2019-01-01 12:00:00", | ||||
|         ], | ||||
|     ) | ||||
|     @pytest.mark.parametrize( | ||||
|         "freq", | ||||
|         [ | ||||
|             "2ns", | ||||
|             "3ns", | ||||
|             "4ns", | ||||
|             "5ns", | ||||
|             "6ns", | ||||
|             "7ns", | ||||
|             "250ns", | ||||
|             "500ns", | ||||
|             "750ns", | ||||
|             "1us", | ||||
|             "19us", | ||||
|             "250us", | ||||
|             "500us", | ||||
|             "750us", | ||||
|             "1s", | ||||
|             "2s", | ||||
|             "3s", | ||||
|             "1D", | ||||
|         ], | ||||
|     ) | ||||
|     def test_round_int64(self, timestamp, freq): | ||||
|         # check that all rounding modes are accurate to int64 precision | ||||
|         # see GH#22591 | ||||
|         dt = Timestamp(timestamp).as_unit("ns") | ||||
|         unit = to_offset(freq).nanos | ||||
|  | ||||
|         # test floor | ||||
|         result = dt.floor(freq) | ||||
|         assert result._value % unit == 0, f"floor not a {freq} multiple" | ||||
|         assert 0 <= dt._value - result._value < unit, "floor error" | ||||
|  | ||||
|         # test ceil | ||||
|         result = dt.ceil(freq) | ||||
|         assert result._value % unit == 0, f"ceil not a {freq} multiple" | ||||
|         assert 0 <= result._value - dt._value < unit, "ceil error" | ||||
|  | ||||
|         # test round | ||||
|         result = dt.round(freq) | ||||
|         assert result._value % unit == 0, f"round not a {freq} multiple" | ||||
|         assert abs(result._value - dt._value) <= unit // 2, "round error" | ||||
|         if unit % 2 == 0 and abs(result._value - dt._value) == unit // 2: | ||||
|             # round half to even | ||||
|             assert result._value // unit % 2 == 0, "round half to even error" | ||||
|  | ||||
|     def test_round_implementation_bounds(self): | ||||
|         # See also: analogous test for Timedelta | ||||
|         result = Timestamp.min.ceil("s") | ||||
|         expected = Timestamp(1677, 9, 21, 0, 12, 44) | ||||
|         assert result == expected | ||||
|  | ||||
|         result = Timestamp.max.floor("s") | ||||
|         expected = Timestamp.max - Timedelta(854775807) | ||||
|         assert result == expected | ||||
|  | ||||
|         msg = "Cannot round 1677-09-21 00:12:43.145224193 to freq=<Second>" | ||||
|         with pytest.raises(OutOfBoundsDatetime, match=msg): | ||||
|             Timestamp.min.floor("s") | ||||
|  | ||||
|         with pytest.raises(OutOfBoundsDatetime, match=msg): | ||||
|             Timestamp.min.round("s") | ||||
|  | ||||
|         msg = "Cannot round 2262-04-11 23:47:16.854775807 to freq=<Second>" | ||||
|         with pytest.raises(OutOfBoundsDatetime, match=msg): | ||||
|             Timestamp.max.ceil("s") | ||||
|  | ||||
|         with pytest.raises(OutOfBoundsDatetime, match=msg): | ||||
|             Timestamp.max.round("s") | ||||
|  | ||||
|     @given(val=st.integers(iNaT + 1, lib.i8max)) | ||||
|     @pytest.mark.parametrize( | ||||
|         "method", [Timestamp.round, Timestamp.floor, Timestamp.ceil] | ||||
|     ) | ||||
|     def test_round_sanity(self, val, method): | ||||
|         cls = Timestamp | ||||
|         err_cls = OutOfBoundsDatetime | ||||
|  | ||||
|         val = np.int64(val) | ||||
|         ts = cls(val) | ||||
|  | ||||
|         def checker(ts, nanos, unit): | ||||
|             # First check that we do raise in cases where we should | ||||
|             if nanos == 1: | ||||
|                 pass | ||||
|             else: | ||||
|                 div, mod = divmod(ts._value, nanos) | ||||
|                 diff = int(nanos - mod) | ||||
|                 lb = ts._value - mod | ||||
|                 assert lb <= ts._value  # i.e. no overflows with python ints | ||||
|                 ub = ts._value + diff | ||||
|                 assert ub > ts._value  # i.e. no overflows with python ints | ||||
|  | ||||
|                 msg = "without overflow" | ||||
|                 if mod == 0: | ||||
|                     # We should never be raising in this | ||||
|                     pass | ||||
|                 elif method is cls.ceil: | ||||
|                     if ub > cls.max._value: | ||||
|                         with pytest.raises(err_cls, match=msg): | ||||
|                             method(ts, unit) | ||||
|                         return | ||||
|                 elif method is cls.floor: | ||||
|                     if lb < cls.min._value: | ||||
|                         with pytest.raises(err_cls, match=msg): | ||||
|                             method(ts, unit) | ||||
|                         return | ||||
|                 elif mod >= diff: | ||||
|                     if ub > cls.max._value: | ||||
|                         with pytest.raises(err_cls, match=msg): | ||||
|                             method(ts, unit) | ||||
|                         return | ||||
|                 elif lb < cls.min._value: | ||||
|                     with pytest.raises(err_cls, match=msg): | ||||
|                         method(ts, unit) | ||||
|                     return | ||||
|  | ||||
|             res = method(ts, unit) | ||||
|  | ||||
|             td = res - ts | ||||
|             diff = abs(td._value) | ||||
|             assert diff < nanos | ||||
|             assert res._value % nanos == 0 | ||||
|  | ||||
|             if method is cls.round: | ||||
|                 assert diff <= nanos / 2 | ||||
|             elif method is cls.floor: | ||||
|                 assert res <= ts | ||||
|             elif method is cls.ceil: | ||||
|                 assert res >= ts | ||||
|  | ||||
|         nanos = 1 | ||||
|         checker(ts, nanos, "ns") | ||||
|  | ||||
|         nanos = 1000 | ||||
|         checker(ts, nanos, "us") | ||||
|  | ||||
|         nanos = 1_000_000 | ||||
|         checker(ts, nanos, "ms") | ||||
|  | ||||
|         nanos = 1_000_000_000 | ||||
|         checker(ts, nanos, "s") | ||||
|  | ||||
|         nanos = 60 * 1_000_000_000 | ||||
|         checker(ts, nanos, "min") | ||||
|  | ||||
|         nanos = 60 * 60 * 1_000_000_000 | ||||
|         checker(ts, nanos, "h") | ||||
|  | ||||
|         nanos = 24 * 60 * 60 * 1_000_000_000 | ||||
|         checker(ts, nanos, "D") | ||||
| @ -0,0 +1,31 @@ | ||||
| # NB: This is for the Timestamp.timestamp *method* specifically, not | ||||
| # the Timestamp class in general. | ||||
|  | ||||
| from pytz import utc | ||||
|  | ||||
| from pandas._libs.tslibs import Timestamp | ||||
| import pandas.util._test_decorators as td | ||||
|  | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimestampMethod: | ||||
|     @td.skip_if_windows | ||||
|     def test_timestamp(self, fixed_now_ts): | ||||
|         # GH#17329 | ||||
|         # tz-naive --> treat it as if it were UTC for purposes of timestamp() | ||||
|         ts = fixed_now_ts | ||||
|         uts = ts.replace(tzinfo=utc) | ||||
|         assert ts.timestamp() == uts.timestamp() | ||||
|  | ||||
|         tsc = Timestamp("2014-10-11 11:00:01.12345678", tz="US/Central") | ||||
|         utsc = tsc.tz_convert("UTC") | ||||
|  | ||||
|         # utsc is a different representation of the same time | ||||
|         assert tsc.timestamp() == utsc.timestamp() | ||||
|  | ||||
|         # datetime.timestamp() converts in the local timezone | ||||
|         with tm.set_timezone("UTC"): | ||||
|             # should agree with datetime.timestamp method | ||||
|             dt = ts.to_pydatetime() | ||||
|             assert dt.timestamp() == ts.timestamp() | ||||
| @ -0,0 +1,28 @@ | ||||
| from pandas import Timestamp | ||||
|  | ||||
|  | ||||
| class TestTimestampToJulianDate: | ||||
|     def test_compare_1700(self): | ||||
|         ts = Timestamp("1700-06-23") | ||||
|         res = ts.to_julian_date() | ||||
|         assert res == 2_342_145.5 | ||||
|  | ||||
|     def test_compare_2000(self): | ||||
|         ts = Timestamp("2000-04-12") | ||||
|         res = ts.to_julian_date() | ||||
|         assert res == 2_451_646.5 | ||||
|  | ||||
|     def test_compare_2100(self): | ||||
|         ts = Timestamp("2100-08-12") | ||||
|         res = ts.to_julian_date() | ||||
|         assert res == 2_488_292.5 | ||||
|  | ||||
|     def test_compare_hour01(self): | ||||
|         ts = Timestamp("2000-08-12T01:00:00") | ||||
|         res = ts.to_julian_date() | ||||
|         assert res == 2_451_768.5416666666666666 | ||||
|  | ||||
|     def test_compare_hour13(self): | ||||
|         ts = Timestamp("2000-08-12T13:00:00") | ||||
|         res = ts.to_julian_date() | ||||
|         assert res == 2_451_769.0416666666666666 | ||||
| @ -0,0 +1,81 @@ | ||||
| from datetime import ( | ||||
|     datetime, | ||||
|     timedelta, | ||||
| ) | ||||
|  | ||||
| import pytz | ||||
|  | ||||
| from pandas._libs.tslibs.timezones import dateutil_gettz as gettz | ||||
| import pandas.util._test_decorators as td | ||||
|  | ||||
| from pandas import Timestamp | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimestampToPyDatetime: | ||||
|     def test_to_pydatetime_fold(self): | ||||
|         # GH#45087 | ||||
|         tzstr = "dateutil/usr/share/zoneinfo/America/Chicago" | ||||
|         ts = Timestamp(year=2013, month=11, day=3, hour=1, minute=0, fold=1, tz=tzstr) | ||||
|         dt = ts.to_pydatetime() | ||||
|         assert dt.fold == 1 | ||||
|  | ||||
|     def test_to_pydatetime_nonzero_nano(self): | ||||
|         ts = Timestamp("2011-01-01 9:00:00.123456789") | ||||
|  | ||||
|         # Warn the user of data loss (nanoseconds). | ||||
|         with tm.assert_produces_warning(UserWarning): | ||||
|             expected = datetime(2011, 1, 1, 9, 0, 0, 123456) | ||||
|             result = ts.to_pydatetime() | ||||
|             assert result == expected | ||||
|  | ||||
|     def test_timestamp_to_datetime(self): | ||||
|         stamp = Timestamp("20090415", tz="US/Eastern") | ||||
|         dtval = stamp.to_pydatetime() | ||||
|         assert stamp == dtval | ||||
|         assert stamp.tzinfo == dtval.tzinfo | ||||
|  | ||||
|     def test_timestamp_to_pydatetime_dateutil(self): | ||||
|         stamp = Timestamp("20090415", tz="dateutil/US/Eastern") | ||||
|         dtval = stamp.to_pydatetime() | ||||
|         assert stamp == dtval | ||||
|         assert stamp.tzinfo == dtval.tzinfo | ||||
|  | ||||
|     def test_timestamp_to_pydatetime_explicit_pytz(self): | ||||
|         stamp = Timestamp("20090415", tz=pytz.timezone("US/Eastern")) | ||||
|         dtval = stamp.to_pydatetime() | ||||
|         assert stamp == dtval | ||||
|         assert stamp.tzinfo == dtval.tzinfo | ||||
|  | ||||
|     @td.skip_if_windows | ||||
|     def test_timestamp_to_pydatetime_explicit_dateutil(self): | ||||
|         stamp = Timestamp("20090415", tz=gettz("US/Eastern")) | ||||
|         dtval = stamp.to_pydatetime() | ||||
|         assert stamp == dtval | ||||
|         assert stamp.tzinfo == dtval.tzinfo | ||||
|  | ||||
|     def test_to_pydatetime_bijective(self): | ||||
|         # Ensure that converting to datetime and back only loses precision | ||||
|         # by going from nanoseconds to microseconds. | ||||
|         exp_warning = None if Timestamp.max.nanosecond == 0 else UserWarning | ||||
|         with tm.assert_produces_warning(exp_warning): | ||||
|             pydt_max = Timestamp.max.to_pydatetime() | ||||
|  | ||||
|         assert ( | ||||
|             Timestamp(pydt_max).as_unit("ns")._value / 1000 | ||||
|             == Timestamp.max._value / 1000 | ||||
|         ) | ||||
|  | ||||
|         exp_warning = None if Timestamp.min.nanosecond == 0 else UserWarning | ||||
|         with tm.assert_produces_warning(exp_warning): | ||||
|             pydt_min = Timestamp.min.to_pydatetime() | ||||
|  | ||||
|         # The next assertion can be enabled once GH#39221 is merged | ||||
|         #  assert pydt_min < Timestamp.min  # this is bc nanos are dropped | ||||
|         tdus = timedelta(microseconds=1) | ||||
|         assert pydt_min + tdus > Timestamp.min | ||||
|  | ||||
|         assert ( | ||||
|             Timestamp(pydt_min + tdus).as_unit("ns")._value / 1000 | ||||
|             == Timestamp.min._value / 1000 | ||||
|         ) | ||||
| @ -0,0 +1,51 @@ | ||||
| import dateutil | ||||
| import pytest | ||||
|  | ||||
| from pandas._libs.tslibs import timezones | ||||
| import pandas.util._test_decorators as td | ||||
|  | ||||
| from pandas import Timestamp | ||||
|  | ||||
|  | ||||
| class TestTimestampTZConvert: | ||||
|     @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) | ||||
|     def test_astimezone(self, tzstr): | ||||
|         # astimezone is an alias for tz_convert, so keep it with | ||||
|         # the tz_convert tests | ||||
|         utcdate = Timestamp("3/11/2012 22:00", tz="UTC") | ||||
|         expected = utcdate.tz_convert(tzstr) | ||||
|         result = utcdate.astimezone(tzstr) | ||||
|         assert expected == result | ||||
|         assert isinstance(result, Timestamp) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "stamp", | ||||
|         [ | ||||
|             "2014-02-01 09:00", | ||||
|             "2014-07-08 09:00", | ||||
|             "2014-11-01 17:00", | ||||
|             "2014-11-05 00:00", | ||||
|         ], | ||||
|     ) | ||||
|     def test_tz_convert_roundtrip(self, stamp, tz_aware_fixture): | ||||
|         tz = tz_aware_fixture | ||||
|  | ||||
|         ts = Timestamp(stamp, tz="UTC") | ||||
|         converted = ts.tz_convert(tz) | ||||
|  | ||||
|         reset = converted.tz_convert(None) | ||||
|         assert reset == Timestamp(stamp) | ||||
|         assert reset.tzinfo is None | ||||
|         assert reset == converted.tz_convert("UTC").tz_localize(None) | ||||
|  | ||||
|     @td.skip_if_windows | ||||
|     def test_tz_convert_utc_with_system_utc(self): | ||||
|         # from system utc to real utc | ||||
|         ts = Timestamp("2001-01-05 11:56", tz=timezones.maybe_get_tz("dateutil/UTC")) | ||||
|         # check that the time hasn't changed. | ||||
|         assert ts == ts.tz_convert(dateutil.tz.tzutc()) | ||||
|  | ||||
|         # from system utc to real utc | ||||
|         ts = Timestamp("2001-01-05 11:56", tz=timezones.maybe_get_tz("dateutil/UTC")) | ||||
|         # check that the time hasn't changed. | ||||
|         assert ts == ts.tz_convert(dateutil.tz.tzutc()) | ||||
| @ -0,0 +1,351 @@ | ||||
| from datetime import timedelta | ||||
| import re | ||||
|  | ||||
| from dateutil.tz import gettz | ||||
| import pytest | ||||
| import pytz | ||||
| from pytz.exceptions import ( | ||||
|     AmbiguousTimeError, | ||||
|     NonExistentTimeError, | ||||
| ) | ||||
|  | ||||
| from pandas._libs.tslibs.dtypes import NpyDatetimeUnit | ||||
| from pandas.errors import OutOfBoundsDatetime | ||||
|  | ||||
| from pandas import ( | ||||
|     NaT, | ||||
|     Timestamp, | ||||
| ) | ||||
|  | ||||
| try: | ||||
|     from zoneinfo import ZoneInfo | ||||
| except ImportError: | ||||
|     # Cannot assign to a type | ||||
|     ZoneInfo = None  # type: ignore[misc, assignment] | ||||
|  | ||||
|  | ||||
| class TestTimestampTZLocalize: | ||||
|     @pytest.mark.skip_ubsan | ||||
|     def test_tz_localize_pushes_out_of_bounds(self): | ||||
|         # GH#12677 | ||||
|         # tz_localize that pushes away from the boundary is OK | ||||
|         msg = ( | ||||
|             f"Converting {Timestamp.min.strftime('%Y-%m-%d %H:%M:%S')} " | ||||
|             f"underflows past {Timestamp.min}" | ||||
|         ) | ||||
|         pac = Timestamp.min.tz_localize("US/Pacific") | ||||
|         assert pac._value > Timestamp.min._value | ||||
|         pac.tz_convert("Asia/Tokyo")  # tz_convert doesn't change value | ||||
|         with pytest.raises(OutOfBoundsDatetime, match=msg): | ||||
|             Timestamp.min.tz_localize("Asia/Tokyo") | ||||
|  | ||||
|         # tz_localize that pushes away from the boundary is OK | ||||
|         msg = ( | ||||
|             f"Converting {Timestamp.max.strftime('%Y-%m-%d %H:%M:%S')} " | ||||
|             f"overflows past {Timestamp.max}" | ||||
|         ) | ||||
|         tokyo = Timestamp.max.tz_localize("Asia/Tokyo") | ||||
|         assert tokyo._value < Timestamp.max._value | ||||
|         tokyo.tz_convert("US/Pacific")  # tz_convert doesn't change value | ||||
|         with pytest.raises(OutOfBoundsDatetime, match=msg): | ||||
|             Timestamp.max.tz_localize("US/Pacific") | ||||
|  | ||||
|     @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"]) | ||||
|     def test_tz_localize_ambiguous_bool(self, unit): | ||||
|         # make sure that we are correctly accepting bool values as ambiguous | ||||
|         # GH#14402 | ||||
|         ts = Timestamp("2015-11-01 01:00:03").as_unit(unit) | ||||
|         expected0 = Timestamp("2015-11-01 01:00:03-0500", tz="US/Central") | ||||
|         expected1 = Timestamp("2015-11-01 01:00:03-0600", tz="US/Central") | ||||
|  | ||||
|         msg = "Cannot infer dst time from 2015-11-01 01:00:03" | ||||
|         with pytest.raises(pytz.AmbiguousTimeError, match=msg): | ||||
|             ts.tz_localize("US/Central") | ||||
|  | ||||
|         with pytest.raises(pytz.AmbiguousTimeError, match=msg): | ||||
|             ts.tz_localize("dateutil/US/Central") | ||||
|  | ||||
|         if ZoneInfo is not None: | ||||
|             try: | ||||
|                 tz = ZoneInfo("US/Central") | ||||
|             except KeyError: | ||||
|                 # no tzdata | ||||
|                 pass | ||||
|             else: | ||||
|                 with pytest.raises(pytz.AmbiguousTimeError, match=msg): | ||||
|                     ts.tz_localize(tz) | ||||
|  | ||||
|         result = ts.tz_localize("US/Central", ambiguous=True) | ||||
|         assert result == expected0 | ||||
|         assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value | ||||
|  | ||||
|         result = ts.tz_localize("US/Central", ambiguous=False) | ||||
|         assert result == expected1 | ||||
|         assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value | ||||
|  | ||||
|     def test_tz_localize_ambiguous(self): | ||||
|         ts = Timestamp("2014-11-02 01:00") | ||||
|         ts_dst = ts.tz_localize("US/Eastern", ambiguous=True) | ||||
|         ts_no_dst = ts.tz_localize("US/Eastern", ambiguous=False) | ||||
|  | ||||
|         assert ts_no_dst._value - ts_dst._value == 3600 | ||||
|         msg = re.escape( | ||||
|             "'ambiguous' parameter must be one of: " | ||||
|             "True, False, 'NaT', 'raise' (default)" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             ts.tz_localize("US/Eastern", ambiguous="infer") | ||||
|  | ||||
|         # GH#8025 | ||||
|         msg = "Cannot localize tz-aware Timestamp, use tz_convert for conversions" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             Timestamp("2011-01-01", tz="US/Eastern").tz_localize("Asia/Tokyo") | ||||
|  | ||||
|         msg = "Cannot convert tz-naive Timestamp, use tz_localize to localize" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             Timestamp("2011-01-01").tz_convert("Asia/Tokyo") | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "stamp, tz", | ||||
|         [ | ||||
|             ("2015-03-08 02:00", "US/Eastern"), | ||||
|             ("2015-03-08 02:30", "US/Pacific"), | ||||
|             ("2015-03-29 02:00", "Europe/Paris"), | ||||
|             ("2015-03-29 02:30", "Europe/Belgrade"), | ||||
|         ], | ||||
|     ) | ||||
|     def test_tz_localize_nonexistent(self, stamp, tz): | ||||
|         # GH#13057 | ||||
|         ts = Timestamp(stamp) | ||||
|         with pytest.raises(NonExistentTimeError, match=stamp): | ||||
|             ts.tz_localize(tz) | ||||
|         # GH 22644 | ||||
|         with pytest.raises(NonExistentTimeError, match=stamp): | ||||
|             ts.tz_localize(tz, nonexistent="raise") | ||||
|         assert ts.tz_localize(tz, nonexistent="NaT") is NaT | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "stamp, tz, forward_expected, backward_expected", | ||||
|         [ | ||||
|             ( | ||||
|                 "2015-03-29 02:00:00", | ||||
|                 "Europe/Warsaw", | ||||
|                 "2015-03-29 03:00:00", | ||||
|                 "2015-03-29 01:59:59", | ||||
|             ),  # utc+1 -> utc+2 | ||||
|             ( | ||||
|                 "2023-03-12 02:00:00", | ||||
|                 "America/Los_Angeles", | ||||
|                 "2023-03-12 03:00:00", | ||||
|                 "2023-03-12 01:59:59", | ||||
|             ),  # utc-8 -> utc-7 | ||||
|             ( | ||||
|                 "2023-03-26 01:00:00", | ||||
|                 "Europe/London", | ||||
|                 "2023-03-26 02:00:00", | ||||
|                 "2023-03-26 00:59:59", | ||||
|             ),  # utc+0 -> utc+1 | ||||
|             ( | ||||
|                 "2023-03-26 00:00:00", | ||||
|                 "Atlantic/Azores", | ||||
|                 "2023-03-26 01:00:00", | ||||
|                 "2023-03-25 23:59:59", | ||||
|             ),  # utc-1 -> utc+0 | ||||
|         ], | ||||
|     ) | ||||
|     def test_tz_localize_nonexistent_shift( | ||||
|         self, stamp, tz, forward_expected, backward_expected | ||||
|     ): | ||||
|         ts = Timestamp(stamp) | ||||
|         forward_ts = ts.tz_localize(tz, nonexistent="shift_forward") | ||||
|         assert forward_ts == Timestamp(forward_expected, tz=tz) | ||||
|         backward_ts = ts.tz_localize(tz, nonexistent="shift_backward") | ||||
|         assert backward_ts == Timestamp(backward_expected, tz=tz) | ||||
|  | ||||
|     def test_tz_localize_ambiguous_raise(self): | ||||
|         # GH#13057 | ||||
|         ts = Timestamp("2015-11-1 01:00") | ||||
|         msg = "Cannot infer dst time from 2015-11-01 01:00:00," | ||||
|         with pytest.raises(AmbiguousTimeError, match=msg): | ||||
|             ts.tz_localize("US/Pacific", ambiguous="raise") | ||||
|  | ||||
|     def test_tz_localize_nonexistent_invalid_arg(self, warsaw): | ||||
|         # GH 22644 | ||||
|         tz = warsaw | ||||
|         ts = Timestamp("2015-03-29 02:00:00") | ||||
|         msg = ( | ||||
|             "The nonexistent argument must be one of 'raise', 'NaT', " | ||||
|             "'shift_forward', 'shift_backward' or a timedelta object" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             ts.tz_localize(tz, nonexistent="foo") | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "stamp", | ||||
|         [ | ||||
|             "2014-02-01 09:00", | ||||
|             "2014-07-08 09:00", | ||||
|             "2014-11-01 17:00", | ||||
|             "2014-11-05 00:00", | ||||
|         ], | ||||
|     ) | ||||
|     def test_tz_localize_roundtrip(self, stamp, tz_aware_fixture): | ||||
|         tz = tz_aware_fixture | ||||
|         ts = Timestamp(stamp) | ||||
|         localized = ts.tz_localize(tz) | ||||
|         assert localized == Timestamp(stamp, tz=tz) | ||||
|  | ||||
|         msg = "Cannot localize tz-aware Timestamp" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             localized.tz_localize(tz) | ||||
|  | ||||
|         reset = localized.tz_localize(None) | ||||
|         assert reset == ts | ||||
|         assert reset.tzinfo is None | ||||
|  | ||||
|     def test_tz_localize_ambiguous_compat(self): | ||||
|         # validate that pytz and dateutil are compat for dst | ||||
|         # when the transition happens | ||||
|         naive = Timestamp("2013-10-27 01:00:00") | ||||
|  | ||||
|         pytz_zone = "Europe/London" | ||||
|         dateutil_zone = "dateutil/Europe/London" | ||||
|         result_pytz = naive.tz_localize(pytz_zone, ambiguous=False) | ||||
|         result_dateutil = naive.tz_localize(dateutil_zone, ambiguous=False) | ||||
|         assert result_pytz._value == result_dateutil._value | ||||
|         assert result_pytz._value == 1382835600 | ||||
|  | ||||
|         # fixed ambiguous behavior | ||||
|         # see gh-14621, GH#45087 | ||||
|         assert result_pytz.to_pydatetime().tzname() == "GMT" | ||||
|         assert result_dateutil.to_pydatetime().tzname() == "GMT" | ||||
|         assert str(result_pytz) == str(result_dateutil) | ||||
|  | ||||
|         # 1 hour difference | ||||
|         result_pytz = naive.tz_localize(pytz_zone, ambiguous=True) | ||||
|         result_dateutil = naive.tz_localize(dateutil_zone, ambiguous=True) | ||||
|         assert result_pytz._value == result_dateutil._value | ||||
|         assert result_pytz._value == 1382832000 | ||||
|  | ||||
|         # see gh-14621 | ||||
|         assert str(result_pytz) == str(result_dateutil) | ||||
|         assert ( | ||||
|             result_pytz.to_pydatetime().tzname() | ||||
|             == result_dateutil.to_pydatetime().tzname() | ||||
|         ) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "tz", | ||||
|         [ | ||||
|             pytz.timezone("US/Eastern"), | ||||
|             gettz("US/Eastern"), | ||||
|             "US/Eastern", | ||||
|             "dateutil/US/Eastern", | ||||
|         ], | ||||
|     ) | ||||
|     def test_timestamp_tz_localize(self, tz): | ||||
|         stamp = Timestamp("3/11/2012 04:00") | ||||
|  | ||||
|         result = stamp.tz_localize(tz) | ||||
|         expected = Timestamp("3/11/2012 04:00", tz=tz) | ||||
|         assert result.hour == expected.hour | ||||
|         assert result == expected | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "start_ts, tz, end_ts, shift", | ||||
|         [ | ||||
|             ["2015-03-29 02:20:00", "Europe/Warsaw", "2015-03-29 03:00:00", "forward"], | ||||
|             [ | ||||
|                 "2015-03-29 02:20:00", | ||||
|                 "Europe/Warsaw", | ||||
|                 "2015-03-29 01:59:59.999999999", | ||||
|                 "backward", | ||||
|             ], | ||||
|             [ | ||||
|                 "2015-03-29 02:20:00", | ||||
|                 "Europe/Warsaw", | ||||
|                 "2015-03-29 03:20:00", | ||||
|                 timedelta(hours=1), | ||||
|             ], | ||||
|             [ | ||||
|                 "2015-03-29 02:20:00", | ||||
|                 "Europe/Warsaw", | ||||
|                 "2015-03-29 01:20:00", | ||||
|                 timedelta(hours=-1), | ||||
|             ], | ||||
|             ["2018-03-11 02:33:00", "US/Pacific", "2018-03-11 03:00:00", "forward"], | ||||
|             [ | ||||
|                 "2018-03-11 02:33:00", | ||||
|                 "US/Pacific", | ||||
|                 "2018-03-11 01:59:59.999999999", | ||||
|                 "backward", | ||||
|             ], | ||||
|             [ | ||||
|                 "2018-03-11 02:33:00", | ||||
|                 "US/Pacific", | ||||
|                 "2018-03-11 03:33:00", | ||||
|                 timedelta(hours=1), | ||||
|             ], | ||||
|             [ | ||||
|                 "2018-03-11 02:33:00", | ||||
|                 "US/Pacific", | ||||
|                 "2018-03-11 01:33:00", | ||||
|                 timedelta(hours=-1), | ||||
|             ], | ||||
|         ], | ||||
|     ) | ||||
|     @pytest.mark.parametrize("tz_type", ["", "dateutil/"]) | ||||
|     @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"]) | ||||
|     def test_timestamp_tz_localize_nonexistent_shift( | ||||
|         self, start_ts, tz, end_ts, shift, tz_type, unit | ||||
|     ): | ||||
|         # GH 8917, 24466 | ||||
|         tz = tz_type + tz | ||||
|         if isinstance(shift, str): | ||||
|             shift = "shift_" + shift | ||||
|         ts = Timestamp(start_ts).as_unit(unit) | ||||
|         result = ts.tz_localize(tz, nonexistent=shift) | ||||
|         expected = Timestamp(end_ts).tz_localize(tz) | ||||
|  | ||||
|         if unit == "us": | ||||
|             assert result == expected.replace(nanosecond=0) | ||||
|         elif unit == "ms": | ||||
|             micros = expected.microsecond - expected.microsecond % 1000 | ||||
|             assert result == expected.replace(microsecond=micros, nanosecond=0) | ||||
|         elif unit == "s": | ||||
|             assert result == expected.replace(microsecond=0, nanosecond=0) | ||||
|         else: | ||||
|             assert result == expected | ||||
|         assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value | ||||
|  | ||||
|     @pytest.mark.parametrize("offset", [-1, 1]) | ||||
|     def test_timestamp_tz_localize_nonexistent_shift_invalid(self, offset, warsaw): | ||||
|         # GH 8917, 24466 | ||||
|         tz = warsaw | ||||
|         ts = Timestamp("2015-03-29 02:20:00") | ||||
|         msg = "The provided timedelta will relocalize on a nonexistent time" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             ts.tz_localize(tz, nonexistent=timedelta(seconds=offset)) | ||||
|  | ||||
|     @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"]) | ||||
|     def test_timestamp_tz_localize_nonexistent_NaT(self, warsaw, unit): | ||||
|         # GH 8917 | ||||
|         tz = warsaw | ||||
|         ts = Timestamp("2015-03-29 02:20:00").as_unit(unit) | ||||
|         result = ts.tz_localize(tz, nonexistent="NaT") | ||||
|         assert result is NaT | ||||
|  | ||||
|     @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"]) | ||||
|     def test_timestamp_tz_localize_nonexistent_raise(self, warsaw, unit): | ||||
|         # GH 8917 | ||||
|         tz = warsaw | ||||
|         ts = Timestamp("2015-03-29 02:20:00").as_unit(unit) | ||||
|         msg = "2015-03-29 02:20:00" | ||||
|         with pytest.raises(pytz.NonExistentTimeError, match=msg): | ||||
|             ts.tz_localize(tz, nonexistent="raise") | ||||
|         msg = ( | ||||
|             "The nonexistent argument must be one of 'raise', 'NaT', " | ||||
|             "'shift_forward', 'shift_backward' or a timedelta object" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             ts.tz_localize(tz, nonexistent="foo") | ||||
| @ -0,0 +1,334 @@ | ||||
| from datetime import ( | ||||
|     datetime, | ||||
|     timedelta, | ||||
|     timezone, | ||||
| ) | ||||
|  | ||||
| from dateutil.tz import gettz | ||||
| import numpy as np | ||||
| import pytest | ||||
| import pytz | ||||
|  | ||||
| from pandas._libs.tslibs import ( | ||||
|     OutOfBoundsDatetime, | ||||
|     OutOfBoundsTimedelta, | ||||
|     Timedelta, | ||||
|     Timestamp, | ||||
|     offsets, | ||||
|     to_offset, | ||||
| ) | ||||
|  | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimestampArithmetic: | ||||
|     def test_overflow_offset(self): | ||||
|         # no overflow expected | ||||
|  | ||||
|         stamp = Timestamp("2000/1/1") | ||||
|         offset_no_overflow = to_offset("D") * 100 | ||||
|  | ||||
|         expected = Timestamp("2000/04/10") | ||||
|         assert stamp + offset_no_overflow == expected | ||||
|  | ||||
|         assert offset_no_overflow + stamp == expected | ||||
|  | ||||
|         expected = Timestamp("1999/09/23") | ||||
|         assert stamp - offset_no_overflow == expected | ||||
|  | ||||
|     def test_overflow_offset_raises(self): | ||||
|         # xref https://github.com/statsmodels/statsmodels/issues/3374 | ||||
|         # ends up multiplying really large numbers which overflow | ||||
|  | ||||
|         stamp = Timestamp("2017-01-13 00:00:00").as_unit("ns") | ||||
|         offset_overflow = 20169940 * offsets.Day(1) | ||||
|         lmsg2 = r"Cannot cast -?20169940 days \+?00:00:00 to unit='ns' without overflow" | ||||
|  | ||||
|         with pytest.raises(OutOfBoundsTimedelta, match=lmsg2): | ||||
|             stamp + offset_overflow | ||||
|  | ||||
|         with pytest.raises(OutOfBoundsTimedelta, match=lmsg2): | ||||
|             offset_overflow + stamp | ||||
|  | ||||
|         with pytest.raises(OutOfBoundsTimedelta, match=lmsg2): | ||||
|             stamp - offset_overflow | ||||
|  | ||||
|         # xref https://github.com/pandas-dev/pandas/issues/14080 | ||||
|         # used to crash, so check for proper overflow exception | ||||
|  | ||||
|         stamp = Timestamp("2000/1/1").as_unit("ns") | ||||
|         offset_overflow = to_offset("D") * 100**5 | ||||
|  | ||||
|         lmsg3 = ( | ||||
|             r"Cannot cast -?10000000000 days \+?00:00:00 to unit='ns' without overflow" | ||||
|         ) | ||||
|         with pytest.raises(OutOfBoundsTimedelta, match=lmsg3): | ||||
|             stamp + offset_overflow | ||||
|  | ||||
|         with pytest.raises(OutOfBoundsTimedelta, match=lmsg3): | ||||
|             offset_overflow + stamp | ||||
|  | ||||
|         with pytest.raises(OutOfBoundsTimedelta, match=lmsg3): | ||||
|             stamp - offset_overflow | ||||
|  | ||||
|     def test_overflow_timestamp_raises(self): | ||||
|         # https://github.com/pandas-dev/pandas/issues/31774 | ||||
|         msg = "Result is too large" | ||||
|         a = Timestamp("2101-01-01 00:00:00").as_unit("ns") | ||||
|         b = Timestamp("1688-01-01 00:00:00").as_unit("ns") | ||||
|  | ||||
|         with pytest.raises(OutOfBoundsDatetime, match=msg): | ||||
|             a - b | ||||
|  | ||||
|         # but we're OK for timestamp and datetime.datetime | ||||
|         assert (a - b.to_pydatetime()) == (a.to_pydatetime() - b) | ||||
|  | ||||
|     def test_delta_preserve_nanos(self): | ||||
|         val = Timestamp(1337299200000000123) | ||||
|         result = val + timedelta(1) | ||||
|         assert result.nanosecond == val.nanosecond | ||||
|  | ||||
|     def test_rsub_dtscalars(self, tz_naive_fixture): | ||||
|         # In particular, check that datetime64 - Timestamp works GH#28286 | ||||
|         td = Timedelta(1235345642000) | ||||
|         ts = Timestamp("2021-01-01", tz=tz_naive_fixture) | ||||
|         other = ts + td | ||||
|  | ||||
|         assert other - ts == td | ||||
|         assert other.to_pydatetime() - ts == td | ||||
|         if tz_naive_fixture is None: | ||||
|             assert other.to_datetime64() - ts == td | ||||
|         else: | ||||
|             msg = "Cannot subtract tz-naive and tz-aware datetime-like objects" | ||||
|             with pytest.raises(TypeError, match=msg): | ||||
|                 other.to_datetime64() - ts | ||||
|  | ||||
|     def test_timestamp_sub_datetime(self): | ||||
|         dt = datetime(2013, 10, 12) | ||||
|         ts = Timestamp(datetime(2013, 10, 13)) | ||||
|         assert (ts - dt).days == 1 | ||||
|         assert (dt - ts).days == -1 | ||||
|  | ||||
|     def test_subtract_tzaware_datetime(self): | ||||
|         t1 = Timestamp("2020-10-22T22:00:00+00:00") | ||||
|         t2 = datetime(2020, 10, 22, 22, tzinfo=timezone.utc) | ||||
|  | ||||
|         result = t1 - t2 | ||||
|  | ||||
|         assert isinstance(result, Timedelta) | ||||
|         assert result == Timedelta("0 days") | ||||
|  | ||||
|     def test_subtract_timestamp_from_different_timezone(self): | ||||
|         t1 = Timestamp("20130101").tz_localize("US/Eastern") | ||||
|         t2 = Timestamp("20130101").tz_localize("CET") | ||||
|  | ||||
|         result = t1 - t2 | ||||
|  | ||||
|         assert isinstance(result, Timedelta) | ||||
|         assert result == Timedelta("0 days 06:00:00") | ||||
|  | ||||
|     def test_subtracting_involving_datetime_with_different_tz(self): | ||||
|         t1 = datetime(2013, 1, 1, tzinfo=timezone(timedelta(hours=-5))) | ||||
|         t2 = Timestamp("20130101").tz_localize("CET") | ||||
|  | ||||
|         result = t1 - t2 | ||||
|  | ||||
|         assert isinstance(result, Timedelta) | ||||
|         assert result == Timedelta("0 days 06:00:00") | ||||
|  | ||||
|         result = t2 - t1 | ||||
|         assert isinstance(result, Timedelta) | ||||
|         assert result == Timedelta("-1 days +18:00:00") | ||||
|  | ||||
|     def test_subtracting_different_timezones(self, tz_aware_fixture): | ||||
|         t_raw = Timestamp("20130101") | ||||
|         t_UTC = t_raw.tz_localize("UTC") | ||||
|         t_diff = t_UTC.tz_convert(tz_aware_fixture) + Timedelta("0 days 05:00:00") | ||||
|  | ||||
|         result = t_diff - t_UTC | ||||
|  | ||||
|         assert isinstance(result, Timedelta) | ||||
|         assert result == Timedelta("0 days 05:00:00") | ||||
|  | ||||
|     def test_addition_subtraction_types(self): | ||||
|         # Assert on the types resulting from Timestamp +/- various date/time | ||||
|         # objects | ||||
|         dt = datetime(2014, 3, 4) | ||||
|         td = timedelta(seconds=1) | ||||
|         ts = Timestamp(dt) | ||||
|  | ||||
|         msg = "Addition/subtraction of integers" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             # GH#22535 add/sub with integers is deprecated | ||||
|             ts + 1 | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             ts - 1 | ||||
|  | ||||
|         # Timestamp + datetime not supported, though subtraction is supported | ||||
|         # and yields timedelta more tests in tseries/base/tests/test_base.py | ||||
|         assert type(ts - dt) == Timedelta | ||||
|         assert type(ts + td) == Timestamp | ||||
|         assert type(ts - td) == Timestamp | ||||
|  | ||||
|         # Timestamp +/- datetime64 not supported, so not tested (could possibly | ||||
|         # assert error raised?) | ||||
|         td64 = np.timedelta64(1, "D") | ||||
|         assert type(ts + td64) == Timestamp | ||||
|         assert type(ts - td64) == Timestamp | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "td", [Timedelta(hours=3), np.timedelta64(3, "h"), timedelta(hours=3)] | ||||
|     ) | ||||
|     def test_radd_tdscalar(self, td, fixed_now_ts): | ||||
|         # GH#24775 timedelta64+Timestamp should not raise | ||||
|         ts = fixed_now_ts | ||||
|         assert td + ts == ts + td | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "other,expected_difference", | ||||
|         [ | ||||
|             (np.timedelta64(-123, "ns"), -123), | ||||
|             (np.timedelta64(1234567898, "ns"), 1234567898), | ||||
|             (np.timedelta64(-123, "us"), -123000), | ||||
|             (np.timedelta64(-123, "ms"), -123000000), | ||||
|         ], | ||||
|     ) | ||||
|     def test_timestamp_add_timedelta64_unit(self, other, expected_difference): | ||||
|         now = datetime.now(timezone.utc) | ||||
|         ts = Timestamp(now).as_unit("ns") | ||||
|         result = ts + other | ||||
|         valdiff = result._value - ts._value | ||||
|         assert valdiff == expected_difference | ||||
|  | ||||
|         ts2 = Timestamp(now) | ||||
|         assert ts2 + other == result | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "ts", | ||||
|         [ | ||||
|             Timestamp("1776-07-04"), | ||||
|             Timestamp("1776-07-04", tz="UTC"), | ||||
|         ], | ||||
|     ) | ||||
|     @pytest.mark.parametrize( | ||||
|         "other", | ||||
|         [ | ||||
|             1, | ||||
|             np.int64(1), | ||||
|             np.array([1, 2], dtype=np.int32), | ||||
|             np.array([3, 4], dtype=np.uint64), | ||||
|         ], | ||||
|     ) | ||||
|     def test_add_int_with_freq(self, ts, other): | ||||
|         msg = "Addition/subtraction of integers and integer-arrays" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             ts + other | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             other + ts | ||||
|  | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             ts - other | ||||
|  | ||||
|         msg = "unsupported operand type" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             other - ts | ||||
|  | ||||
|     @pytest.mark.parametrize("shape", [(6,), (2, 3)]) | ||||
|     def test_addsub_m8ndarray(self, shape): | ||||
|         # GH#33296 | ||||
|         ts = Timestamp("2020-04-04 15:45").as_unit("ns") | ||||
|         other = np.arange(6).astype("m8[h]").reshape(shape) | ||||
|  | ||||
|         result = ts + other | ||||
|  | ||||
|         ex_stamps = [ts + Timedelta(hours=n) for n in range(6)] | ||||
|         expected = np.array([x.asm8 for x in ex_stamps], dtype="M8[ns]").reshape(shape) | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|         result = other + ts | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|         result = ts - other | ||||
|         ex_stamps = [ts - Timedelta(hours=n) for n in range(6)] | ||||
|         expected = np.array([x.asm8 for x in ex_stamps], dtype="M8[ns]").reshape(shape) | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|         msg = r"unsupported operand type\(s\) for -: 'numpy.ndarray' and 'Timestamp'" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             other - ts | ||||
|  | ||||
|     @pytest.mark.parametrize("shape", [(6,), (2, 3)]) | ||||
|     def test_addsub_m8ndarray_tzaware(self, shape): | ||||
|         # GH#33296 | ||||
|         ts = Timestamp("2020-04-04 15:45", tz="US/Pacific") | ||||
|  | ||||
|         other = np.arange(6).astype("m8[h]").reshape(shape) | ||||
|  | ||||
|         result = ts + other | ||||
|  | ||||
|         ex_stamps = [ts + Timedelta(hours=n) for n in range(6)] | ||||
|         expected = np.array(ex_stamps).reshape(shape) | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|         result = other + ts | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|         result = ts - other | ||||
|         ex_stamps = [ts - Timedelta(hours=n) for n in range(6)] | ||||
|         expected = np.array(ex_stamps).reshape(shape) | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|         msg = r"unsupported operand type\(s\) for -: 'numpy.ndarray' and 'Timestamp'" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             other - ts | ||||
|  | ||||
|     def test_subtract_different_utc_objects(self, utc_fixture, utc_fixture2): | ||||
|         # GH 32619 | ||||
|         dt = datetime(2021, 1, 1) | ||||
|         ts1 = Timestamp(dt, tz=utc_fixture) | ||||
|         ts2 = Timestamp(dt, tz=utc_fixture2) | ||||
|         result = ts1 - ts2 | ||||
|         expected = Timedelta(0) | ||||
|         assert result == expected | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "tz", | ||||
|         [ | ||||
|             pytz.timezone("US/Eastern"), | ||||
|             gettz("US/Eastern"), | ||||
|             "US/Eastern", | ||||
|             "dateutil/US/Eastern", | ||||
|         ], | ||||
|     ) | ||||
|     def test_timestamp_add_timedelta_push_over_dst_boundary(self, tz): | ||||
|         # GH#1389 | ||||
|  | ||||
|         # 4 hours before DST transition | ||||
|         stamp = Timestamp("3/10/2012 22:00", tz=tz) | ||||
|  | ||||
|         result = stamp + timedelta(hours=6) | ||||
|  | ||||
|         # spring forward, + "7" hours | ||||
|         expected = Timestamp("3/11/2012 05:00", tz=tz) | ||||
|  | ||||
|         assert result == expected | ||||
|  | ||||
|  | ||||
| class SubDatetime(datetime): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize( | ||||
|     "lh,rh", | ||||
|     [ | ||||
|         (SubDatetime(2000, 1, 1), Timedelta(hours=1)), | ||||
|         (Timedelta(hours=1), SubDatetime(2000, 1, 1)), | ||||
|     ], | ||||
| ) | ||||
| def test_dt_subclass_add_timedelta(lh, rh): | ||||
|     # GH#25851 | ||||
|     # ensure that subclassed datetime works for | ||||
|     # Timedelta operations | ||||
|     result = lh + rh | ||||
|     expected = SubDatetime(2000, 1, 1, 1) | ||||
|     assert result == expected | ||||
| @ -0,0 +1,313 @@ | ||||
| from datetime import ( | ||||
|     datetime, | ||||
|     timedelta, | ||||
| ) | ||||
| import operator | ||||
|  | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas import Timestamp | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimestampComparison: | ||||
|     def test_compare_non_nano_dt64(self): | ||||
|         # don't raise when converting dt64 to Timestamp in __richcmp__ | ||||
|         dt = np.datetime64("1066-10-14") | ||||
|         ts = Timestamp(dt) | ||||
|  | ||||
|         assert dt == ts | ||||
|  | ||||
|     def test_comparison_dt64_ndarray(self): | ||||
|         ts = Timestamp("2021-01-01") | ||||
|         ts2 = Timestamp("2019-04-05") | ||||
|         arr = np.array([[ts.asm8, ts2.asm8]], dtype="M8[ns]") | ||||
|  | ||||
|         result = ts == arr | ||||
|         expected = np.array([[True, False]], dtype=bool) | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|         result = arr == ts | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|         result = ts != arr | ||||
|         tm.assert_numpy_array_equal(result, ~expected) | ||||
|  | ||||
|         result = arr != ts | ||||
|         tm.assert_numpy_array_equal(result, ~expected) | ||||
|  | ||||
|         result = ts2 < arr | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|         result = arr < ts2 | ||||
|         tm.assert_numpy_array_equal(result, np.array([[False, False]], dtype=bool)) | ||||
|  | ||||
|         result = ts2 <= arr | ||||
|         tm.assert_numpy_array_equal(result, np.array([[True, True]], dtype=bool)) | ||||
|  | ||||
|         result = arr <= ts2 | ||||
|         tm.assert_numpy_array_equal(result, ~expected) | ||||
|  | ||||
|         result = ts >= arr | ||||
|         tm.assert_numpy_array_equal(result, np.array([[True, True]], dtype=bool)) | ||||
|  | ||||
|         result = arr >= ts | ||||
|         tm.assert_numpy_array_equal(result, np.array([[True, False]], dtype=bool)) | ||||
|  | ||||
|     @pytest.mark.parametrize("reverse", [True, False]) | ||||
|     def test_comparison_dt64_ndarray_tzaware(self, reverse, comparison_op): | ||||
|         ts = Timestamp("2021-01-01 00:00:00.00000", tz="UTC") | ||||
|         arr = np.array([ts.asm8, ts.asm8], dtype="M8[ns]") | ||||
|  | ||||
|         left, right = ts, arr | ||||
|         if reverse: | ||||
|             left, right = arr, ts | ||||
|  | ||||
|         if comparison_op is operator.eq: | ||||
|             expected = np.array([False, False], dtype=bool) | ||||
|             result = comparison_op(left, right) | ||||
|             tm.assert_numpy_array_equal(result, expected) | ||||
|         elif comparison_op is operator.ne: | ||||
|             expected = np.array([True, True], dtype=bool) | ||||
|             result = comparison_op(left, right) | ||||
|             tm.assert_numpy_array_equal(result, expected) | ||||
|         else: | ||||
|             msg = "Cannot compare tz-naive and tz-aware timestamps" | ||||
|             with pytest.raises(TypeError, match=msg): | ||||
|                 comparison_op(left, right) | ||||
|  | ||||
|     def test_comparison_object_array(self): | ||||
|         # GH#15183 | ||||
|         ts = Timestamp("2011-01-03 00:00:00-0500", tz="US/Eastern") | ||||
|         other = Timestamp("2011-01-01 00:00:00-0500", tz="US/Eastern") | ||||
|         naive = Timestamp("2011-01-01 00:00:00") | ||||
|  | ||||
|         arr = np.array([other, ts], dtype=object) | ||||
|         res = arr == ts | ||||
|         expected = np.array([False, True], dtype=bool) | ||||
|         assert (res == expected).all() | ||||
|  | ||||
|         # 2D case | ||||
|         arr = np.array([[other, ts], [ts, other]], dtype=object) | ||||
|         res = arr != ts | ||||
|         expected = np.array([[True, False], [False, True]], dtype=bool) | ||||
|         assert res.shape == expected.shape | ||||
|         assert (res == expected).all() | ||||
|  | ||||
|         # tzaware mismatch | ||||
|         arr = np.array([naive], dtype=object) | ||||
|         msg = "Cannot compare tz-naive and tz-aware timestamps" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             arr < ts | ||||
|  | ||||
|     def test_comparison(self): | ||||
|         # 5-18-2012 00:00:00.000 | ||||
|         stamp = 1337299200000000000 | ||||
|  | ||||
|         val = Timestamp(stamp) | ||||
|  | ||||
|         assert val == val | ||||
|         assert not val != val | ||||
|         assert not val < val | ||||
|         assert val <= val | ||||
|         assert not val > val | ||||
|         assert val >= val | ||||
|  | ||||
|         other = datetime(2012, 5, 18) | ||||
|         assert val == other | ||||
|         assert not val != other | ||||
|         assert not val < other | ||||
|         assert val <= other | ||||
|         assert not val > other | ||||
|         assert val >= other | ||||
|  | ||||
|         other = Timestamp(stamp + 100) | ||||
|  | ||||
|         assert val != other | ||||
|         assert val != other | ||||
|         assert val < other | ||||
|         assert val <= other | ||||
|         assert other > val | ||||
|         assert other >= val | ||||
|  | ||||
|     def test_compare_invalid(self): | ||||
|         # GH#8058 | ||||
|         val = Timestamp("20130101 12:01:02") | ||||
|         assert not val == "foo" | ||||
|         assert not val == 10.0 | ||||
|         assert not val == 1 | ||||
|         assert not val == [] | ||||
|         assert not val == {"foo": 1} | ||||
|         assert not val == np.float64(1) | ||||
|         assert not val == np.int64(1) | ||||
|  | ||||
|         assert val != "foo" | ||||
|         assert val != 10.0 | ||||
|         assert val != 1 | ||||
|         assert val != [] | ||||
|         assert val != {"foo": 1} | ||||
|         assert val != np.float64(1) | ||||
|         assert val != np.int64(1) | ||||
|  | ||||
|     @pytest.mark.parametrize("tz", [None, "US/Pacific"]) | ||||
|     def test_compare_date(self, tz): | ||||
|         # GH#36131 comparing Timestamp with date object is deprecated | ||||
|         ts = Timestamp("2021-01-01 00:00:00.00000", tz=tz) | ||||
|         dt = ts.to_pydatetime().date() | ||||
|         # in 2.0 we disallow comparing pydate objects with Timestamps, | ||||
|         #  following the stdlib datetime behavior. | ||||
|  | ||||
|         msg = "Cannot compare Timestamp with datetime.date" | ||||
|         for left, right in [(ts, dt), (dt, ts)]: | ||||
|             assert not left == right | ||||
|             assert left != right | ||||
|  | ||||
|             with pytest.raises(TypeError, match=msg): | ||||
|                 left < right | ||||
|             with pytest.raises(TypeError, match=msg): | ||||
|                 left <= right | ||||
|             with pytest.raises(TypeError, match=msg): | ||||
|                 left > right | ||||
|             with pytest.raises(TypeError, match=msg): | ||||
|                 left >= right | ||||
|  | ||||
|     def test_cant_compare_tz_naive_w_aware(self, utc_fixture): | ||||
|         # see GH#1404 | ||||
|         a = Timestamp("3/12/2012") | ||||
|         b = Timestamp("3/12/2012", tz=utc_fixture) | ||||
|  | ||||
|         msg = "Cannot compare tz-naive and tz-aware timestamps" | ||||
|         assert not a == b | ||||
|         assert a != b | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             a < b | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             a <= b | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             a > b | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             a >= b | ||||
|  | ||||
|         assert not b == a | ||||
|         assert b != a | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             b < a | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             b <= a | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             b > a | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             b >= a | ||||
|  | ||||
|         assert not a == b.to_pydatetime() | ||||
|         assert not a.to_pydatetime() == b | ||||
|  | ||||
|     def test_timestamp_compare_scalars(self): | ||||
|         # case where ndim == 0 | ||||
|         lhs = np.datetime64(datetime(2013, 12, 6)) | ||||
|         rhs = Timestamp("now") | ||||
|         nat = Timestamp("nat") | ||||
|  | ||||
|         ops = {"gt": "lt", "lt": "gt", "ge": "le", "le": "ge", "eq": "eq", "ne": "ne"} | ||||
|  | ||||
|         for left, right in ops.items(): | ||||
|             left_f = getattr(operator, left) | ||||
|             right_f = getattr(operator, right) | ||||
|             expected = left_f(lhs, rhs) | ||||
|  | ||||
|             result = right_f(rhs, lhs) | ||||
|             assert result == expected | ||||
|  | ||||
|             expected = left_f(rhs, nat) | ||||
|             result = right_f(nat, rhs) | ||||
|             assert result == expected | ||||
|  | ||||
|     def test_timestamp_compare_with_early_datetime(self): | ||||
|         # e.g. datetime.min | ||||
|         stamp = Timestamp("2012-01-01") | ||||
|  | ||||
|         assert not stamp == datetime.min | ||||
|         assert not stamp == datetime(1600, 1, 1) | ||||
|         assert not stamp == datetime(2700, 1, 1) | ||||
|         assert stamp != datetime.min | ||||
|         assert stamp != datetime(1600, 1, 1) | ||||
|         assert stamp != datetime(2700, 1, 1) | ||||
|         assert stamp > datetime(1600, 1, 1) | ||||
|         assert stamp >= datetime(1600, 1, 1) | ||||
|         assert stamp < datetime(2700, 1, 1) | ||||
|         assert stamp <= datetime(2700, 1, 1) | ||||
|  | ||||
|         other = Timestamp.min.to_pydatetime(warn=False) | ||||
|         assert other - timedelta(microseconds=1) < Timestamp.min | ||||
|  | ||||
|     def test_timestamp_compare_oob_dt64(self): | ||||
|         us = np.timedelta64(1, "us") | ||||
|         other = np.datetime64(Timestamp.min).astype("M8[us]") | ||||
|  | ||||
|         # This may change if the implementation bound is dropped to match | ||||
|         #  DatetimeArray/DatetimeIndex GH#24124 | ||||
|         assert Timestamp.min > other | ||||
|         # Note: numpy gets the reversed comparison wrong | ||||
|  | ||||
|         other = np.datetime64(Timestamp.max).astype("M8[us]") | ||||
|         assert Timestamp.max > other  # not actually OOB | ||||
|         assert other < Timestamp.max | ||||
|  | ||||
|         assert Timestamp.max < other + us | ||||
|         # Note: numpy gets the reversed comparison wrong | ||||
|  | ||||
|         # GH-42794 | ||||
|         other = datetime(9999, 9, 9) | ||||
|         assert Timestamp.min < other | ||||
|         assert other > Timestamp.min | ||||
|         assert Timestamp.max < other | ||||
|         assert other > Timestamp.max | ||||
|  | ||||
|         other = datetime(1, 1, 1) | ||||
|         assert Timestamp.max > other | ||||
|         assert other < Timestamp.max | ||||
|         assert Timestamp.min > other | ||||
|         assert other < Timestamp.min | ||||
|  | ||||
|     def test_compare_zerodim_array(self, fixed_now_ts): | ||||
|         # GH#26916 | ||||
|         ts = fixed_now_ts | ||||
|         dt64 = np.datetime64("2016-01-01", "ns") | ||||
|         arr = np.array(dt64) | ||||
|         assert arr.ndim == 0 | ||||
|  | ||||
|         result = arr < ts | ||||
|         assert result is np.bool_(True) | ||||
|         result = arr > ts | ||||
|         assert result is np.bool_(False) | ||||
|  | ||||
|  | ||||
| def test_rich_comparison_with_unsupported_type(): | ||||
|     # Comparisons with unsupported objects should return NotImplemented | ||||
|     # (it previously raised TypeError, see #24011) | ||||
|  | ||||
|     class Inf: | ||||
|         def __lt__(self, o): | ||||
|             return False | ||||
|  | ||||
|         def __le__(self, o): | ||||
|             return isinstance(o, Inf) | ||||
|  | ||||
|         def __gt__(self, o): | ||||
|             return not isinstance(o, Inf) | ||||
|  | ||||
|         def __ge__(self, o): | ||||
|             return True | ||||
|  | ||||
|         def __eq__(self, other) -> bool: | ||||
|             return isinstance(other, Inf) | ||||
|  | ||||
|     inf = Inf() | ||||
|     timestamp = Timestamp("2018-11-30") | ||||
|  | ||||
|     for left, right in [(inf, timestamp), (timestamp, inf)]: | ||||
|         assert left > right or left < right | ||||
|         assert left >= right or left <= right | ||||
|         assert not left == right  # pylint: disable=unneeded-not | ||||
|         assert left != right | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -0,0 +1,201 @@ | ||||
| from datetime import datetime | ||||
| import pprint | ||||
|  | ||||
| import dateutil.tz | ||||
| import pytest | ||||
| import pytz  # a test below uses pytz but only inside a `eval` call | ||||
|  | ||||
| from pandas import Timestamp | ||||
|  | ||||
| ts_no_ns = Timestamp( | ||||
|     year=2019, | ||||
|     month=5, | ||||
|     day=18, | ||||
|     hour=15, | ||||
|     minute=17, | ||||
|     second=8, | ||||
|     microsecond=132263, | ||||
| ) | ||||
| ts_no_ns_year1 = Timestamp( | ||||
|     year=1, | ||||
|     month=5, | ||||
|     day=18, | ||||
|     hour=15, | ||||
|     minute=17, | ||||
|     second=8, | ||||
|     microsecond=132263, | ||||
| ) | ||||
| ts_ns = Timestamp( | ||||
|     year=2019, | ||||
|     month=5, | ||||
|     day=18, | ||||
|     hour=15, | ||||
|     minute=17, | ||||
|     second=8, | ||||
|     microsecond=132263, | ||||
|     nanosecond=123, | ||||
| ) | ||||
| ts_ns_tz = Timestamp( | ||||
|     year=2019, | ||||
|     month=5, | ||||
|     day=18, | ||||
|     hour=15, | ||||
|     minute=17, | ||||
|     second=8, | ||||
|     microsecond=132263, | ||||
|     nanosecond=123, | ||||
|     tz="UTC", | ||||
| ) | ||||
| ts_no_us = Timestamp( | ||||
|     year=2019, | ||||
|     month=5, | ||||
|     day=18, | ||||
|     hour=15, | ||||
|     minute=17, | ||||
|     second=8, | ||||
|     microsecond=0, | ||||
|     nanosecond=123, | ||||
| ) | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize( | ||||
|     "ts, timespec, expected_iso", | ||||
|     [ | ||||
|         (ts_no_ns, "auto", "2019-05-18T15:17:08.132263"), | ||||
|         (ts_no_ns, "seconds", "2019-05-18T15:17:08"), | ||||
|         (ts_no_ns, "nanoseconds", "2019-05-18T15:17:08.132263000"), | ||||
|         (ts_no_ns_year1, "seconds", "0001-05-18T15:17:08"), | ||||
|         (ts_no_ns_year1, "nanoseconds", "0001-05-18T15:17:08.132263000"), | ||||
|         (ts_ns, "auto", "2019-05-18T15:17:08.132263123"), | ||||
|         (ts_ns, "hours", "2019-05-18T15"), | ||||
|         (ts_ns, "minutes", "2019-05-18T15:17"), | ||||
|         (ts_ns, "seconds", "2019-05-18T15:17:08"), | ||||
|         (ts_ns, "milliseconds", "2019-05-18T15:17:08.132"), | ||||
|         (ts_ns, "microseconds", "2019-05-18T15:17:08.132263"), | ||||
|         (ts_ns, "nanoseconds", "2019-05-18T15:17:08.132263123"), | ||||
|         (ts_ns_tz, "auto", "2019-05-18T15:17:08.132263123+00:00"), | ||||
|         (ts_ns_tz, "hours", "2019-05-18T15+00:00"), | ||||
|         (ts_ns_tz, "minutes", "2019-05-18T15:17+00:00"), | ||||
|         (ts_ns_tz, "seconds", "2019-05-18T15:17:08+00:00"), | ||||
|         (ts_ns_tz, "milliseconds", "2019-05-18T15:17:08.132+00:00"), | ||||
|         (ts_ns_tz, "microseconds", "2019-05-18T15:17:08.132263+00:00"), | ||||
|         (ts_ns_tz, "nanoseconds", "2019-05-18T15:17:08.132263123+00:00"), | ||||
|         (ts_no_us, "auto", "2019-05-18T15:17:08.000000123"), | ||||
|     ], | ||||
| ) | ||||
| def test_isoformat(ts, timespec, expected_iso): | ||||
|     assert ts.isoformat(timespec=timespec) == expected_iso | ||||
|  | ||||
|  | ||||
| class TestTimestampRendering: | ||||
|     timezones = ["UTC", "Asia/Tokyo", "US/Eastern", "dateutil/America/Los_Angeles"] | ||||
|  | ||||
|     @pytest.mark.parametrize("tz", timezones) | ||||
|     @pytest.mark.parametrize("freq", ["D", "M", "S", "N"]) | ||||
|     @pytest.mark.parametrize( | ||||
|         "date", ["2014-03-07", "2014-01-01 09:00", "2014-01-01 00:00:00.000000001"] | ||||
|     ) | ||||
|     def test_repr(self, date, freq, tz): | ||||
|         # avoid to match with timezone name | ||||
|         freq_repr = f"'{freq}'" | ||||
|         if tz.startswith("dateutil"): | ||||
|             tz_repr = tz.replace("dateutil", "") | ||||
|         else: | ||||
|             tz_repr = tz | ||||
|  | ||||
|         date_only = Timestamp(date) | ||||
|         assert date in repr(date_only) | ||||
|         assert tz_repr not in repr(date_only) | ||||
|         assert freq_repr not in repr(date_only) | ||||
|         assert date_only == eval(repr(date_only)) | ||||
|  | ||||
|         date_tz = Timestamp(date, tz=tz) | ||||
|         assert date in repr(date_tz) | ||||
|         assert tz_repr in repr(date_tz) | ||||
|         assert freq_repr not in repr(date_tz) | ||||
|         assert date_tz == eval(repr(date_tz)) | ||||
|  | ||||
|     def test_repr_utcoffset(self): | ||||
|         # This can cause the tz field to be populated, but it's redundant to | ||||
|         # include this information in the date-string. | ||||
|         date_with_utc_offset = Timestamp("2014-03-13 00:00:00-0400", tz=None) | ||||
|         assert "2014-03-13 00:00:00-0400" in repr(date_with_utc_offset) | ||||
|         assert "tzoffset" not in repr(date_with_utc_offset) | ||||
|         assert "UTC-04:00" in repr(date_with_utc_offset) | ||||
|         expr = repr(date_with_utc_offset) | ||||
|         assert date_with_utc_offset == eval(expr) | ||||
|  | ||||
|     def test_timestamp_repr_pre1900(self): | ||||
|         # pre-1900 | ||||
|         stamp = Timestamp("1850-01-01", tz="US/Eastern") | ||||
|         repr(stamp) | ||||
|  | ||||
|         iso8601 = "1850-01-01 01:23:45.012345" | ||||
|         stamp = Timestamp(iso8601, tz="US/Eastern") | ||||
|         result = repr(stamp) | ||||
|         assert iso8601 in result | ||||
|  | ||||
|     def test_pprint(self): | ||||
|         # GH#12622 | ||||
|         nested_obj = {"foo": 1, "bar": [{"w": {"a": Timestamp("2011-01-01")}}] * 10} | ||||
|         result = pprint.pformat(nested_obj, width=50) | ||||
|         expected = r"""{'bar': [{'w': {'a': Timestamp('2011-01-01 00:00:00')}}, | ||||
|          {'w': {'a': Timestamp('2011-01-01 00:00:00')}}, | ||||
|          {'w': {'a': Timestamp('2011-01-01 00:00:00')}}, | ||||
|          {'w': {'a': Timestamp('2011-01-01 00:00:00')}}, | ||||
|          {'w': {'a': Timestamp('2011-01-01 00:00:00')}}, | ||||
|          {'w': {'a': Timestamp('2011-01-01 00:00:00')}}, | ||||
|          {'w': {'a': Timestamp('2011-01-01 00:00:00')}}, | ||||
|          {'w': {'a': Timestamp('2011-01-01 00:00:00')}}, | ||||
|          {'w': {'a': Timestamp('2011-01-01 00:00:00')}}, | ||||
|          {'w': {'a': Timestamp('2011-01-01 00:00:00')}}], | ||||
|  'foo': 1}""" | ||||
|         assert result == expected | ||||
|  | ||||
|     def test_to_timestamp_repr_is_code(self): | ||||
|         zs = [ | ||||
|             Timestamp("99-04-17 00:00:00", tz="UTC"), | ||||
|             Timestamp("2001-04-17 00:00:00", tz="UTC"), | ||||
|             Timestamp("2001-04-17 00:00:00", tz="America/Los_Angeles"), | ||||
|             Timestamp("2001-04-17 00:00:00", tz=None), | ||||
|         ] | ||||
|         for z in zs: | ||||
|             assert eval(repr(z)) == z | ||||
|  | ||||
|     def test_repr_matches_pydatetime_no_tz(self): | ||||
|         dt_date = datetime(2013, 1, 2) | ||||
|         assert str(dt_date) == str(Timestamp(dt_date)) | ||||
|  | ||||
|         dt_datetime = datetime(2013, 1, 2, 12, 1, 3) | ||||
|         assert str(dt_datetime) == str(Timestamp(dt_datetime)) | ||||
|  | ||||
|         dt_datetime_us = datetime(2013, 1, 2, 12, 1, 3, 45) | ||||
|         assert str(dt_datetime_us) == str(Timestamp(dt_datetime_us)) | ||||
|  | ||||
|         ts_nanos_only = Timestamp(200) | ||||
|         assert str(ts_nanos_only) == "1970-01-01 00:00:00.000000200" | ||||
|  | ||||
|         ts_nanos_micros = Timestamp(1200) | ||||
|         assert str(ts_nanos_micros) == "1970-01-01 00:00:00.000001200" | ||||
|  | ||||
|     def test_repr_matches_pydatetime_tz_pytz(self): | ||||
|         dt_date = datetime(2013, 1, 2, tzinfo=pytz.utc) | ||||
|         assert str(dt_date) == str(Timestamp(dt_date)) | ||||
|  | ||||
|         dt_datetime = datetime(2013, 1, 2, 12, 1, 3, tzinfo=pytz.utc) | ||||
|         assert str(dt_datetime) == str(Timestamp(dt_datetime)) | ||||
|  | ||||
|         dt_datetime_us = datetime(2013, 1, 2, 12, 1, 3, 45, tzinfo=pytz.utc) | ||||
|         assert str(dt_datetime_us) == str(Timestamp(dt_datetime_us)) | ||||
|  | ||||
|     def test_repr_matches_pydatetime_tz_dateutil(self): | ||||
|         utc = dateutil.tz.tzutc() | ||||
|  | ||||
|         dt_date = datetime(2013, 1, 2, tzinfo=utc) | ||||
|         assert str(dt_date) == str(Timestamp(dt_date)) | ||||
|  | ||||
|         dt_datetime = datetime(2013, 1, 2, 12, 1, 3, tzinfo=utc) | ||||
|         assert str(dt_datetime) == str(Timestamp(dt_datetime)) | ||||
|  | ||||
|         dt_datetime_us = datetime(2013, 1, 2, 12, 1, 3, 45, tzinfo=utc) | ||||
|         assert str(dt_datetime_us) == str(Timestamp(dt_datetime_us)) | ||||
| @ -0,0 +1,928 @@ | ||||
| """ test the scalar Timestamp """ | ||||
|  | ||||
| import calendar | ||||
| from datetime import ( | ||||
|     datetime, | ||||
|     timedelta, | ||||
|     timezone, | ||||
| ) | ||||
| import locale | ||||
| import time | ||||
| import unicodedata | ||||
|  | ||||
| from dateutil.tz import ( | ||||
|     tzlocal, | ||||
|     tzutc, | ||||
| ) | ||||
| from hypothesis import ( | ||||
|     given, | ||||
|     strategies as st, | ||||
| ) | ||||
| import numpy as np | ||||
| import pytest | ||||
| import pytz | ||||
| from pytz import utc | ||||
|  | ||||
| from pandas._libs.tslibs.dtypes import NpyDatetimeUnit | ||||
| from pandas._libs.tslibs.timezones import ( | ||||
|     dateutil_gettz as gettz, | ||||
|     get_timezone, | ||||
|     maybe_get_tz, | ||||
|     tz_compare, | ||||
| ) | ||||
| from pandas.compat import IS64 | ||||
|  | ||||
| from pandas import ( | ||||
|     NaT, | ||||
|     Timedelta, | ||||
|     Timestamp, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
| from pandas.tseries import offsets | ||||
| from pandas.tseries.frequencies import to_offset | ||||
|  | ||||
|  | ||||
| class TestTimestampProperties: | ||||
|     def test_properties_business(self): | ||||
|         freq = to_offset("B") | ||||
|  | ||||
|         ts = Timestamp("2017-10-01") | ||||
|         assert ts.dayofweek == 6 | ||||
|         assert ts.day_of_week == 6 | ||||
|         assert ts.is_month_start  # not a weekday | ||||
|         assert not freq.is_month_start(ts) | ||||
|         assert freq.is_month_start(ts + Timedelta(days=1)) | ||||
|         assert not freq.is_quarter_start(ts) | ||||
|         assert freq.is_quarter_start(ts + Timedelta(days=1)) | ||||
|  | ||||
|         ts = Timestamp("2017-09-30") | ||||
|         assert ts.dayofweek == 5 | ||||
|         assert ts.day_of_week == 5 | ||||
|         assert ts.is_month_end | ||||
|         assert not freq.is_month_end(ts) | ||||
|         assert freq.is_month_end(ts - Timedelta(days=1)) | ||||
|         assert ts.is_quarter_end | ||||
|         assert not freq.is_quarter_end(ts) | ||||
|         assert freq.is_quarter_end(ts - Timedelta(days=1)) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "attr, expected", | ||||
|         [ | ||||
|             ["year", 2014], | ||||
|             ["month", 12], | ||||
|             ["day", 31], | ||||
|             ["hour", 23], | ||||
|             ["minute", 59], | ||||
|             ["second", 0], | ||||
|             ["microsecond", 0], | ||||
|             ["nanosecond", 0], | ||||
|             ["dayofweek", 2], | ||||
|             ["day_of_week", 2], | ||||
|             ["quarter", 4], | ||||
|             ["dayofyear", 365], | ||||
|             ["day_of_year", 365], | ||||
|             ["week", 1], | ||||
|             ["daysinmonth", 31], | ||||
|         ], | ||||
|     ) | ||||
|     @pytest.mark.parametrize("tz", [None, "US/Eastern"]) | ||||
|     def test_fields(self, attr, expected, tz): | ||||
|         # GH 10050 | ||||
|         # GH 13303 | ||||
|         ts = Timestamp("2014-12-31 23:59:00", tz=tz) | ||||
|         result = getattr(ts, attr) | ||||
|         # that we are int like | ||||
|         assert isinstance(result, int) | ||||
|         assert result == expected | ||||
|  | ||||
|     @pytest.mark.parametrize("tz", [None, "US/Eastern"]) | ||||
|     def test_millisecond_raises(self, tz): | ||||
|         ts = Timestamp("2014-12-31 23:59:00", tz=tz) | ||||
|         msg = "'Timestamp' object has no attribute 'millisecond'" | ||||
|         with pytest.raises(AttributeError, match=msg): | ||||
|             ts.millisecond | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "start", ["is_month_start", "is_quarter_start", "is_year_start"] | ||||
|     ) | ||||
|     @pytest.mark.parametrize("tz", [None, "US/Eastern"]) | ||||
|     def test_is_start(self, start, tz): | ||||
|         ts = Timestamp("2014-01-01 00:00:00", tz=tz) | ||||
|         assert getattr(ts, start) | ||||
|  | ||||
|     @pytest.mark.parametrize("end", ["is_month_end", "is_year_end", "is_quarter_end"]) | ||||
|     @pytest.mark.parametrize("tz", [None, "US/Eastern"]) | ||||
|     def test_is_end(self, end, tz): | ||||
|         ts = Timestamp("2014-12-31 23:59:59", tz=tz) | ||||
|         assert getattr(ts, end) | ||||
|  | ||||
|     # GH 12806 | ||||
|     @pytest.mark.parametrize( | ||||
|         "data", | ||||
|         [Timestamp("2017-08-28 23:00:00"), Timestamp("2017-08-28 23:00:00", tz="EST")], | ||||
|     ) | ||||
|     # error: Unsupported operand types for + ("List[None]" and "List[str]") | ||||
|     @pytest.mark.parametrize( | ||||
|         "time_locale", [None] + tm.get_locales()  # type: ignore[operator] | ||||
|     ) | ||||
|     def test_names(self, data, time_locale): | ||||
|         # GH 17354 | ||||
|         # Test .day_name(), .month_name | ||||
|         if time_locale is None: | ||||
|             expected_day = "Monday" | ||||
|             expected_month = "August" | ||||
|         else: | ||||
|             with tm.set_locale(time_locale, locale.LC_TIME): | ||||
|                 expected_day = calendar.day_name[0].capitalize() | ||||
|                 expected_month = calendar.month_name[8].capitalize() | ||||
|  | ||||
|         result_day = data.day_name(time_locale) | ||||
|         result_month = data.month_name(time_locale) | ||||
|  | ||||
|         # Work around https://github.com/pandas-dev/pandas/issues/22342 | ||||
|         # different normalizations | ||||
|         expected_day = unicodedata.normalize("NFD", expected_day) | ||||
|         expected_month = unicodedata.normalize("NFD", expected_month) | ||||
|  | ||||
|         result_day = unicodedata.normalize("NFD", result_day) | ||||
|         result_month = unicodedata.normalize("NFD", result_month) | ||||
|  | ||||
|         assert result_day == expected_day | ||||
|         assert result_month == expected_month | ||||
|  | ||||
|         # Test NaT | ||||
|         nan_ts = Timestamp(NaT) | ||||
|         assert np.isnan(nan_ts.day_name(time_locale)) | ||||
|         assert np.isnan(nan_ts.month_name(time_locale)) | ||||
|  | ||||
|     def test_is_leap_year(self, tz_naive_fixture): | ||||
|         tz = tz_naive_fixture | ||||
|         if not IS64 and tz == tzlocal(): | ||||
|             # https://github.com/dateutil/dateutil/issues/197 | ||||
|             pytest.skip( | ||||
|                 "tzlocal() on a 32 bit platform causes internal overflow errors" | ||||
|             ) | ||||
|         # GH 13727 | ||||
|         dt = Timestamp("2000-01-01 00:00:00", tz=tz) | ||||
|         assert dt.is_leap_year | ||||
|         assert isinstance(dt.is_leap_year, bool) | ||||
|  | ||||
|         dt = Timestamp("1999-01-01 00:00:00", tz=tz) | ||||
|         assert not dt.is_leap_year | ||||
|  | ||||
|         dt = Timestamp("2004-01-01 00:00:00", tz=tz) | ||||
|         assert dt.is_leap_year | ||||
|  | ||||
|         dt = Timestamp("2100-01-01 00:00:00", tz=tz) | ||||
|         assert not dt.is_leap_year | ||||
|  | ||||
|     def test_woy_boundary(self): | ||||
|         # make sure weeks at year boundaries are correct | ||||
|         d = datetime(2013, 12, 31) | ||||
|         result = Timestamp(d).week | ||||
|         expected = 1  # ISO standard | ||||
|         assert result == expected | ||||
|  | ||||
|         d = datetime(2008, 12, 28) | ||||
|         result = Timestamp(d).week | ||||
|         expected = 52  # ISO standard | ||||
|         assert result == expected | ||||
|  | ||||
|         d = datetime(2009, 12, 31) | ||||
|         result = Timestamp(d).week | ||||
|         expected = 53  # ISO standard | ||||
|         assert result == expected | ||||
|  | ||||
|         d = datetime(2010, 1, 1) | ||||
|         result = Timestamp(d).week | ||||
|         expected = 53  # ISO standard | ||||
|         assert result == expected | ||||
|  | ||||
|         d = datetime(2010, 1, 3) | ||||
|         result = Timestamp(d).week | ||||
|         expected = 53  # ISO standard | ||||
|         assert result == expected | ||||
|  | ||||
|         result = np.array( | ||||
|             [ | ||||
|                 Timestamp(datetime(*args)).week | ||||
|                 for args in [(2000, 1, 1), (2000, 1, 2), (2005, 1, 1), (2005, 1, 2)] | ||||
|             ] | ||||
|         ) | ||||
|         assert (result == [52, 52, 53, 53]).all() | ||||
|  | ||||
|     def test_resolution(self): | ||||
|         # GH#21336, GH#21365 | ||||
|         dt = Timestamp("2100-01-01 00:00:00.000000000") | ||||
|         assert dt.resolution == Timedelta(nanoseconds=1) | ||||
|  | ||||
|         # Check that the attribute is available on the class, mirroring | ||||
|         #  the stdlib datetime behavior | ||||
|         assert Timestamp.resolution == Timedelta(nanoseconds=1) | ||||
|  | ||||
|         assert dt.as_unit("us").resolution == Timedelta(microseconds=1) | ||||
|         assert dt.as_unit("ms").resolution == Timedelta(milliseconds=1) | ||||
|         assert dt.as_unit("s").resolution == Timedelta(seconds=1) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "date_string, expected", | ||||
|         [ | ||||
|             ("0000-2-29", 1), | ||||
|             ("0000-3-1", 2), | ||||
|             ("1582-10-14", 3), | ||||
|             ("-0040-1-1", 4), | ||||
|             ("2023-06-18", 6), | ||||
|         ], | ||||
|     ) | ||||
|     def test_dow_historic(self, date_string, expected): | ||||
|         # GH 53738 | ||||
|         ts = Timestamp(date_string) | ||||
|         dow = ts.weekday() | ||||
|         assert dow == expected | ||||
|  | ||||
|     @given( | ||||
|         ts=st.datetimes(), | ||||
|         sign=st.sampled_from(["-", ""]), | ||||
|     ) | ||||
|     def test_dow_parametric(self, ts, sign): | ||||
|         # GH 53738 | ||||
|         ts = ( | ||||
|             f"{sign}{str(ts.year).zfill(4)}" | ||||
|             f"-{str(ts.month).zfill(2)}" | ||||
|             f"-{str(ts.day).zfill(2)}" | ||||
|         ) | ||||
|         result = Timestamp(ts).weekday() | ||||
|         expected = ( | ||||
|             (np.datetime64(ts) - np.datetime64("1970-01-01")).astype("int64") - 4 | ||||
|         ) % 7 | ||||
|         assert result == expected | ||||
|  | ||||
|  | ||||
| class TestTimestamp: | ||||
|     @pytest.mark.parametrize("tz", [None, pytz.timezone("US/Pacific")]) | ||||
|     def test_disallow_setting_tz(self, tz): | ||||
|         # GH#3746 | ||||
|         ts = Timestamp("2010") | ||||
|         msg = "Cannot directly set timezone" | ||||
|         with pytest.raises(AttributeError, match=msg): | ||||
|             ts.tz = tz | ||||
|  | ||||
|     def test_default_to_stdlib_utc(self): | ||||
|         assert Timestamp.utcnow().tz is timezone.utc | ||||
|         assert Timestamp.now("UTC").tz is timezone.utc | ||||
|         assert Timestamp("2016-01-01", tz="UTC").tz is timezone.utc | ||||
|  | ||||
|     def test_tz(self): | ||||
|         tstr = "2014-02-01 09:00" | ||||
|         ts = Timestamp(tstr) | ||||
|         local = ts.tz_localize("Asia/Tokyo") | ||||
|         assert local.hour == 9 | ||||
|         assert local == Timestamp(tstr, tz="Asia/Tokyo") | ||||
|         conv = local.tz_convert("US/Eastern") | ||||
|         assert conv == Timestamp("2014-01-31 19:00", tz="US/Eastern") | ||||
|         assert conv.hour == 19 | ||||
|  | ||||
|         # preserves nanosecond | ||||
|         ts = Timestamp(tstr) + offsets.Nano(5) | ||||
|         local = ts.tz_localize("Asia/Tokyo") | ||||
|         assert local.hour == 9 | ||||
|         assert local.nanosecond == 5 | ||||
|         conv = local.tz_convert("US/Eastern") | ||||
|         assert conv.nanosecond == 5 | ||||
|         assert conv.hour == 19 | ||||
|  | ||||
|     def test_utc_z_designator(self): | ||||
|         assert get_timezone(Timestamp("2014-11-02 01:00Z").tzinfo) is timezone.utc | ||||
|  | ||||
|     def test_asm8(self): | ||||
|         ns = [Timestamp.min._value, Timestamp.max._value, 1000] | ||||
|  | ||||
|         for n in ns: | ||||
|             assert ( | ||||
|                 Timestamp(n).asm8.view("i8") == np.datetime64(n, "ns").view("i8") == n | ||||
|             ) | ||||
|  | ||||
|         assert Timestamp("nat").asm8.view("i8") == np.datetime64("nat", "ns").view("i8") | ||||
|  | ||||
|     def test_class_ops(self): | ||||
|         def compare(x, y): | ||||
|             assert int((Timestamp(x)._value - Timestamp(y)._value) / 1e9) == 0 | ||||
|  | ||||
|         compare(Timestamp.now(), datetime.now()) | ||||
|         compare(Timestamp.now("UTC"), datetime.now(pytz.timezone("UTC"))) | ||||
|         compare(Timestamp.now("UTC"), datetime.now(tzutc())) | ||||
|         compare(Timestamp.utcnow(), datetime.now(timezone.utc)) | ||||
|         compare(Timestamp.today(), datetime.today()) | ||||
|         current_time = calendar.timegm(datetime.now().utctimetuple()) | ||||
|  | ||||
|         ts_utc = Timestamp.utcfromtimestamp(current_time) | ||||
|         assert ts_utc.timestamp() == current_time | ||||
|         compare( | ||||
|             Timestamp.fromtimestamp(current_time), datetime.fromtimestamp(current_time) | ||||
|         ) | ||||
|         compare( | ||||
|             # Support tz kwarg in Timestamp.fromtimestamp | ||||
|             Timestamp.fromtimestamp(current_time, "UTC"), | ||||
|             datetime.fromtimestamp(current_time, utc), | ||||
|         ) | ||||
|         compare( | ||||
|             # Support tz kwarg in Timestamp.fromtimestamp | ||||
|             Timestamp.fromtimestamp(current_time, tz="UTC"), | ||||
|             datetime.fromtimestamp(current_time, utc), | ||||
|         ) | ||||
|  | ||||
|         date_component = datetime.now(timezone.utc) | ||||
|         time_component = (date_component + timedelta(minutes=10)).time() | ||||
|         compare( | ||||
|             Timestamp.combine(date_component, time_component), | ||||
|             datetime.combine(date_component, time_component), | ||||
|         ) | ||||
|  | ||||
|     def test_basics_nanos(self): | ||||
|         val = np.int64(946_684_800_000_000_000).view("M8[ns]") | ||||
|         stamp = Timestamp(val.view("i8") + 500) | ||||
|         assert stamp.year == 2000 | ||||
|         assert stamp.month == 1 | ||||
|         assert stamp.microsecond == 0 | ||||
|         assert stamp.nanosecond == 500 | ||||
|  | ||||
|         # GH 14415 | ||||
|         val = np.iinfo(np.int64).min + 80_000_000_000_000 | ||||
|         stamp = Timestamp(val) | ||||
|         assert stamp.year == 1677 | ||||
|         assert stamp.month == 9 | ||||
|         assert stamp.day == 21 | ||||
|         assert stamp.microsecond == 145224 | ||||
|         assert stamp.nanosecond == 192 | ||||
|  | ||||
|     def test_roundtrip(self): | ||||
|         # test value to string and back conversions | ||||
|         # further test accessors | ||||
|         base = Timestamp("20140101 00:00:00").as_unit("ns") | ||||
|  | ||||
|         result = Timestamp(base._value + Timedelta("5ms")._value) | ||||
|         assert result == Timestamp(f"{base}.005000") | ||||
|         assert result.microsecond == 5000 | ||||
|  | ||||
|         result = Timestamp(base._value + Timedelta("5us")._value) | ||||
|         assert result == Timestamp(f"{base}.000005") | ||||
|         assert result.microsecond == 5 | ||||
|  | ||||
|         result = Timestamp(base._value + Timedelta("5ns")._value) | ||||
|         assert result == Timestamp(f"{base}.000000005") | ||||
|         assert result.nanosecond == 5 | ||||
|         assert result.microsecond == 0 | ||||
|  | ||||
|         result = Timestamp(base._value + Timedelta("6ms 5us")._value) | ||||
|         assert result == Timestamp(f"{base}.006005") | ||||
|         assert result.microsecond == 5 + 6 * 1000 | ||||
|  | ||||
|         result = Timestamp(base._value + Timedelta("200ms 5us")._value) | ||||
|         assert result == Timestamp(f"{base}.200005") | ||||
|         assert result.microsecond == 5 + 200 * 1000 | ||||
|  | ||||
|     def test_hash_equivalent(self): | ||||
|         d = {datetime(2011, 1, 1): 5} | ||||
|         stamp = Timestamp(datetime(2011, 1, 1)) | ||||
|         assert d[stamp] == 5 | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "timezone, year, month, day, hour", | ||||
|         [["America/Chicago", 2013, 11, 3, 1], ["America/Santiago", 2021, 4, 3, 23]], | ||||
|     ) | ||||
|     def test_hash_timestamp_with_fold(self, timezone, year, month, day, hour): | ||||
|         # see gh-33931 | ||||
|         test_timezone = gettz(timezone) | ||||
|         transition_1 = Timestamp( | ||||
|             year=year, | ||||
|             month=month, | ||||
|             day=day, | ||||
|             hour=hour, | ||||
|             minute=0, | ||||
|             fold=0, | ||||
|             tzinfo=test_timezone, | ||||
|         ) | ||||
|         transition_2 = Timestamp( | ||||
|             year=year, | ||||
|             month=month, | ||||
|             day=day, | ||||
|             hour=hour, | ||||
|             minute=0, | ||||
|             fold=1, | ||||
|             tzinfo=test_timezone, | ||||
|         ) | ||||
|         assert hash(transition_1) == hash(transition_2) | ||||
|  | ||||
|  | ||||
| class TestTimestampNsOperations: | ||||
|     def test_nanosecond_string_parsing(self): | ||||
|         ts = Timestamp("2013-05-01 07:15:45.123456789") | ||||
|         # GH 7878 | ||||
|         expected_repr = "2013-05-01 07:15:45.123456789" | ||||
|         expected_value = 1_367_392_545_123_456_789 | ||||
|         assert ts._value == expected_value | ||||
|         assert expected_repr in repr(ts) | ||||
|  | ||||
|         ts = Timestamp("2013-05-01 07:15:45.123456789+09:00", tz="Asia/Tokyo") | ||||
|         assert ts._value == expected_value - 9 * 3600 * 1_000_000_000 | ||||
|         assert expected_repr in repr(ts) | ||||
|  | ||||
|         ts = Timestamp("2013-05-01 07:15:45.123456789", tz="UTC") | ||||
|         assert ts._value == expected_value | ||||
|         assert expected_repr in repr(ts) | ||||
|  | ||||
|         ts = Timestamp("2013-05-01 07:15:45.123456789", tz="US/Eastern") | ||||
|         assert ts._value == expected_value + 4 * 3600 * 1_000_000_000 | ||||
|         assert expected_repr in repr(ts) | ||||
|  | ||||
|         # GH 10041 | ||||
|         ts = Timestamp("20130501T071545.123456789") | ||||
|         assert ts._value == expected_value | ||||
|         assert expected_repr in repr(ts) | ||||
|  | ||||
|     def test_nanosecond_timestamp(self): | ||||
|         # GH 7610 | ||||
|         expected = 1_293_840_000_000_000_005 | ||||
|         t = Timestamp("2011-01-01") + offsets.Nano(5) | ||||
|         assert repr(t) == "Timestamp('2011-01-01 00:00:00.000000005')" | ||||
|         assert t._value == expected | ||||
|         assert t.nanosecond == 5 | ||||
|  | ||||
|         t = Timestamp(t) | ||||
|         assert repr(t) == "Timestamp('2011-01-01 00:00:00.000000005')" | ||||
|         assert t._value == expected | ||||
|         assert t.nanosecond == 5 | ||||
|  | ||||
|         t = Timestamp("2011-01-01 00:00:00.000000005") | ||||
|         assert repr(t) == "Timestamp('2011-01-01 00:00:00.000000005')" | ||||
|         assert t._value == expected | ||||
|         assert t.nanosecond == 5 | ||||
|  | ||||
|         expected = 1_293_840_000_000_000_010 | ||||
|         t = t + offsets.Nano(5) | ||||
|         assert repr(t) == "Timestamp('2011-01-01 00:00:00.000000010')" | ||||
|         assert t._value == expected | ||||
|         assert t.nanosecond == 10 | ||||
|  | ||||
|         t = Timestamp(t) | ||||
|         assert repr(t) == "Timestamp('2011-01-01 00:00:00.000000010')" | ||||
|         assert t._value == expected | ||||
|         assert t.nanosecond == 10 | ||||
|  | ||||
|         t = Timestamp("2011-01-01 00:00:00.000000010") | ||||
|         assert repr(t) == "Timestamp('2011-01-01 00:00:00.000000010')" | ||||
|         assert t._value == expected | ||||
|         assert t.nanosecond == 10 | ||||
|  | ||||
|  | ||||
| class TestTimestampConversion: | ||||
|     def test_conversion(self): | ||||
|         # GH#9255 | ||||
|         ts = Timestamp("2000-01-01").as_unit("ns") | ||||
|  | ||||
|         result = ts.to_pydatetime() | ||||
|         expected = datetime(2000, 1, 1) | ||||
|         assert result == expected | ||||
|         assert type(result) == type(expected) | ||||
|  | ||||
|         result = ts.to_datetime64() | ||||
|         expected = np.datetime64(ts._value, "ns") | ||||
|         assert result == expected | ||||
|         assert type(result) == type(expected) | ||||
|         assert result.dtype == expected.dtype | ||||
|  | ||||
|     def test_to_period_tz_warning(self): | ||||
|         # GH#21333 make sure a warning is issued when timezone | ||||
|         # info is lost | ||||
|         ts = Timestamp("2009-04-15 16:17:18", tz="US/Eastern") | ||||
|         with tm.assert_produces_warning(UserWarning): | ||||
|             # warning that timezone info will be lost | ||||
|             ts.to_period("D") | ||||
|  | ||||
|     def test_to_numpy_alias(self): | ||||
|         # GH 24653: alias .to_numpy() for scalars | ||||
|         ts = Timestamp(datetime.now()) | ||||
|         assert ts.to_datetime64() == ts.to_numpy() | ||||
|  | ||||
|         # GH#44460 | ||||
|         msg = "dtype and copy arguments are ignored" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             ts.to_numpy("M8[s]") | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             ts.to_numpy(copy=True) | ||||
|  | ||||
|  | ||||
| class TestNonNano: | ||||
|     @pytest.fixture(params=["s", "ms", "us"]) | ||||
|     def reso(self, request): | ||||
|         return request.param | ||||
|  | ||||
|     @pytest.fixture | ||||
|     def dt64(self, reso): | ||||
|         # cases that are in-bounds for nanosecond, so we can compare against | ||||
|         #  the existing implementation. | ||||
|         return np.datetime64("2016-01-01", reso) | ||||
|  | ||||
|     @pytest.fixture | ||||
|     def ts(self, dt64): | ||||
|         return Timestamp._from_dt64(dt64) | ||||
|  | ||||
|     @pytest.fixture | ||||
|     def ts_tz(self, ts, tz_aware_fixture): | ||||
|         tz = maybe_get_tz(tz_aware_fixture) | ||||
|         return Timestamp._from_value_and_reso(ts._value, ts._creso, tz) | ||||
|  | ||||
|     def test_non_nano_construction(self, dt64, ts, reso): | ||||
|         assert ts._value == dt64.view("i8") | ||||
|  | ||||
|         if reso == "s": | ||||
|             assert ts._creso == NpyDatetimeUnit.NPY_FR_s.value | ||||
|         elif reso == "ms": | ||||
|             assert ts._creso == NpyDatetimeUnit.NPY_FR_ms.value | ||||
|         elif reso == "us": | ||||
|             assert ts._creso == NpyDatetimeUnit.NPY_FR_us.value | ||||
|  | ||||
|     def test_non_nano_fields(self, dt64, ts): | ||||
|         alt = Timestamp(dt64) | ||||
|  | ||||
|         assert ts.year == alt.year | ||||
|         assert ts.month == alt.month | ||||
|         assert ts.day == alt.day | ||||
|         assert ts.hour == ts.minute == ts.second == ts.microsecond == 0 | ||||
|         assert ts.nanosecond == 0 | ||||
|  | ||||
|         assert ts.to_julian_date() == alt.to_julian_date() | ||||
|         assert ts.weekday() == alt.weekday() | ||||
|         assert ts.isoweekday() == alt.isoweekday() | ||||
|  | ||||
|     def test_start_end_fields(self, ts): | ||||
|         assert ts.is_year_start | ||||
|         assert ts.is_quarter_start | ||||
|         assert ts.is_month_start | ||||
|         assert not ts.is_year_end | ||||
|         assert not ts.is_month_end | ||||
|         assert not ts.is_month_end | ||||
|  | ||||
|         # 2016-01-01 is a Friday, so is year/quarter/month start with this freq | ||||
|         assert ts.is_year_start | ||||
|         assert ts.is_quarter_start | ||||
|         assert ts.is_month_start | ||||
|         assert not ts.is_year_end | ||||
|         assert not ts.is_month_end | ||||
|         assert not ts.is_month_end | ||||
|  | ||||
|     def test_day_name(self, dt64, ts): | ||||
|         alt = Timestamp(dt64) | ||||
|         assert ts.day_name() == alt.day_name() | ||||
|  | ||||
|     def test_month_name(self, dt64, ts): | ||||
|         alt = Timestamp(dt64) | ||||
|         assert ts.month_name() == alt.month_name() | ||||
|  | ||||
|     def test_tz_convert(self, ts): | ||||
|         ts = Timestamp._from_value_and_reso(ts._value, ts._creso, utc) | ||||
|  | ||||
|         tz = pytz.timezone("US/Pacific") | ||||
|         result = ts.tz_convert(tz) | ||||
|  | ||||
|         assert isinstance(result, Timestamp) | ||||
|         assert result._creso == ts._creso | ||||
|         assert tz_compare(result.tz, tz) | ||||
|  | ||||
|     def test_repr(self, dt64, ts): | ||||
|         alt = Timestamp(dt64) | ||||
|  | ||||
|         assert str(ts) == str(alt) | ||||
|         assert repr(ts) == repr(alt) | ||||
|  | ||||
|     def test_comparison(self, dt64, ts): | ||||
|         alt = Timestamp(dt64) | ||||
|  | ||||
|         assert ts == dt64 | ||||
|         assert dt64 == ts | ||||
|         assert ts == alt | ||||
|         assert alt == ts | ||||
|  | ||||
|         assert not ts != dt64 | ||||
|         assert not dt64 != ts | ||||
|         assert not ts != alt | ||||
|         assert not alt != ts | ||||
|  | ||||
|         assert not ts < dt64 | ||||
|         assert not dt64 < ts | ||||
|         assert not ts < alt | ||||
|         assert not alt < ts | ||||
|  | ||||
|         assert not ts > dt64 | ||||
|         assert not dt64 > ts | ||||
|         assert not ts > alt | ||||
|         assert not alt > ts | ||||
|  | ||||
|         assert ts >= dt64 | ||||
|         assert dt64 >= ts | ||||
|         assert ts >= alt | ||||
|         assert alt >= ts | ||||
|  | ||||
|         assert ts <= dt64 | ||||
|         assert dt64 <= ts | ||||
|         assert ts <= alt | ||||
|         assert alt <= ts | ||||
|  | ||||
|     def test_cmp_cross_reso(self): | ||||
|         # numpy gets this wrong because of silent overflow | ||||
|         dt64 = np.datetime64(9223372800, "s")  # won't fit in M8[ns] | ||||
|         ts = Timestamp._from_dt64(dt64) | ||||
|  | ||||
|         # subtracting 3600*24 gives a datetime64 that _can_ fit inside the | ||||
|         #  nanosecond implementation bounds. | ||||
|         other = Timestamp(dt64 - 3600 * 24).as_unit("ns") | ||||
|         assert other < ts | ||||
|         assert other.asm8 > ts.asm8  # <- numpy gets this wrong | ||||
|         assert ts > other | ||||
|         assert ts.asm8 < other.asm8  # <- numpy gets this wrong | ||||
|         assert not other == ts | ||||
|         assert ts != other | ||||
|  | ||||
|     @pytest.mark.xfail(reason="Dispatches to np.datetime64 which is wrong") | ||||
|     def test_cmp_cross_reso_reversed_dt64(self): | ||||
|         dt64 = np.datetime64(106752, "D")  # won't fit in M8[ns] | ||||
|         ts = Timestamp._from_dt64(dt64) | ||||
|         other = Timestamp(dt64 - 1) | ||||
|  | ||||
|         assert other.asm8 < ts | ||||
|  | ||||
|     def test_pickle(self, ts, tz_aware_fixture): | ||||
|         tz = tz_aware_fixture | ||||
|         tz = maybe_get_tz(tz) | ||||
|         ts = Timestamp._from_value_and_reso(ts._value, ts._creso, tz) | ||||
|         rt = tm.round_trip_pickle(ts) | ||||
|         assert rt._creso == ts._creso | ||||
|         assert rt == ts | ||||
|  | ||||
|     def test_normalize(self, dt64, ts): | ||||
|         alt = Timestamp(dt64) | ||||
|         result = ts.normalize() | ||||
|         assert result._creso == ts._creso | ||||
|         assert result == alt.normalize() | ||||
|  | ||||
|     def test_asm8(self, dt64, ts): | ||||
|         rt = ts.asm8 | ||||
|         assert rt == dt64 | ||||
|         assert rt.dtype == dt64.dtype | ||||
|  | ||||
|     def test_to_numpy(self, dt64, ts): | ||||
|         res = ts.to_numpy() | ||||
|         assert res == dt64 | ||||
|         assert res.dtype == dt64.dtype | ||||
|  | ||||
|     def test_to_datetime64(self, dt64, ts): | ||||
|         res = ts.to_datetime64() | ||||
|         assert res == dt64 | ||||
|         assert res.dtype == dt64.dtype | ||||
|  | ||||
|     def test_timestamp(self, dt64, ts): | ||||
|         alt = Timestamp(dt64) | ||||
|         assert ts.timestamp() == alt.timestamp() | ||||
|  | ||||
|     def test_to_period(self, dt64, ts): | ||||
|         alt = Timestamp(dt64) | ||||
|         assert ts.to_period("D") == alt.to_period("D") | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "td", [timedelta(days=4), Timedelta(days=4), np.timedelta64(4, "D")] | ||||
|     ) | ||||
|     def test_addsub_timedeltalike_non_nano(self, dt64, ts, td): | ||||
|         exp_reso = max(ts._creso, Timedelta(td)._creso) | ||||
|  | ||||
|         result = ts - td | ||||
|         expected = Timestamp(dt64) - td | ||||
|         assert isinstance(result, Timestamp) | ||||
|         assert result._creso == exp_reso | ||||
|         assert result == expected | ||||
|  | ||||
|         result = ts + td | ||||
|         expected = Timestamp(dt64) + td | ||||
|         assert isinstance(result, Timestamp) | ||||
|         assert result._creso == exp_reso | ||||
|         assert result == expected | ||||
|  | ||||
|         result = td + ts | ||||
|         expected = td + Timestamp(dt64) | ||||
|         assert isinstance(result, Timestamp) | ||||
|         assert result._creso == exp_reso | ||||
|         assert result == expected | ||||
|  | ||||
|     def test_addsub_offset(self, ts_tz): | ||||
|         # specifically non-Tick offset | ||||
|         off = offsets.YearEnd(1) | ||||
|         result = ts_tz + off | ||||
|  | ||||
|         assert isinstance(result, Timestamp) | ||||
|         assert result._creso == ts_tz._creso | ||||
|         if ts_tz.month == 12 and ts_tz.day == 31: | ||||
|             assert result.year == ts_tz.year + 1 | ||||
|         else: | ||||
|             assert result.year == ts_tz.year | ||||
|         assert result.day == 31 | ||||
|         assert result.month == 12 | ||||
|         assert tz_compare(result.tz, ts_tz.tz) | ||||
|  | ||||
|         result = ts_tz - off | ||||
|  | ||||
|         assert isinstance(result, Timestamp) | ||||
|         assert result._creso == ts_tz._creso | ||||
|         assert result.year == ts_tz.year - 1 | ||||
|         assert result.day == 31 | ||||
|         assert result.month == 12 | ||||
|         assert tz_compare(result.tz, ts_tz.tz) | ||||
|  | ||||
|     def test_sub_datetimelike_mismatched_reso(self, ts_tz): | ||||
|         # case with non-lossy rounding | ||||
|         ts = ts_tz | ||||
|  | ||||
|         # choose a unit for `other` that doesn't match ts_tz's; | ||||
|         #  this construction ensures we get cases with other._creso < ts._creso | ||||
|         #  and cases with other._creso > ts._creso | ||||
|         unit = { | ||||
|             NpyDatetimeUnit.NPY_FR_us.value: "ms", | ||||
|             NpyDatetimeUnit.NPY_FR_ms.value: "s", | ||||
|             NpyDatetimeUnit.NPY_FR_s.value: "us", | ||||
|         }[ts._creso] | ||||
|         other = ts.as_unit(unit) | ||||
|         assert other._creso != ts._creso | ||||
|  | ||||
|         result = ts - other | ||||
|         assert isinstance(result, Timedelta) | ||||
|         assert result._value == 0 | ||||
|         assert result._creso == max(ts._creso, other._creso) | ||||
|  | ||||
|         result = other - ts | ||||
|         assert isinstance(result, Timedelta) | ||||
|         assert result._value == 0 | ||||
|         assert result._creso == max(ts._creso, other._creso) | ||||
|  | ||||
|         if ts._creso < other._creso: | ||||
|             # Case where rounding is lossy | ||||
|             other2 = other + Timedelta._from_value_and_reso(1, other._creso) | ||||
|             exp = ts.as_unit(other.unit) - other2 | ||||
|  | ||||
|             res = ts - other2 | ||||
|             assert res == exp | ||||
|             assert res._creso == max(ts._creso, other._creso) | ||||
|  | ||||
|             res = other2 - ts | ||||
|             assert res == -exp | ||||
|             assert res._creso == max(ts._creso, other._creso) | ||||
|         else: | ||||
|             ts2 = ts + Timedelta._from_value_and_reso(1, ts._creso) | ||||
|             exp = ts2 - other.as_unit(ts2.unit) | ||||
|  | ||||
|             res = ts2 - other | ||||
|             assert res == exp | ||||
|             assert res._creso == max(ts._creso, other._creso) | ||||
|             res = other - ts2 | ||||
|             assert res == -exp | ||||
|             assert res._creso == max(ts._creso, other._creso) | ||||
|  | ||||
|     def test_sub_timedeltalike_mismatched_reso(self, ts_tz): | ||||
|         # case with non-lossy rounding | ||||
|         ts = ts_tz | ||||
|  | ||||
|         # choose a unit for `other` that doesn't match ts_tz's; | ||||
|         #  this construction ensures we get cases with other._creso < ts._creso | ||||
|         #  and cases with other._creso > ts._creso | ||||
|         unit = { | ||||
|             NpyDatetimeUnit.NPY_FR_us.value: "ms", | ||||
|             NpyDatetimeUnit.NPY_FR_ms.value: "s", | ||||
|             NpyDatetimeUnit.NPY_FR_s.value: "us", | ||||
|         }[ts._creso] | ||||
|         other = Timedelta(0).as_unit(unit) | ||||
|         assert other._creso != ts._creso | ||||
|  | ||||
|         result = ts + other | ||||
|         assert isinstance(result, Timestamp) | ||||
|         assert result == ts | ||||
|         assert result._creso == max(ts._creso, other._creso) | ||||
|  | ||||
|         result = other + ts | ||||
|         assert isinstance(result, Timestamp) | ||||
|         assert result == ts | ||||
|         assert result._creso == max(ts._creso, other._creso) | ||||
|  | ||||
|         if ts._creso < other._creso: | ||||
|             # Case where rounding is lossy | ||||
|             other2 = other + Timedelta._from_value_and_reso(1, other._creso) | ||||
|             exp = ts.as_unit(other.unit) + other2 | ||||
|             res = ts + other2 | ||||
|             assert res == exp | ||||
|             assert res._creso == max(ts._creso, other._creso) | ||||
|             res = other2 + ts | ||||
|             assert res == exp | ||||
|             assert res._creso == max(ts._creso, other._creso) | ||||
|         else: | ||||
|             ts2 = ts + Timedelta._from_value_and_reso(1, ts._creso) | ||||
|             exp = ts2 + other.as_unit(ts2.unit) | ||||
|  | ||||
|             res = ts2 + other | ||||
|             assert res == exp | ||||
|             assert res._creso == max(ts._creso, other._creso) | ||||
|             res = other + ts2 | ||||
|             assert res == exp | ||||
|             assert res._creso == max(ts._creso, other._creso) | ||||
|  | ||||
|     def test_addition_doesnt_downcast_reso(self): | ||||
|         # https://github.com/pandas-dev/pandas/pull/48748#pullrequestreview-1122635413 | ||||
|         ts = Timestamp(year=2022, month=1, day=1, microsecond=999999).as_unit("us") | ||||
|         td = Timedelta(microseconds=1).as_unit("us") | ||||
|         res = ts + td | ||||
|         assert res._creso == ts._creso | ||||
|  | ||||
|     def test_sub_timedelta64_mismatched_reso(self, ts_tz): | ||||
|         ts = ts_tz | ||||
|  | ||||
|         res = ts + np.timedelta64(1, "ns") | ||||
|         exp = ts.as_unit("ns") + np.timedelta64(1, "ns") | ||||
|         assert exp == res | ||||
|         assert exp._creso == NpyDatetimeUnit.NPY_FR_ns.value | ||||
|  | ||||
|     def test_min(self, ts): | ||||
|         assert ts.min <= ts | ||||
|         assert ts.min._creso == ts._creso | ||||
|         assert ts.min._value == NaT._value + 1 | ||||
|  | ||||
|     def test_max(self, ts): | ||||
|         assert ts.max >= ts | ||||
|         assert ts.max._creso == ts._creso | ||||
|         assert ts.max._value == np.iinfo(np.int64).max | ||||
|  | ||||
|     def test_resolution(self, ts): | ||||
|         expected = Timedelta._from_value_and_reso(1, ts._creso) | ||||
|         result = ts.resolution | ||||
|         assert result == expected | ||||
|         assert result._creso == expected._creso | ||||
|  | ||||
|     def test_out_of_ns_bounds(self): | ||||
|         # https://github.com/pandas-dev/pandas/issues/51060 | ||||
|         result = Timestamp(-52700112000, unit="s") | ||||
|         assert result == Timestamp("0300-01-01") | ||||
|         assert result.to_numpy() == np.datetime64("0300-01-01T00:00:00", "s") | ||||
|  | ||||
|  | ||||
| def test_timestamp_class_min_max_resolution(): | ||||
|     # when accessed on the class (as opposed to an instance), we default | ||||
|     #  to nanoseconds | ||||
|     assert Timestamp.min == Timestamp(NaT._value + 1) | ||||
|     assert Timestamp.min._creso == NpyDatetimeUnit.NPY_FR_ns.value | ||||
|  | ||||
|     assert Timestamp.max == Timestamp(np.iinfo(np.int64).max) | ||||
|     assert Timestamp.max._creso == NpyDatetimeUnit.NPY_FR_ns.value | ||||
|  | ||||
|     assert Timestamp.resolution == Timedelta(1) | ||||
|     assert Timestamp.resolution._creso == NpyDatetimeUnit.NPY_FR_ns.value | ||||
|  | ||||
|  | ||||
| def test_delimited_date(): | ||||
|     # https://github.com/pandas-dev/pandas/issues/50231 | ||||
|     with tm.assert_produces_warning(None): | ||||
|         result = Timestamp("13-01-2000") | ||||
|     expected = Timestamp(2000, 1, 13) | ||||
|     assert result == expected | ||||
|  | ||||
|  | ||||
| def test_utctimetuple(): | ||||
|     # GH 32174 | ||||
|     ts = Timestamp("2000-01-01", tz="UTC") | ||||
|     result = ts.utctimetuple() | ||||
|     expected = time.struct_time((2000, 1, 1, 0, 0, 0, 5, 1, 0)) | ||||
|     assert result == expected | ||||
|  | ||||
|  | ||||
| def test_negative_dates(): | ||||
|     # https://github.com/pandas-dev/pandas/issues/50787 | ||||
|     ts = Timestamp("-2000-01-01") | ||||
|     msg = ( | ||||
|         " not yet supported on Timestamps which are outside the range of " | ||||
|         "Python's standard library. For now, please call the components you need " | ||||
|         r"\(such as `.year` and `.month`\) and construct your string from there.$" | ||||
|     ) | ||||
|     func = "^strftime" | ||||
|     with pytest.raises(NotImplementedError, match=func + msg): | ||||
|         ts.strftime("%Y") | ||||
|  | ||||
|     msg = ( | ||||
|         " not yet supported on Timestamps which " | ||||
|         "are outside the range of Python's standard library. " | ||||
|     ) | ||||
|     func = "^date" | ||||
|     with pytest.raises(NotImplementedError, match=func + msg): | ||||
|         ts.date() | ||||
|     func = "^isocalendar" | ||||
|     with pytest.raises(NotImplementedError, match=func + msg): | ||||
|         ts.isocalendar() | ||||
|     func = "^timetuple" | ||||
|     with pytest.raises(NotImplementedError, match=func + msg): | ||||
|         ts.timetuple() | ||||
|     func = "^toordinal" | ||||
|     with pytest.raises(NotImplementedError, match=func + msg): | ||||
|         ts.toordinal() | ||||
| @ -0,0 +1,24 @@ | ||||
| """ | ||||
| Tests for Timestamp timezone-related methods | ||||
| """ | ||||
| from datetime import datetime | ||||
|  | ||||
| from pandas._libs.tslibs import timezones | ||||
|  | ||||
| from pandas import Timestamp | ||||
|  | ||||
|  | ||||
| class TestTimestampTZOperations: | ||||
|     # ------------------------------------------------------------------ | ||||
|  | ||||
|     def test_timestamp_timetz_equivalent_with_datetime_tz(self, tz_naive_fixture): | ||||
|         # GH21358 | ||||
|         tz = timezones.maybe_get_tz(tz_naive_fixture) | ||||
|  | ||||
|         stamp = Timestamp("2018-06-04 10:20:30", tz=tz) | ||||
|         _datetime = datetime(2018, 6, 4, hour=10, minute=20, second=30, tzinfo=tz) | ||||
|  | ||||
|         result = stamp.timetz() | ||||
|         expected = _datetime.timetz() | ||||
|  | ||||
|         assert result == expected | ||||
		Reference in New Issue
	
	Block a user