virtuelle Umgebungen teil20 und teil20a
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.
@@ -0,0 +1,295 @@
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
timezone,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
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)
|
||||
msg = (
|
||||
"the add operation between "
|
||||
r"\<-?\d+ \* Days\> and \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} "
|
||||
"will overflow"
|
||||
)
|
||||
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(OverflowError, match=msg):
|
||||
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(OverflowError, match=msg):
|
||||
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
|
@@ -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
|
@@ -0,0 +1,910 @@
|
||||
import calendar
|
||||
from datetime import (
|
||||
date,
|
||||
datetime,
|
||||
timedelta,
|
||||
timezone,
|
||||
)
|
||||
import zoneinfo
|
||||
|
||||
import dateutil.tz
|
||||
from dateutil.tz import tzutc
|
||||
import numpy as np
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
|
||||
from pandas.compat import PY310
|
||||
from pandas.errors import OutOfBoundsDatetime
|
||||
|
||||
from pandas import (
|
||||
NA,
|
||||
NaT,
|
||||
Period,
|
||||
Timedelta,
|
||||
Timestamp,
|
||||
)
|
||||
|
||||
|
||||
class TestTimestampConstructors:
|
||||
def test_construct_from_time_unit(self):
|
||||
# GH#54097 only passing a time component, no date
|
||||
ts = Timestamp("01:01:01.111")
|
||||
assert ts.unit == "ms"
|
||||
|
||||
def test_weekday_but_no_day_raises(self):
|
||||
# GH#52659
|
||||
msg = "Parsing datetimes with weekday but no day information is not supported"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp("2023 Sept Thu")
|
||||
|
||||
def test_construct_from_string_invalid_raises(self):
|
||||
# dateutil (weirdly) parses "200622-12-31" as
|
||||
# datetime(2022, 6, 20, 12, 0, tzinfo=tzoffset(None, -111600)
|
||||
# which besides being mis-parsed, is a tzoffset that will cause
|
||||
# str(ts) to raise ValueError. Ensure we raise in the constructor
|
||||
# instead.
|
||||
# see test_to_datetime_malformed_raise for analogous to_datetime test
|
||||
with pytest.raises(ValueError, match="gives an invalid tzoffset"):
|
||||
Timestamp("200622-12-31")
|
||||
|
||||
def test_constructor_str_infer_reso(self):
|
||||
# non-iso8601 path
|
||||
|
||||
# _parse_delimited_date path
|
||||
ts = Timestamp("01/30/2023")
|
||||
assert ts.unit == "s"
|
||||
|
||||
# _parse_dateabbr_string path
|
||||
ts = Timestamp("2015Q1")
|
||||
assert ts.unit == "s"
|
||||
|
||||
# dateutil_parse path
|
||||
ts = Timestamp("2016-01-01 1:30:01 PM")
|
||||
assert ts.unit == "s"
|
||||
|
||||
ts = Timestamp("2016 June 3 15:25:01.345")
|
||||
assert ts.unit == "ms"
|
||||
|
||||
ts = Timestamp("300-01-01")
|
||||
assert ts.unit == "s"
|
||||
|
||||
ts = Timestamp("300 June 1:30:01.300")
|
||||
assert ts.unit == "ms"
|
||||
|
||||
def test_constructor_from_iso8601_str_with_offset_reso(self):
|
||||
# GH#49737
|
||||
ts = Timestamp("2016-01-01 04:05:06-01:00")
|
||||
assert ts.unit == "s"
|
||||
|
||||
ts = Timestamp("2016-01-01 04:05:06.000-01:00")
|
||||
assert ts.unit == "ms"
|
||||
|
||||
ts = Timestamp("2016-01-01 04:05:06.000000-01:00")
|
||||
assert ts.unit == "us"
|
||||
|
||||
ts = Timestamp("2016-01-01 04:05:06.000000001-01:00")
|
||||
assert ts.unit == "ns"
|
||||
|
||||
def test_constructor_from_date_second_reso(self):
|
||||
# GH#49034 constructing from a pydate object gets lowest supported
|
||||
# reso, i.e. seconds
|
||||
obj = date(2012, 9, 1)
|
||||
ts = Timestamp(obj)
|
||||
assert ts.unit == "s"
|
||||
|
||||
@pytest.mark.parametrize("typ", [int, float])
|
||||
def test_construct_from_int_float_with_unit_out_of_bound_raises(self, typ):
|
||||
# GH#50870 make sure we get a OutOfBoundsDatetime instead of OverflowError
|
||||
val = typ(150000000000000)
|
||||
|
||||
msg = f"cannot convert input {val} with the unit 'D'"
|
||||
with pytest.raises(OutOfBoundsDatetime, match=msg):
|
||||
Timestamp(val, unit="D")
|
||||
|
||||
@pytest.mark.parametrize("typ", [int, float])
|
||||
def test_constructor_int_float_with_YM_unit(self, typ):
|
||||
# GH#47266 avoid the conversions in cast_from_unit
|
||||
val = typ(150)
|
||||
|
||||
ts = Timestamp(val, unit="Y")
|
||||
expected = Timestamp("2120-01-01")
|
||||
assert ts == expected
|
||||
|
||||
ts = Timestamp(val, unit="M")
|
||||
expected = Timestamp("1982-07-01")
|
||||
assert ts == expected
|
||||
|
||||
def test_constructor_float_not_round_with_YM_unit_deprecated(self):
|
||||
# GH#47267 avoid the conversions in cast_from-unit
|
||||
|
||||
msg = "Conversion of non-round float with unit=[MY] is ambiguous"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(150.5, unit="Y")
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(150.5, unit="M")
|
||||
|
||||
def test_constructor_datetime64_with_tz(self):
|
||||
# GH#42288, GH#24559
|
||||
dt = np.datetime64("1970-01-01 05:00:00")
|
||||
tzstr = "UTC+05:00"
|
||||
|
||||
# pre-2.0 this interpreted dt as a UTC time. in 2.0 this is treated
|
||||
# as a wall-time, consistent with DatetimeIndex behavior
|
||||
ts = Timestamp(dt, tz=tzstr)
|
||||
|
||||
alt = Timestamp(dt).tz_localize(tzstr)
|
||||
assert ts == alt
|
||||
assert ts.hour == 5
|
||||
|
||||
def test_constructor(self):
|
||||
base_str = "2014-07-01 09:00"
|
||||
base_dt = datetime(2014, 7, 1, 9)
|
||||
base_expected = 1_404_205_200_000_000_000
|
||||
|
||||
# confirm base representation is correct
|
||||
assert calendar.timegm(base_dt.timetuple()) * 1_000_000_000 == base_expected
|
||||
|
||||
tests = [
|
||||
(base_str, base_dt, base_expected),
|
||||
(
|
||||
"2014-07-01 10:00",
|
||||
datetime(2014, 7, 1, 10),
|
||||
base_expected + 3600 * 1_000_000_000,
|
||||
),
|
||||
(
|
||||
"2014-07-01 09:00:00.000008000",
|
||||
datetime(2014, 7, 1, 9, 0, 0, 8),
|
||||
base_expected + 8000,
|
||||
),
|
||||
(
|
||||
"2014-07-01 09:00:00.000000005",
|
||||
Timestamp("2014-07-01 09:00:00.000000005"),
|
||||
base_expected + 5,
|
||||
),
|
||||
]
|
||||
|
||||
timezones = [
|
||||
(None, 0),
|
||||
("UTC", 0),
|
||||
(pytz.utc, 0),
|
||||
("Asia/Tokyo", 9),
|
||||
("US/Eastern", -4),
|
||||
("dateutil/US/Pacific", -7),
|
||||
(pytz.FixedOffset(-180), -3),
|
||||
(dateutil.tz.tzoffset(None, 18000), 5),
|
||||
]
|
||||
|
||||
for date_str, date_obj, expected in tests:
|
||||
for result in [Timestamp(date_str), Timestamp(date_obj)]:
|
||||
result = result.as_unit("ns") # test originally written before non-nano
|
||||
# only with timestring
|
||||
assert result.as_unit("ns")._value == expected
|
||||
|
||||
# re-creation shouldn't affect to internal value
|
||||
result = Timestamp(result)
|
||||
assert result.as_unit("ns")._value == expected
|
||||
|
||||
# with timezone
|
||||
for tz, offset in timezones:
|
||||
for result in [Timestamp(date_str, tz=tz), Timestamp(date_obj, tz=tz)]:
|
||||
result = result.as_unit(
|
||||
"ns"
|
||||
) # test originally written before non-nano
|
||||
expected_tz = expected - offset * 3600 * 1_000_000_000
|
||||
assert result.as_unit("ns")._value == expected_tz
|
||||
|
||||
# should preserve tz
|
||||
result = Timestamp(result)
|
||||
assert result.as_unit("ns")._value == expected_tz
|
||||
|
||||
# should convert to UTC
|
||||
if tz is not None:
|
||||
result = Timestamp(result).tz_convert("UTC")
|
||||
else:
|
||||
result = Timestamp(result, tz="UTC")
|
||||
expected_utc = expected - offset * 3600 * 1_000_000_000
|
||||
assert result.as_unit("ns")._value == expected_utc
|
||||
|
||||
def test_constructor_with_stringoffset(self):
|
||||
# GH 7833
|
||||
base_str = "2014-07-01 11:00:00+02:00"
|
||||
base_dt = datetime(2014, 7, 1, 9)
|
||||
base_expected = 1_404_205_200_000_000_000
|
||||
|
||||
# confirm base representation is correct
|
||||
assert calendar.timegm(base_dt.timetuple()) * 1_000_000_000 == base_expected
|
||||
|
||||
tests = [
|
||||
(base_str, base_expected),
|
||||
("2014-07-01 12:00:00+02:00", base_expected + 3600 * 1_000_000_000),
|
||||
("2014-07-01 11:00:00.000008000+02:00", base_expected + 8000),
|
||||
("2014-07-01 11:00:00.000000005+02:00", base_expected + 5),
|
||||
]
|
||||
|
||||
timezones = [
|
||||
(None, 0),
|
||||
("UTC", 0),
|
||||
(pytz.utc, 0),
|
||||
("Asia/Tokyo", 9),
|
||||
("US/Eastern", -4),
|
||||
("dateutil/US/Pacific", -7),
|
||||
(pytz.FixedOffset(-180), -3),
|
||||
(dateutil.tz.tzoffset(None, 18000), 5),
|
||||
]
|
||||
|
||||
for date_str, expected in tests:
|
||||
for result in [Timestamp(date_str)]:
|
||||
# only with timestring
|
||||
assert result.as_unit("ns")._value == expected
|
||||
|
||||
# re-creation shouldn't affect to internal value
|
||||
result = Timestamp(result)
|
||||
assert result.as_unit("ns")._value == expected
|
||||
|
||||
# with timezone
|
||||
for tz, offset in timezones:
|
||||
result = Timestamp(date_str, tz=tz)
|
||||
expected_tz = expected
|
||||
assert result.as_unit("ns")._value == expected_tz
|
||||
|
||||
# should preserve tz
|
||||
result = Timestamp(result)
|
||||
assert result.as_unit("ns")._value == expected_tz
|
||||
|
||||
# should convert to UTC
|
||||
result = Timestamp(result).tz_convert("UTC")
|
||||
expected_utc = expected
|
||||
assert result.as_unit("ns")._value == expected_utc
|
||||
|
||||
# This should be 2013-11-01 05:00 in UTC
|
||||
# converted to Chicago tz
|
||||
result = Timestamp("2013-11-01 00:00:00-0500", tz="America/Chicago")
|
||||
assert result._value == Timestamp("2013-11-01 05:00")._value
|
||||
expected = "Timestamp('2013-11-01 00:00:00-0500', tz='America/Chicago')"
|
||||
assert repr(result) == expected
|
||||
assert result == eval(repr(result))
|
||||
|
||||
# This should be 2013-11-01 05:00 in UTC
|
||||
# converted to Tokyo tz (+09:00)
|
||||
result = Timestamp("2013-11-01 00:00:00-0500", tz="Asia/Tokyo")
|
||||
assert result._value == Timestamp("2013-11-01 05:00")._value
|
||||
expected = "Timestamp('2013-11-01 14:00:00+0900', tz='Asia/Tokyo')"
|
||||
assert repr(result) == expected
|
||||
assert result == eval(repr(result))
|
||||
|
||||
# GH11708
|
||||
# This should be 2015-11-18 10:00 in UTC
|
||||
# converted to Asia/Katmandu
|
||||
result = Timestamp("2015-11-18 15:45:00+05:45", tz="Asia/Katmandu")
|
||||
assert result._value == Timestamp("2015-11-18 10:00")._value
|
||||
expected = "Timestamp('2015-11-18 15:45:00+0545', tz='Asia/Katmandu')"
|
||||
assert repr(result) == expected
|
||||
assert result == eval(repr(result))
|
||||
|
||||
# This should be 2015-11-18 10:00 in UTC
|
||||
# converted to Asia/Kolkata
|
||||
result = Timestamp("2015-11-18 15:30:00+05:30", tz="Asia/Kolkata")
|
||||
assert result._value == Timestamp("2015-11-18 10:00")._value
|
||||
expected = "Timestamp('2015-11-18 15:30:00+0530', tz='Asia/Kolkata')"
|
||||
assert repr(result) == expected
|
||||
assert result == eval(repr(result))
|
||||
|
||||
def test_constructor_invalid(self):
|
||||
msg = "Cannot convert input"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
Timestamp(slice(2))
|
||||
msg = "Cannot convert Period"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(Period("1000-01-01"))
|
||||
|
||||
def test_constructor_invalid_tz(self):
|
||||
# GH#17690
|
||||
msg = (
|
||||
"Argument 'tzinfo' has incorrect type "
|
||||
r"\(expected datetime.tzinfo, got str\)"
|
||||
)
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
Timestamp("2017-10-22", tzinfo="US/Eastern")
|
||||
|
||||
msg = "at most one of"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp("2017-10-22", tzinfo=pytz.utc, tz="UTC")
|
||||
|
||||
msg = "Cannot pass a date attribute keyword argument when passing a date string"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
# GH#5168
|
||||
# case where user tries to pass tz as an arg, not kwarg, gets
|
||||
# interpreted as `year`
|
||||
Timestamp("2012-01-01", "US/Pacific")
|
||||
|
||||
def test_constructor_strptime(self):
|
||||
# GH25016
|
||||
# Test support for Timestamp.strptime
|
||||
fmt = "%Y%m%d-%H%M%S-%f%z"
|
||||
ts = "20190129-235348-000001+0000"
|
||||
msg = r"Timestamp.strptime\(\) is not implemented"
|
||||
with pytest.raises(NotImplementedError, match=msg):
|
||||
Timestamp.strptime(ts, fmt)
|
||||
|
||||
def test_constructor_tz_or_tzinfo(self):
|
||||
# GH#17943, GH#17690, GH#5168
|
||||
stamps = [
|
||||
Timestamp(year=2017, month=10, day=22, tz="UTC"),
|
||||
Timestamp(year=2017, month=10, day=22, tzinfo=pytz.utc),
|
||||
Timestamp(year=2017, month=10, day=22, tz=pytz.utc),
|
||||
Timestamp(datetime(2017, 10, 22), tzinfo=pytz.utc),
|
||||
Timestamp(datetime(2017, 10, 22), tz="UTC"),
|
||||
Timestamp(datetime(2017, 10, 22), tz=pytz.utc),
|
||||
]
|
||||
assert all(ts == stamps[0] for ts in stamps)
|
||||
|
||||
def test_constructor_positional_with_tzinfo(self):
|
||||
# GH#31929
|
||||
ts = Timestamp(2020, 12, 31, tzinfo=timezone.utc)
|
||||
expected = Timestamp("2020-12-31", tzinfo=timezone.utc)
|
||||
assert ts == expected
|
||||
|
||||
@pytest.mark.parametrize("kwd", ["nanosecond", "microsecond", "second", "minute"])
|
||||
def test_constructor_positional_keyword_mixed_with_tzinfo(self, kwd, request):
|
||||
# TODO: if we passed microsecond with a keyword we would mess up
|
||||
# xref GH#45307
|
||||
if kwd != "nanosecond":
|
||||
# nanosecond is keyword-only as of 2.0, others are not
|
||||
mark = pytest.mark.xfail(reason="GH#45307")
|
||||
request.node.add_marker(mark)
|
||||
|
||||
kwargs = {kwd: 4}
|
||||
ts = Timestamp(2020, 12, 31, tzinfo=timezone.utc, **kwargs)
|
||||
|
||||
td_kwargs = {kwd + "s": 4}
|
||||
td = Timedelta(**td_kwargs)
|
||||
expected = Timestamp("2020-12-31", tz=timezone.utc) + td
|
||||
assert ts == expected
|
||||
|
||||
def test_constructor_positional(self):
|
||||
# see gh-10758
|
||||
msg = (
|
||||
"'NoneType' object cannot be interpreted as an integer"
|
||||
if PY310
|
||||
else "an integer is required"
|
||||
)
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
Timestamp(2000, 1)
|
||||
|
||||
msg = "month must be in 1..12"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(2000, 0, 1)
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(2000, 13, 1)
|
||||
|
||||
msg = "day is out of range for month"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(2000, 1, 0)
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(2000, 1, 32)
|
||||
|
||||
# see gh-11630
|
||||
assert repr(Timestamp(2015, 11, 12)) == repr(Timestamp("20151112"))
|
||||
assert repr(Timestamp(2015, 11, 12, 1, 2, 3, 999999)) == repr(
|
||||
Timestamp("2015-11-12 01:02:03.999999")
|
||||
)
|
||||
|
||||
def test_constructor_keyword(self):
|
||||
# GH 10758
|
||||
msg = "function missing required argument 'day'|Required argument 'day'"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
Timestamp(year=2000, month=1)
|
||||
|
||||
msg = "month must be in 1..12"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(year=2000, month=0, day=1)
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(year=2000, month=13, day=1)
|
||||
|
||||
msg = "day is out of range for month"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(year=2000, month=1, day=0)
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(year=2000, month=1, day=32)
|
||||
|
||||
assert repr(Timestamp(year=2015, month=11, day=12)) == repr(
|
||||
Timestamp("20151112")
|
||||
)
|
||||
|
||||
assert repr(
|
||||
Timestamp(
|
||||
year=2015,
|
||||
month=11,
|
||||
day=12,
|
||||
hour=1,
|
||||
minute=2,
|
||||
second=3,
|
||||
microsecond=999999,
|
||||
)
|
||||
) == repr(Timestamp("2015-11-12 01:02:03.999999"))
|
||||
|
||||
def test_constructor_fromordinal(self):
|
||||
base = datetime(2000, 1, 1)
|
||||
|
||||
ts = Timestamp.fromordinal(base.toordinal())
|
||||
assert base == ts
|
||||
assert base.toordinal() == ts.toordinal()
|
||||
|
||||
ts = Timestamp.fromordinal(base.toordinal(), tz="US/Eastern")
|
||||
assert Timestamp("2000-01-01", tz="US/Eastern") == ts
|
||||
assert base.toordinal() == ts.toordinal()
|
||||
|
||||
# GH#3042
|
||||
dt = datetime(2011, 4, 16, 0, 0)
|
||||
ts = Timestamp.fromordinal(dt.toordinal())
|
||||
assert ts.to_pydatetime() == dt
|
||||
|
||||
# with a tzinfo
|
||||
stamp = Timestamp("2011-4-16", tz="US/Eastern")
|
||||
dt_tz = stamp.to_pydatetime()
|
||||
ts = Timestamp.fromordinal(dt_tz.toordinal(), tz="US/Eastern")
|
||||
assert ts.to_pydatetime() == dt_tz
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"result",
|
||||
[
|
||||
Timestamp(datetime(2000, 1, 2, 3, 4, 5, 6), nanosecond=1),
|
||||
Timestamp(
|
||||
year=2000,
|
||||
month=1,
|
||||
day=2,
|
||||
hour=3,
|
||||
minute=4,
|
||||
second=5,
|
||||
microsecond=6,
|
||||
nanosecond=1,
|
||||
),
|
||||
Timestamp(
|
||||
year=2000,
|
||||
month=1,
|
||||
day=2,
|
||||
hour=3,
|
||||
minute=4,
|
||||
second=5,
|
||||
microsecond=6,
|
||||
nanosecond=1,
|
||||
tz="UTC",
|
||||
),
|
||||
Timestamp(2000, 1, 2, 3, 4, 5, 6, None, nanosecond=1),
|
||||
Timestamp(2000, 1, 2, 3, 4, 5, 6, tz=pytz.UTC, nanosecond=1),
|
||||
],
|
||||
)
|
||||
def test_constructor_nanosecond(self, result):
|
||||
# GH 18898
|
||||
# As of 2.0 (GH 49416), nanosecond should not be accepted positionally
|
||||
expected = Timestamp(datetime(2000, 1, 2, 3, 4, 5, 6), tz=result.tz)
|
||||
expected = expected + Timedelta(nanoseconds=1)
|
||||
assert result == expected
|
||||
|
||||
@pytest.mark.parametrize("z", ["Z0", "Z00"])
|
||||
def test_constructor_invalid_Z0_isostring(self, z):
|
||||
# GH 8910
|
||||
msg = f"Unknown datetime string format, unable to parse: 2014-11-02 01:00{z}"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(f"2014-11-02 01:00{z}")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"arg",
|
||||
[
|
||||
"year",
|
||||
"month",
|
||||
"day",
|
||||
"hour",
|
||||
"minute",
|
||||
"second",
|
||||
"microsecond",
|
||||
"nanosecond",
|
||||
],
|
||||
)
|
||||
def test_invalid_date_kwarg_with_string_input(self, arg):
|
||||
kwarg = {arg: 1}
|
||||
msg = "Cannot pass a date attribute keyword argument"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp("2010-10-10 12:59:59.999999999", **kwarg)
|
||||
|
||||
def test_out_of_bounds_integer_value(self):
|
||||
# GH#26651 check that we raise OutOfBoundsDatetime, not OverflowError
|
||||
msg = str(Timestamp.max._value * 2)
|
||||
with pytest.raises(OutOfBoundsDatetime, match=msg):
|
||||
Timestamp(Timestamp.max._value * 2)
|
||||
msg = str(Timestamp.min._value * 2)
|
||||
with pytest.raises(OutOfBoundsDatetime, match=msg):
|
||||
Timestamp(Timestamp.min._value * 2)
|
||||
|
||||
def test_out_of_bounds_value(self):
|
||||
one_us = np.timedelta64(1).astype("timedelta64[us]")
|
||||
|
||||
# By definition we can't go out of bounds in [ns], so we
|
||||
# convert the datetime64s to [us] so we can go out of bounds
|
||||
min_ts_us = np.datetime64(Timestamp.min).astype("M8[us]") + one_us
|
||||
max_ts_us = np.datetime64(Timestamp.max).astype("M8[us]")
|
||||
|
||||
# No error for the min/max datetimes
|
||||
Timestamp(min_ts_us)
|
||||
Timestamp(max_ts_us)
|
||||
|
||||
# We used to raise on these before supporting non-nano
|
||||
us_val = NpyDatetimeUnit.NPY_FR_us.value
|
||||
assert Timestamp(min_ts_us - one_us)._creso == us_val
|
||||
assert Timestamp(max_ts_us + one_us)._creso == us_val
|
||||
|
||||
# https://github.com/numpy/numpy/issues/22346 for why
|
||||
# we can't use the same construction as above with minute resolution
|
||||
|
||||
# too_low, too_high are the _just_ outside the range of M8[s]
|
||||
too_low = np.datetime64("-292277022657-01-27T08:29", "m")
|
||||
too_high = np.datetime64("292277026596-12-04T15:31", "m")
|
||||
|
||||
msg = "Out of bounds"
|
||||
# One us less than the minimum is an error
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(too_low)
|
||||
|
||||
# One us more than the maximum is an error
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(too_high)
|
||||
|
||||
def test_out_of_bounds_string(self):
|
||||
msg = "Cannot cast .* to unit='ns' without overflow"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp("1676-01-01").as_unit("ns")
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp("2263-01-01").as_unit("ns")
|
||||
|
||||
ts = Timestamp("2263-01-01")
|
||||
assert ts.unit == "s"
|
||||
|
||||
ts = Timestamp("1676-01-01")
|
||||
assert ts.unit == "s"
|
||||
|
||||
def test_barely_out_of_bounds(self):
|
||||
# GH#19529
|
||||
# GH#19382 close enough to bounds that dropping nanos would result
|
||||
# in an in-bounds datetime
|
||||
msg = "Out of bounds nanosecond timestamp: 2262-04-11 23:47:16"
|
||||
with pytest.raises(OutOfBoundsDatetime, match=msg):
|
||||
Timestamp("2262-04-11 23:47:16.854775808")
|
||||
|
||||
def test_bounds_with_different_units(self):
|
||||
out_of_bounds_dates = ("1677-09-21", "2262-04-12")
|
||||
|
||||
time_units = ("D", "h", "m", "s", "ms", "us")
|
||||
|
||||
for date_string in out_of_bounds_dates:
|
||||
for unit in time_units:
|
||||
dt64 = np.datetime64(date_string, unit)
|
||||
ts = Timestamp(dt64)
|
||||
if unit in ["s", "ms", "us"]:
|
||||
# We can preserve the input unit
|
||||
assert ts._value == dt64.view("i8")
|
||||
else:
|
||||
# we chose the closest unit that we _do_ support
|
||||
assert ts._creso == NpyDatetimeUnit.NPY_FR_s.value
|
||||
|
||||
# With more extreme cases, we can't even fit inside second resolution
|
||||
info = np.iinfo(np.int64)
|
||||
msg = "Out of bounds nanosecond timestamp:"
|
||||
for value in [info.min + 1, info.max]:
|
||||
for unit in ["D", "h", "m"]:
|
||||
dt64 = np.datetime64(value, unit)
|
||||
with pytest.raises(OutOfBoundsDatetime, match=msg):
|
||||
Timestamp(dt64)
|
||||
|
||||
in_bounds_dates = ("1677-09-23", "2262-04-11")
|
||||
|
||||
for date_string in in_bounds_dates:
|
||||
for unit in time_units:
|
||||
dt64 = np.datetime64(date_string, unit)
|
||||
Timestamp(dt64)
|
||||
|
||||
@pytest.mark.parametrize("arg", ["001-01-01", "0001-01-01"])
|
||||
def test_out_of_bounds_string_consistency(self, arg):
|
||||
# GH 15829
|
||||
msg = "Cannot cast 0001-01-01 00:00:00 to unit='ns' without overflow"
|
||||
with pytest.raises(OutOfBoundsDatetime, match=msg):
|
||||
Timestamp(arg).as_unit("ns")
|
||||
|
||||
ts = Timestamp(arg)
|
||||
assert ts.unit == "s"
|
||||
assert ts.year == ts.month == ts.day == 1
|
||||
|
||||
def test_min_valid(self):
|
||||
# Ensure that Timestamp.min is a valid Timestamp
|
||||
Timestamp(Timestamp.min)
|
||||
|
||||
def test_max_valid(self):
|
||||
# Ensure that Timestamp.max is a valid Timestamp
|
||||
Timestamp(Timestamp.max)
|
||||
|
||||
def test_now(self):
|
||||
# GH#9000
|
||||
ts_from_string = Timestamp("now")
|
||||
ts_from_method = Timestamp.now()
|
||||
ts_datetime = datetime.now()
|
||||
|
||||
ts_from_string_tz = Timestamp("now", tz="US/Eastern")
|
||||
ts_from_method_tz = Timestamp.now(tz="US/Eastern")
|
||||
|
||||
# Check that the delta between the times is less than 1s (arbitrarily
|
||||
# small)
|
||||
delta = Timedelta(seconds=1)
|
||||
assert abs(ts_from_method - ts_from_string) < delta
|
||||
assert abs(ts_datetime - ts_from_method) < delta
|
||||
assert abs(ts_from_method_tz - ts_from_string_tz) < delta
|
||||
assert (
|
||||
abs(
|
||||
ts_from_string_tz.tz_localize(None)
|
||||
- ts_from_method_tz.tz_localize(None)
|
||||
)
|
||||
< delta
|
||||
)
|
||||
|
||||
def test_today(self):
|
||||
ts_from_string = Timestamp("today")
|
||||
ts_from_method = Timestamp.today()
|
||||
ts_datetime = datetime.today()
|
||||
|
||||
ts_from_string_tz = Timestamp("today", tz="US/Eastern")
|
||||
ts_from_method_tz = Timestamp.today(tz="US/Eastern")
|
||||
|
||||
# Check that the delta between the times is less than 1s (arbitrarily
|
||||
# small)
|
||||
delta = Timedelta(seconds=1)
|
||||
assert abs(ts_from_method - ts_from_string) < delta
|
||||
assert abs(ts_datetime - ts_from_method) < delta
|
||||
assert abs(ts_from_method_tz - ts_from_string_tz) < delta
|
||||
assert (
|
||||
abs(
|
||||
ts_from_string_tz.tz_localize(None)
|
||||
- ts_from_method_tz.tz_localize(None)
|
||||
)
|
||||
< delta
|
||||
)
|
||||
|
||||
@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
|
||||
|
||||
@pytest.mark.parametrize("offset", ["+0300", "+0200"])
|
||||
def test_construct_timestamp_near_dst(self, offset):
|
||||
# GH 20854
|
||||
expected = Timestamp(f"2016-10-30 03:00:00{offset}", tz="Europe/Helsinki")
|
||||
result = Timestamp(expected).tz_convert("Europe/Helsinki")
|
||||
assert result == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"arg", ["2013/01/01 00:00:00+09:00", "2013-01-01 00:00:00+09:00"]
|
||||
)
|
||||
def test_construct_with_different_string_format(self, arg):
|
||||
# GH 12064
|
||||
result = Timestamp(arg)
|
||||
expected = Timestamp(datetime(2013, 1, 1), tz=pytz.FixedOffset(540))
|
||||
assert result == expected
|
||||
|
||||
@pytest.mark.parametrize("box", [datetime, Timestamp])
|
||||
def test_raise_tz_and_tzinfo_in_datetime_input(self, box):
|
||||
# GH 23579
|
||||
kwargs = {"year": 2018, "month": 1, "day": 1, "tzinfo": pytz.utc}
|
||||
msg = "Cannot pass a datetime or Timestamp"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(box(**kwargs), tz="US/Pacific")
|
||||
msg = "Cannot pass a datetime or Timestamp"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(box(**kwargs), tzinfo=pytz.timezone("US/Pacific"))
|
||||
|
||||
def test_dont_convert_dateutil_utc_to_pytz_utc(self):
|
||||
result = Timestamp(datetime(2018, 1, 1), tz=tzutc())
|
||||
expected = Timestamp(datetime(2018, 1, 1)).tz_localize(tzutc())
|
||||
assert result == expected
|
||||
|
||||
def test_constructor_subclassed_datetime(self):
|
||||
# GH 25851
|
||||
# ensure that subclassed datetime works for
|
||||
# Timestamp creation
|
||||
class SubDatetime(datetime):
|
||||
pass
|
||||
|
||||
data = SubDatetime(2000, 1, 1)
|
||||
result = Timestamp(data)
|
||||
expected = Timestamp(2000, 1, 1)
|
||||
assert result == expected
|
||||
|
||||
def test_constructor_fromisocalendar(self):
|
||||
# GH 30395
|
||||
expected_timestamp = Timestamp("2000-01-03 00:00:00")
|
||||
expected_stdlib = datetime.fromisocalendar(2000, 1, 1)
|
||||
result = Timestamp.fromisocalendar(2000, 1, 1)
|
||||
assert result == expected_timestamp
|
||||
assert result == expected_stdlib
|
||||
assert isinstance(result, Timestamp)
|
||||
|
||||
|
||||
def test_constructor_ambiguous_dst():
|
||||
# GH 24329
|
||||
# Make sure that calling Timestamp constructor
|
||||
# on Timestamp created from ambiguous time
|
||||
# doesn't change Timestamp.value
|
||||
ts = Timestamp(1382835600000000000, tz="dateutil/Europe/London")
|
||||
expected = ts._value
|
||||
result = Timestamp(ts)._value
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("epoch", [1552211999999999872, 1552211999999999999])
|
||||
def test_constructor_before_dst_switch(epoch):
|
||||
# GH 31043
|
||||
# Make sure that calling Timestamp constructor
|
||||
# on time just before DST switch doesn't lead to
|
||||
# nonexistent time or value change
|
||||
ts = Timestamp(epoch, tz="dateutil/America/Los_Angeles")
|
||||
result = ts.tz.dst(ts)
|
||||
expected = timedelta(seconds=0)
|
||||
assert Timestamp(ts)._value == epoch
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_timestamp_constructor_identity():
|
||||
# Test for #30543
|
||||
expected = Timestamp("2017-01-01T12")
|
||||
result = Timestamp(expected)
|
||||
assert result is expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kwargs", [{}, {"year": 2020}, {"year": 2020, "month": 1}])
|
||||
def test_constructor_missing_keyword(kwargs):
|
||||
# GH 31200
|
||||
|
||||
# The exact error message of datetime() depends on its version
|
||||
msg1 = r"function missing required argument '(year|month|day)' \(pos [123]\)"
|
||||
msg2 = r"Required argument '(year|month|day)' \(pos [123]\) not found"
|
||||
msg = "|".join([msg1, msg2])
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
Timestamp(**kwargs)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("nano", [-1, 1000])
|
||||
def test_timestamp_nano_range(nano):
|
||||
# GH 48255
|
||||
with pytest.raises(ValueError, match="nanosecond must be in 0..999"):
|
||||
Timestamp(year=2022, month=1, day=1, nanosecond=nano)
|
||||
|
||||
|
||||
def test_non_nano_value():
|
||||
# https://github.com/pandas-dev/pandas/issues/49076
|
||||
result = Timestamp("1800-01-01", unit="s").value
|
||||
# `.value` shows nanoseconds, even though unit is 's'
|
||||
assert result == -5364662400000000000
|
||||
|
||||
# out-of-nanoseconds-bounds `.value` raises informative message
|
||||
msg = (
|
||||
r"Cannot convert Timestamp to nanoseconds without overflow. "
|
||||
r"Use `.asm8.view\('i8'\)` to cast represent Timestamp in its "
|
||||
r"own unit \(here, s\).$"
|
||||
)
|
||||
ts = Timestamp("0300-01-01")
|
||||
with pytest.raises(OverflowError, match=msg):
|
||||
ts.value
|
||||
# check that the suggested workaround actually works
|
||||
result = ts.asm8.view("i8")
|
||||
assert result == -52700112000
|
||||
|
||||
|
||||
def test_timestamp_constructor_invalid_fold_raise():
|
||||
# Test forGH #25057
|
||||
# Valid fold values are only [None, 0, 1]
|
||||
msg = "Valid values for the fold argument are None, 0, or 1."
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(123, fold=2)
|
||||
|
||||
|
||||
def test_timestamp_constructor_pytz_fold_raise():
|
||||
# Test for GH#25057
|
||||
# pytz doesn't support fold. Check that we raise
|
||||
# if fold is passed with pytz
|
||||
msg = "pytz timezones do not support fold. Please use dateutil timezones."
|
||||
tz = pytz.timezone("Europe/London")
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(datetime(2019, 10, 27, 0, 30, 0, 0), tz=tz, fold=0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("fold", [0, 1])
|
||||
@pytest.mark.parametrize(
|
||||
"ts_input",
|
||||
[
|
||||
1572136200000000000,
|
||||
1572136200000000000.0,
|
||||
np.datetime64(1572136200000000000, "ns"),
|
||||
"2019-10-27 01:30:00+01:00",
|
||||
datetime(2019, 10, 27, 0, 30, 0, 0, tzinfo=timezone.utc),
|
||||
],
|
||||
)
|
||||
def test_timestamp_constructor_fold_conflict(ts_input, fold):
|
||||
# Test for GH#25057
|
||||
# Check that we raise on fold conflict
|
||||
msg = (
|
||||
"Cannot pass fold with possibly unambiguous input: int, float, "
|
||||
"numpy.datetime64, str, or timezone-aware datetime-like. "
|
||||
"Pass naive datetime-like or build Timestamp from components."
|
||||
)
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timestamp(ts_input=ts_input, fold=fold)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tz", ["dateutil/Europe/London", None])
|
||||
@pytest.mark.parametrize("fold", [0, 1])
|
||||
def test_timestamp_constructor_retain_fold(tz, fold):
|
||||
# Test for GH#25057
|
||||
# Check that we retain fold
|
||||
ts = Timestamp(year=2019, month=10, day=27, hour=1, minute=30, tz=tz, fold=fold)
|
||||
result = ts.fold
|
||||
expected = fold
|
||||
assert result == expected
|
||||
|
||||
|
||||
try:
|
||||
_tzs = [
|
||||
"dateutil/Europe/London",
|
||||
zoneinfo.ZoneInfo("Europe/London"),
|
||||
]
|
||||
except zoneinfo.ZoneInfoNotFoundError:
|
||||
_tzs = ["dateutil/Europe/London"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tz", _tzs)
|
||||
@pytest.mark.parametrize(
|
||||
"ts_input,fold_out",
|
||||
[
|
||||
(1572136200000000000, 0),
|
||||
(1572139800000000000, 1),
|
||||
("2019-10-27 01:30:00+01:00", 0),
|
||||
("2019-10-27 01:30:00+00:00", 1),
|
||||
(datetime(2019, 10, 27, 1, 30, 0, 0, fold=0), 0),
|
||||
(datetime(2019, 10, 27, 1, 30, 0, 0, fold=1), 1),
|
||||
],
|
||||
)
|
||||
def test_timestamp_constructor_infer_fold_from_value(tz, ts_input, fold_out):
|
||||
# Test for GH#25057
|
||||
# Check that we infer fold correctly based on timestamps since utc
|
||||
# or strings
|
||||
ts = Timestamp(ts_input, tz=tz)
|
||||
result = ts.fold
|
||||
expected = fold_out
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tz", ["dateutil/Europe/London"])
|
||||
@pytest.mark.parametrize(
|
||||
"ts_input,fold,value_out",
|
||||
[
|
||||
(datetime(2019, 10, 27, 1, 30, 0, 0), 0, 1572136200000000),
|
||||
(datetime(2019, 10, 27, 1, 30, 0, 0), 1, 1572139800000000),
|
||||
],
|
||||
)
|
||||
def test_timestamp_constructor_adjust_value_for_fold(tz, ts_input, fold, value_out):
|
||||
# Test for GH#25057
|
||||
# Check that we adjust value for fold correctly
|
||||
# based on timestamps since utc
|
||||
ts = Timestamp(ts_input, tz=tz, fold=fold)
|
||||
result = ts._value
|
||||
expected = value_out
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("na_value", [None, np.nan, np.datetime64("NaT"), NaT, NA])
|
||||
def test_timestamp_constructor_na_value(na_value):
|
||||
# GH45481
|
||||
result = Timestamp(na_value)
|
||||
expected = NaT
|
||||
assert result is expected
|
@@ -0,0 +1,82 @@
|
||||
import pytest
|
||||
|
||||
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
|
@@ -0,0 +1,82 @@
|
||||
import pprint
|
||||
|
||||
import pytest
|
||||
import pytz # noqa: F401 # a test below uses pytz but only inside a `eval` call
|
||||
|
||||
from pandas import Timestamp
|
||||
|
||||
|
||||
class TestTimestampRendering:
|
||||
timezones = ["UTC", "Asia/Tokyo", "US/Eastern", "dateutil/US/Pacific"]
|
||||
|
||||
@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
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,494 @@
|
||||
"""
|
||||
Tests for Timestamp timezone-related methods
|
||||
"""
|
||||
from datetime import (
|
||||
date,
|
||||
datetime,
|
||||
timedelta,
|
||||
timezone,
|
||||
)
|
||||
import re
|
||||
|
||||
import dateutil
|
||||
from dateutil.tz import (
|
||||
gettz,
|
||||
tzoffset,
|
||||
)
|
||||
import pytest
|
||||
import pytz
|
||||
from pytz.exceptions import (
|
||||
AmbiguousTimeError,
|
||||
NonExistentTimeError,
|
||||
)
|
||||
|
||||
from pandas._libs.tslibs import timezones
|
||||
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
|
||||
from pandas.errors import OutOfBoundsDatetime
|
||||
import pandas.util._test_decorators as td
|
||||
|
||||
from pandas import (
|
||||
NaT,
|
||||
Timestamp,
|
||||
)
|
||||
|
||||
try:
|
||||
from zoneinfo import ZoneInfo
|
||||
except ImportError:
|
||||
# Cannot assign to a type
|
||||
ZoneInfo = None # type: ignore[misc, assignment]
|
||||
|
||||
|
||||
class TestTimestampTZOperations:
|
||||
# --------------------------------------------------------------
|
||||
# Timestamp.tz_localize
|
||||
|
||||
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
|
||||
|
||||
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")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Timestamp.tz_convert
|
||||
|
||||
@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)
|
||||
|
||||
@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)
|
||||
|
||||
@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())
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Timestamp.__init__ with tz str or tzinfo
|
||||
|
||||
def test_timestamp_constructor_tz_utc(self):
|
||||
utc_stamp = Timestamp("3/11/2012 05:00", tz="utc")
|
||||
assert utc_stamp.tzinfo is timezone.utc
|
||||
assert utc_stamp.hour == 5
|
||||
|
||||
utc_stamp = Timestamp("3/11/2012 05:00").tz_localize("utc")
|
||||
assert utc_stamp.hour == 5
|
||||
|
||||
def test_timestamp_to_datetime_tzoffset(self):
|
||||
tzinfo = tzoffset(None, 7200)
|
||||
expected = Timestamp("3/11/2012 04:00", tz=tzinfo)
|
||||
result = Timestamp(expected.to_pydatetime())
|
||||
assert expected == result
|
||||
|
||||
def test_timestamp_constructor_near_dst_boundary(self):
|
||||
# GH#11481 & GH#15777
|
||||
# Naive string timestamps were being localized incorrectly
|
||||
# with tz_convert_from_utc_single instead of tz_localize_to_utc
|
||||
|
||||
for tz in ["Europe/Brussels", "Europe/Prague"]:
|
||||
result = Timestamp("2015-10-25 01:00", tz=tz)
|
||||
expected = Timestamp("2015-10-25 01:00").tz_localize(tz)
|
||||
assert result == expected
|
||||
|
||||
msg = "Cannot infer dst time from 2015-10-25 02:00:00"
|
||||
with pytest.raises(pytz.AmbiguousTimeError, match=msg):
|
||||
Timestamp("2015-10-25 02:00", tz=tz)
|
||||
|
||||
result = Timestamp("2017-03-26 01:00", tz="Europe/Paris")
|
||||
expected = Timestamp("2017-03-26 01:00").tz_localize("Europe/Paris")
|
||||
assert result == expected
|
||||
|
||||
msg = "2017-03-26 02:00"
|
||||
with pytest.raises(pytz.NonExistentTimeError, match=msg):
|
||||
Timestamp("2017-03-26 02:00", tz="Europe/Paris")
|
||||
|
||||
# GH#11708
|
||||
naive = Timestamp("2015-11-18 10:00:00")
|
||||
result = naive.tz_localize("UTC").tz_convert("Asia/Kolkata")
|
||||
expected = Timestamp("2015-11-18 15:30:00+0530", tz="Asia/Kolkata")
|
||||
assert result == expected
|
||||
|
||||
# GH#15823
|
||||
result = Timestamp("2017-03-26 00:00", tz="Europe/Paris")
|
||||
expected = Timestamp("2017-03-26 00:00:00+0100", tz="Europe/Paris")
|
||||
assert result == expected
|
||||
|
||||
result = Timestamp("2017-03-26 01:00", tz="Europe/Paris")
|
||||
expected = Timestamp("2017-03-26 01:00:00+0100", tz="Europe/Paris")
|
||||
assert result == expected
|
||||
|
||||
msg = "2017-03-26 02:00"
|
||||
with pytest.raises(pytz.NonExistentTimeError, match=msg):
|
||||
Timestamp("2017-03-26 02:00", tz="Europe/Paris")
|
||||
|
||||
result = Timestamp("2017-03-26 02:00:00+0100", tz="Europe/Paris")
|
||||
naive = Timestamp(result.as_unit("ns")._value)
|
||||
expected = naive.tz_localize("UTC").tz_convert("Europe/Paris")
|
||||
assert result == expected
|
||||
|
||||
result = Timestamp("2017-03-26 03:00", tz="Europe/Paris")
|
||||
expected = Timestamp("2017-03-26 03:00:00+0200", tz="Europe/Paris")
|
||||
assert result == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"tz",
|
||||
[
|
||||
pytz.timezone("US/Eastern"),
|
||||
gettz("US/Eastern"),
|
||||
"US/Eastern",
|
||||
"dateutil/US/Eastern",
|
||||
],
|
||||
)
|
||||
def test_timestamp_constructed_by_date_and_tz(self, tz):
|
||||
# GH#2993, Timestamp cannot be constructed by datetime.date
|
||||
# and tz correctly
|
||||
|
||||
result = Timestamp(date(2012, 3, 11), tz=tz)
|
||||
|
||||
expected = Timestamp("3/11/2012", tz=tz)
|
||||
assert result.hour == expected.hour
|
||||
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
|
||||
|
||||
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
|
@@ -0,0 +1,609 @@
|
||||
from datetime import datetime
|
||||
|
||||
from dateutil.tz import gettz
|
||||
from hypothesis import (
|
||||
given,
|
||||
strategies as st,
|
||||
)
|
||||
import numpy as np
|
||||
import pytest
|
||||
import pytz
|
||||
from pytz import utc
|
||||
|
||||
from pandas._libs import lib
|
||||
from pandas._libs.tslibs import (
|
||||
NaT,
|
||||
OutOfBoundsDatetime,
|
||||
Timedelta,
|
||||
Timestamp,
|
||||
conversion,
|
||||
iNaT,
|
||||
to_offset,
|
||||
)
|
||||
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
|
||||
from pandas._libs.tslibs.period import INVALID_FREQ_ERR_MSG
|
||||
import pandas.util._test_decorators as td
|
||||
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
class TestTimestampUnaryOps:
|
||||
# --------------------------------------------------------------
|
||||
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")
|
||||
|
||||
# Timestamp.round
|
||||
@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", "2T", "2018-01-01 00:02:00"),
|
||||
("2018-01-01 00:04:00", "4T", "2018-01-01 00:04:00"),
|
||||
("2018-01-01 00:15:00", "15T", "2018-01-01 00:15:00"),
|
||||
("2018-01-01 00:20:00", "20T", "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")
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# Timestamp.replace
|
||||
|
||||
def test_replace_out_of_pydatetime_bounds(self):
|
||||
# GH#50348
|
||||
ts = Timestamp("2016-01-01").as_unit("ns")
|
||||
|
||||
msg = "Out of bounds nanosecond timestamp: 99999-01-01 00:00:00"
|
||||
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
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# Timestamp.normalize
|
||||
|
||||
@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
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
@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()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("fold", [0, 1])
|
||||
def test_replace_preserves_fold(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
|
Reference in New Issue
Block a user