forked from Alsan/Post_finder
venv
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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