Updated script that can be controled by Nodejs web app
This commit is contained in:
@ -0,0 +1,69 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
Period,
|
||||
to_offset,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,exp_freqstr",
|
||||
[("D", "D"), ("W", "D"), ("ME", "D"), ("s", "s"), ("min", "s"), ("h", "s")],
|
||||
)
|
||||
def test_get_to_timestamp_base(freqstr, exp_freqstr):
|
||||
off = to_offset(freqstr)
|
||||
per = Period._from_ordinal(1, off)
|
||||
exp_code = to_offset(exp_freqstr)._period_dtype_code
|
||||
|
||||
result_code = per._dtype._get_to_timestamp_base()
|
||||
assert result_code == exp_code
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"args,expected",
|
||||
[
|
||||
((1.5, "min"), (90, "s")),
|
||||
((62.4, "min"), (3744, "s")),
|
||||
((1.04, "h"), (3744, "s")),
|
||||
((1, "D"), (1, "D")),
|
||||
((0.342931, "h"), (1234551600, "us")),
|
||||
((1.2345, "D"), (106660800, "ms")),
|
||||
],
|
||||
)
|
||||
def test_resolution_bumping(args, expected):
|
||||
# see gh-14378
|
||||
off = to_offset(str(args[0]) + args[1])
|
||||
assert off.n == expected[0]
|
||||
assert off._prefix == expected[1]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"args",
|
||||
[
|
||||
(0.5, "ns"),
|
||||
# Too much precision in the input can prevent.
|
||||
(0.3429324798798269273987982, "h"),
|
||||
],
|
||||
)
|
||||
def test_cat(args):
|
||||
msg = "Invalid frequency"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
to_offset(str(args[0]) + args[1])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected",
|
||||
[
|
||||
("1h", "2021-01-01T09:00:00"),
|
||||
("1D", "2021-01-02T08:00:00"),
|
||||
("1W", "2021-01-03T08:00:00"),
|
||||
("1ME", "2021-01-31T08:00:00"),
|
||||
("1YE", "2021-12-31T08:00:00"),
|
||||
],
|
||||
)
|
||||
def test_compatibility(freqstr, expected):
|
||||
ts_np = np.datetime64("2021-01-01T08:00:00.00")
|
||||
do = to_offset(freqstr)
|
||||
assert ts_np + do == np.datetime64(expected)
|
@ -0,0 +1,29 @@
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import offsets
|
||||
|
||||
from pandas.tseries.frequencies import (
|
||||
is_subperiod,
|
||||
is_superperiod,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"p1,p2,expected",
|
||||
[
|
||||
# Input validation.
|
||||
(offsets.MonthEnd(), None, False),
|
||||
(offsets.YearEnd(), None, False),
|
||||
(None, offsets.YearEnd(), False),
|
||||
(None, offsets.MonthEnd(), False),
|
||||
(None, None, False),
|
||||
(offsets.YearEnd(), offsets.MonthEnd(), True),
|
||||
(offsets.Hour(), offsets.Minute(), True),
|
||||
(offsets.Second(), offsets.Milli(), True),
|
||||
(offsets.Milli(), offsets.Micro(), True),
|
||||
(offsets.Micro(), offsets.Nano(), True),
|
||||
],
|
||||
)
|
||||
def test_super_sub_symmetry(p1, p2, expected):
|
||||
assert is_superperiod(p1, p2) is expected
|
||||
assert is_subperiod(p2, p1) is expected
|
@ -0,0 +1,558 @@
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.ccalendar import (
|
||||
DAYS,
|
||||
MONTHS,
|
||||
)
|
||||
from pandas._libs.tslibs.offsets import _get_offset
|
||||
from pandas._libs.tslibs.period import INVALID_FREQ_ERR_MSG
|
||||
from pandas.compat import is_platform_windows
|
||||
|
||||
from pandas import (
|
||||
DatetimeIndex,
|
||||
Index,
|
||||
RangeIndex,
|
||||
Series,
|
||||
Timestamp,
|
||||
date_range,
|
||||
period_range,
|
||||
)
|
||||
import pandas._testing as tm
|
||||
from pandas.core.arrays import (
|
||||
DatetimeArray,
|
||||
TimedeltaArray,
|
||||
)
|
||||
from pandas.core.tools.datetimes import to_datetime
|
||||
|
||||
from pandas.tseries import (
|
||||
frequencies,
|
||||
offsets,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
params=[
|
||||
(timedelta(1), "D"),
|
||||
(timedelta(hours=1), "h"),
|
||||
(timedelta(minutes=1), "min"),
|
||||
(timedelta(seconds=1), "s"),
|
||||
(np.timedelta64(1, "ns"), "ns"),
|
||||
(timedelta(microseconds=1), "us"),
|
||||
(timedelta(microseconds=1000), "ms"),
|
||||
]
|
||||
)
|
||||
def base_delta_code_pair(request):
|
||||
return request.param
|
||||
|
||||
|
||||
freqs = (
|
||||
[f"QE-{month}" for month in MONTHS]
|
||||
+ [f"{annual}-{month}" for annual in ["YE", "BYE"] for month in MONTHS]
|
||||
+ ["ME", "BME", "BMS"]
|
||||
+ [f"WOM-{count}{day}" for count in range(1, 5) for day in DAYS]
|
||||
+ [f"W-{day}" for day in DAYS]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", freqs)
|
||||
@pytest.mark.parametrize("periods", [5, 7])
|
||||
def test_infer_freq_range(periods, freq):
|
||||
freq = freq.upper()
|
||||
|
||||
gen = date_range("1/1/2000", periods=periods, freq=freq)
|
||||
index = DatetimeIndex(gen.values)
|
||||
|
||||
if not freq.startswith("QE-"):
|
||||
assert frequencies.infer_freq(index) == gen.freqstr
|
||||
else:
|
||||
inf_freq = frequencies.infer_freq(index)
|
||||
is_dec_range = inf_freq == "QE-DEC" and gen.freqstr in (
|
||||
"QE",
|
||||
"QE-DEC",
|
||||
"QE-SEP",
|
||||
"QE-JUN",
|
||||
"QE-MAR",
|
||||
)
|
||||
is_nov_range = inf_freq == "QE-NOV" and gen.freqstr in (
|
||||
"QE-NOV",
|
||||
"QE-AUG",
|
||||
"QE-MAY",
|
||||
"QE-FEB",
|
||||
)
|
||||
is_oct_range = inf_freq == "QE-OCT" and gen.freqstr in (
|
||||
"QE-OCT",
|
||||
"QE-JUL",
|
||||
"QE-APR",
|
||||
"QE-JAN",
|
||||
)
|
||||
assert is_dec_range or is_nov_range or is_oct_range
|
||||
|
||||
|
||||
def test_raise_if_period_index():
|
||||
index = period_range(start="1/1/1990", periods=20, freq="M")
|
||||
msg = "Check the `freq` attribute instead of using infer_freq"
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
frequencies.infer_freq(index)
|
||||
|
||||
|
||||
def test_raise_if_too_few():
|
||||
index = DatetimeIndex(["12/31/1998", "1/3/1999"])
|
||||
msg = "Need at least 3 dates to infer frequency"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
frequencies.infer_freq(index)
|
||||
|
||||
|
||||
def test_business_daily():
|
||||
index = DatetimeIndex(["01/01/1999", "1/4/1999", "1/5/1999"])
|
||||
assert frequencies.infer_freq(index) == "B"
|
||||
|
||||
|
||||
def test_business_daily_look_alike():
|
||||
# see gh-16624
|
||||
#
|
||||
# Do not infer "B when "weekend" (2-day gap) in wrong place.
|
||||
index = DatetimeIndex(["12/31/1998", "1/3/1999", "1/4/1999"])
|
||||
assert frequencies.infer_freq(index) is None
|
||||
|
||||
|
||||
def test_day_corner():
|
||||
index = DatetimeIndex(["1/1/2000", "1/2/2000", "1/3/2000"])
|
||||
assert frequencies.infer_freq(index) == "D"
|
||||
|
||||
|
||||
def test_non_datetime_index():
|
||||
dates = to_datetime(["1/1/2000", "1/2/2000", "1/3/2000"])
|
||||
assert frequencies.infer_freq(dates) == "D"
|
||||
|
||||
|
||||
def test_fifth_week_of_month_infer():
|
||||
# see gh-9425
|
||||
#
|
||||
# Only attempt to infer up to WOM-4.
|
||||
index = DatetimeIndex(["2014-03-31", "2014-06-30", "2015-03-30"])
|
||||
assert frequencies.infer_freq(index) is None
|
||||
|
||||
|
||||
def test_week_of_month_fake():
|
||||
# All of these dates are on same day
|
||||
# of week and are 4 or 5 weeks apart.
|
||||
index = DatetimeIndex(["2013-08-27", "2013-10-01", "2013-10-29", "2013-11-26"])
|
||||
assert frequencies.infer_freq(index) != "WOM-4TUE"
|
||||
|
||||
|
||||
def test_fifth_week_of_month():
|
||||
# see gh-9425
|
||||
#
|
||||
# Only supports freq up to WOM-4.
|
||||
msg = (
|
||||
"Of the four parameters: start, end, periods, "
|
||||
"and freq, exactly three must be specified"
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
date_range("2014-01-01", freq="WOM-5MON")
|
||||
|
||||
|
||||
def test_monthly_ambiguous():
|
||||
rng = DatetimeIndex(["1/31/2000", "2/29/2000", "3/31/2000"])
|
||||
assert rng.inferred_freq == "ME"
|
||||
|
||||
|
||||
def test_annual_ambiguous():
|
||||
rng = DatetimeIndex(["1/31/2000", "1/31/2001", "1/31/2002"])
|
||||
assert rng.inferred_freq == "YE-JAN"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", range(1, 5))
|
||||
def test_infer_freq_delta(base_delta_code_pair, count):
|
||||
b = Timestamp(datetime.now())
|
||||
base_delta, code = base_delta_code_pair
|
||||
|
||||
inc = base_delta * count
|
||||
index = DatetimeIndex([b + inc * j for j in range(3)])
|
||||
|
||||
exp_freq = f"{count:d}{code}" if count > 1 else code
|
||||
assert frequencies.infer_freq(index) == exp_freq
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"constructor",
|
||||
[
|
||||
lambda now, delta: DatetimeIndex(
|
||||
[now + delta * 7] + [now + delta * j for j in range(3)]
|
||||
),
|
||||
lambda now, delta: DatetimeIndex(
|
||||
[now + delta * j for j in range(3)] + [now + delta * 7]
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_infer_freq_custom(base_delta_code_pair, constructor):
|
||||
b = Timestamp(datetime.now())
|
||||
base_delta, _ = base_delta_code_pair
|
||||
|
||||
index = constructor(b, base_delta)
|
||||
assert frequencies.infer_freq(index) is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freq,expected", [("Q", "QE-DEC"), ("Q-NOV", "QE-NOV"), ("Q-OCT", "QE-OCT")]
|
||||
)
|
||||
def test_infer_freq_index(freq, expected):
|
||||
rng = period_range("1959Q2", "2009Q3", freq=freq)
|
||||
with tm.assert_produces_warning(FutureWarning, match="Dtype inference"):
|
||||
rng = Index(rng.to_timestamp("D", how="e").astype(object))
|
||||
|
||||
assert rng.inferred_freq == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected,dates",
|
||||
list(
|
||||
{
|
||||
"YS-JAN": ["2009-01-01", "2010-01-01", "2011-01-01", "2012-01-01"],
|
||||
"QE-OCT": ["2009-01-31", "2009-04-30", "2009-07-31", "2009-10-31"],
|
||||
"ME": ["2010-11-30", "2010-12-31", "2011-01-31", "2011-02-28"],
|
||||
"W-SAT": ["2010-12-25", "2011-01-01", "2011-01-08", "2011-01-15"],
|
||||
"D": ["2011-01-01", "2011-01-02", "2011-01-03", "2011-01-04"],
|
||||
"h": [
|
||||
"2011-12-31 22:00",
|
||||
"2011-12-31 23:00",
|
||||
"2012-01-01 00:00",
|
||||
"2012-01-01 01:00",
|
||||
],
|
||||
}.items()
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize("unit", ["s", "ms", "us", "ns"])
|
||||
def test_infer_freq_tz(tz_naive_fixture, expected, dates, unit):
|
||||
# see gh-7310, GH#55609
|
||||
tz = tz_naive_fixture
|
||||
idx = DatetimeIndex(dates, tz=tz).as_unit(unit)
|
||||
assert idx.inferred_freq == expected
|
||||
|
||||
|
||||
def test_infer_freq_tz_series(tz_naive_fixture):
|
||||
# infer_freq should work with both tz-naive and tz-aware series. See gh-52456
|
||||
tz = tz_naive_fixture
|
||||
idx = date_range("2021-01-01", "2021-01-04", tz=tz)
|
||||
series = idx.to_series().reset_index(drop=True)
|
||||
inferred_freq = frequencies.infer_freq(series)
|
||||
assert inferred_freq == "D"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_pair",
|
||||
[
|
||||
["2013-11-02", "2013-11-5"], # Fall DST
|
||||
["2014-03-08", "2014-03-11"], # Spring DST
|
||||
["2014-01-01", "2014-01-03"], # Regular Time
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"freq",
|
||||
["h", "3h", "10min", "3601s", "3600001ms", "3600000001us", "3600000000001ns"],
|
||||
)
|
||||
def test_infer_freq_tz_transition(tz_naive_fixture, date_pair, freq):
|
||||
# see gh-8772
|
||||
tz = tz_naive_fixture
|
||||
idx = date_range(date_pair[0], date_pair[1], freq=freq, tz=tz)
|
||||
assert idx.inferred_freq == freq
|
||||
|
||||
|
||||
def test_infer_freq_tz_transition_custom():
|
||||
index = date_range("2013-11-03", periods=5, freq="3h").tz_localize(
|
||||
"America/Chicago"
|
||||
)
|
||||
assert index.inferred_freq is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data,expected",
|
||||
[
|
||||
# Hourly freq in a day must result in "h"
|
||||
(
|
||||
[
|
||||
"2014-07-01 09:00",
|
||||
"2014-07-01 10:00",
|
||||
"2014-07-01 11:00",
|
||||
"2014-07-01 12:00",
|
||||
"2014-07-01 13:00",
|
||||
"2014-07-01 14:00",
|
||||
],
|
||||
"h",
|
||||
),
|
||||
(
|
||||
[
|
||||
"2014-07-01 09:00",
|
||||
"2014-07-01 10:00",
|
||||
"2014-07-01 11:00",
|
||||
"2014-07-01 12:00",
|
||||
"2014-07-01 13:00",
|
||||
"2014-07-01 14:00",
|
||||
"2014-07-01 15:00",
|
||||
"2014-07-01 16:00",
|
||||
"2014-07-02 09:00",
|
||||
"2014-07-02 10:00",
|
||||
"2014-07-02 11:00",
|
||||
],
|
||||
"bh",
|
||||
),
|
||||
(
|
||||
[
|
||||
"2014-07-04 09:00",
|
||||
"2014-07-04 10:00",
|
||||
"2014-07-04 11:00",
|
||||
"2014-07-04 12:00",
|
||||
"2014-07-04 13:00",
|
||||
"2014-07-04 14:00",
|
||||
"2014-07-04 15:00",
|
||||
"2014-07-04 16:00",
|
||||
"2014-07-07 09:00",
|
||||
"2014-07-07 10:00",
|
||||
"2014-07-07 11:00",
|
||||
],
|
||||
"bh",
|
||||
),
|
||||
(
|
||||
[
|
||||
"2014-07-04 09:00",
|
||||
"2014-07-04 10:00",
|
||||
"2014-07-04 11:00",
|
||||
"2014-07-04 12:00",
|
||||
"2014-07-04 13:00",
|
||||
"2014-07-04 14:00",
|
||||
"2014-07-04 15:00",
|
||||
"2014-07-04 16:00",
|
||||
"2014-07-07 09:00",
|
||||
"2014-07-07 10:00",
|
||||
"2014-07-07 11:00",
|
||||
"2014-07-07 12:00",
|
||||
"2014-07-07 13:00",
|
||||
"2014-07-07 14:00",
|
||||
"2014-07-07 15:00",
|
||||
"2014-07-07 16:00",
|
||||
"2014-07-08 09:00",
|
||||
"2014-07-08 10:00",
|
||||
"2014-07-08 11:00",
|
||||
"2014-07-08 12:00",
|
||||
"2014-07-08 13:00",
|
||||
"2014-07-08 14:00",
|
||||
"2014-07-08 15:00",
|
||||
"2014-07-08 16:00",
|
||||
],
|
||||
"bh",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_infer_freq_business_hour(data, expected):
|
||||
# see gh-7905
|
||||
idx = DatetimeIndex(data)
|
||||
assert idx.inferred_freq == expected
|
||||
|
||||
|
||||
def test_not_monotonic():
|
||||
rng = DatetimeIndex(["1/31/2000", "1/31/2001", "1/31/2002"])
|
||||
rng = rng[::-1]
|
||||
|
||||
assert rng.inferred_freq == "-1YE-JAN"
|
||||
|
||||
|
||||
def test_non_datetime_index2():
|
||||
rng = DatetimeIndex(["1/31/2000", "1/31/2001", "1/31/2002"])
|
||||
vals = rng.to_pydatetime()
|
||||
|
||||
result = frequencies.infer_freq(vals)
|
||||
assert result == rng.inferred_freq
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"idx",
|
||||
[
|
||||
Index(np.arange(5), dtype=np.int64),
|
||||
Index(np.arange(5), dtype=np.float64),
|
||||
period_range("2020-01-01", periods=5),
|
||||
RangeIndex(5),
|
||||
],
|
||||
)
|
||||
def test_invalid_index_types(idx):
|
||||
# see gh-48439
|
||||
msg = "|".join(
|
||||
[
|
||||
"cannot infer freq from a non-convertible",
|
||||
"Check the `freq` attribute instead of using infer_freq",
|
||||
]
|
||||
)
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
frequencies.infer_freq(idx)
|
||||
|
||||
|
||||
@pytest.mark.skipif(is_platform_windows(), reason="see gh-10822: Windows issue")
|
||||
def test_invalid_index_types_unicode():
|
||||
# see gh-10822
|
||||
#
|
||||
# Odd error message on conversions to datetime for unicode.
|
||||
msg = "Unknown datetime string format"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
frequencies.infer_freq(Index(["ZqgszYBfuL"]))
|
||||
|
||||
|
||||
def test_string_datetime_like_compat():
|
||||
# see gh-6463
|
||||
data = ["2004-01", "2004-02", "2004-03", "2004-04"]
|
||||
|
||||
expected = frequencies.infer_freq(data)
|
||||
result = frequencies.infer_freq(Index(data))
|
||||
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_series():
|
||||
# see gh-6407
|
||||
s = Series(date_range("20130101", "20130110"))
|
||||
inferred = frequencies.infer_freq(s)
|
||||
assert inferred == "D"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("end", [10, 10.0])
|
||||
def test_series_invalid_type(end):
|
||||
# see gh-6407
|
||||
msg = "cannot infer freq from a non-convertible dtype on a Series"
|
||||
s = Series(np.arange(end))
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
frequencies.infer_freq(s)
|
||||
|
||||
|
||||
def test_series_inconvertible_string(using_infer_string):
|
||||
# see gh-6407
|
||||
if using_infer_string:
|
||||
msg = "cannot infer freq from"
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
frequencies.infer_freq(Series(["foo", "bar"]))
|
||||
else:
|
||||
msg = "Unknown datetime string format"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
frequencies.infer_freq(Series(["foo", "bar"]))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", [None, "ms"])
|
||||
def test_series_period_index(freq):
|
||||
# see gh-6407
|
||||
#
|
||||
# Cannot infer on PeriodIndex
|
||||
msg = "cannot infer freq from a non-convertible dtype on a Series"
|
||||
s = Series(period_range("2013", periods=10, freq=freq))
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
frequencies.infer_freq(s)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", ["ME", "ms", "s"])
|
||||
def test_series_datetime_index(freq):
|
||||
s = Series(date_range("20130101", periods=10, freq=freq))
|
||||
inferred = frequencies.infer_freq(s)
|
||||
assert inferred == freq
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"offset_func",
|
||||
[
|
||||
_get_offset,
|
||||
lambda freq: date_range("2011-01-01", periods=5, freq=freq),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"freq",
|
||||
[
|
||||
"WEEKDAY",
|
||||
"EOM",
|
||||
"W@MON",
|
||||
"W@TUE",
|
||||
"W@WED",
|
||||
"W@THU",
|
||||
"W@FRI",
|
||||
"W@SAT",
|
||||
"W@SUN",
|
||||
"QE@JAN",
|
||||
"QE@FEB",
|
||||
"QE@MAR",
|
||||
"YE@JAN",
|
||||
"YE@FEB",
|
||||
"YE@MAR",
|
||||
"YE@APR",
|
||||
"YE@MAY",
|
||||
"YE@JUN",
|
||||
"YE@JUL",
|
||||
"YE@AUG",
|
||||
"YE@SEP",
|
||||
"YE@OCT",
|
||||
"YE@NOV",
|
||||
"YE@DEC",
|
||||
"YE@JAN",
|
||||
"WOM@1MON",
|
||||
"WOM@2MON",
|
||||
"WOM@3MON",
|
||||
"WOM@4MON",
|
||||
"WOM@1TUE",
|
||||
"WOM@2TUE",
|
||||
"WOM@3TUE",
|
||||
"WOM@4TUE",
|
||||
"WOM@1WED",
|
||||
"WOM@2WED",
|
||||
"WOM@3WED",
|
||||
"WOM@4WED",
|
||||
"WOM@1THU",
|
||||
"WOM@2THU",
|
||||
"WOM@3THU",
|
||||
"WOM@4THU",
|
||||
"WOM@1FRI",
|
||||
"WOM@2FRI",
|
||||
"WOM@3FRI",
|
||||
"WOM@4FRI",
|
||||
],
|
||||
)
|
||||
def test_legacy_offset_warnings(offset_func, freq):
|
||||
with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG):
|
||||
offset_func(freq)
|
||||
|
||||
|
||||
def test_ms_vs_capital_ms():
|
||||
left = _get_offset("ms")
|
||||
right = _get_offset("MS")
|
||||
|
||||
assert left == offsets.Milli()
|
||||
assert right == offsets.MonthBegin()
|
||||
|
||||
|
||||
def test_infer_freq_non_nano():
|
||||
arr = np.arange(10).astype(np.int64).view("M8[s]")
|
||||
dta = DatetimeArray._simple_new(arr, dtype=arr.dtype)
|
||||
res = frequencies.infer_freq(dta)
|
||||
assert res == "s"
|
||||
|
||||
arr2 = arr.view("m8[ms]")
|
||||
tda = TimedeltaArray._simple_new(arr2, dtype=arr2.dtype)
|
||||
res2 = frequencies.infer_freq(tda)
|
||||
assert res2 == "ms"
|
||||
|
||||
|
||||
def test_infer_freq_non_nano_tzaware(tz_aware_fixture):
|
||||
tz = tz_aware_fixture
|
||||
|
||||
dti = date_range("2016-01-01", periods=365, freq="B", tz=tz)
|
||||
dta = dti._data.as_unit("s")
|
||||
|
||||
res = frequencies.infer_freq(dta)
|
||||
assert res == "B"
|
@ -0,0 +1,119 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas import (
|
||||
DatetimeIndex,
|
||||
offsets,
|
||||
to_datetime,
|
||||
)
|
||||
import pandas._testing as tm
|
||||
|
||||
from pandas.tseries.holiday import (
|
||||
AbstractHolidayCalendar,
|
||||
Holiday,
|
||||
Timestamp,
|
||||
USFederalHolidayCalendar,
|
||||
USLaborDay,
|
||||
USThanksgivingDay,
|
||||
get_calendar,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"transform", [lambda x: x, lambda x: x.strftime("%Y-%m-%d"), lambda x: Timestamp(x)]
|
||||
)
|
||||
def test_calendar(transform):
|
||||
start_date = datetime(2012, 1, 1)
|
||||
end_date = datetime(2012, 12, 31)
|
||||
|
||||
calendar = USFederalHolidayCalendar()
|
||||
holidays = calendar.holidays(transform(start_date), transform(end_date))
|
||||
|
||||
expected = [
|
||||
datetime(2012, 1, 2),
|
||||
datetime(2012, 1, 16),
|
||||
datetime(2012, 2, 20),
|
||||
datetime(2012, 5, 28),
|
||||
datetime(2012, 7, 4),
|
||||
datetime(2012, 9, 3),
|
||||
datetime(2012, 10, 8),
|
||||
datetime(2012, 11, 12),
|
||||
datetime(2012, 11, 22),
|
||||
datetime(2012, 12, 25),
|
||||
]
|
||||
|
||||
assert list(holidays.to_pydatetime()) == expected
|
||||
|
||||
|
||||
def test_calendar_caching():
|
||||
# see gh-9552.
|
||||
|
||||
class TestCalendar(AbstractHolidayCalendar):
|
||||
def __init__(self, name=None, rules=None) -> None:
|
||||
super().__init__(name=name, rules=rules)
|
||||
|
||||
jan1 = TestCalendar(rules=[Holiday("jan1", year=2015, month=1, day=1)])
|
||||
jan2 = TestCalendar(rules=[Holiday("jan2", year=2015, month=1, day=2)])
|
||||
|
||||
# Getting holidays for Jan 1 should not alter results for Jan 2.
|
||||
expected = DatetimeIndex(["01-Jan-2015"]).as_unit("ns")
|
||||
tm.assert_index_equal(jan1.holidays(), expected)
|
||||
|
||||
expected2 = DatetimeIndex(["02-Jan-2015"]).as_unit("ns")
|
||||
tm.assert_index_equal(jan2.holidays(), expected2)
|
||||
|
||||
|
||||
def test_calendar_observance_dates():
|
||||
# see gh-11477
|
||||
us_fed_cal = get_calendar("USFederalHolidayCalendar")
|
||||
holidays0 = us_fed_cal.holidays(
|
||||
datetime(2015, 7, 3), datetime(2015, 7, 3)
|
||||
) # <-- same start and end dates
|
||||
holidays1 = us_fed_cal.holidays(
|
||||
datetime(2015, 7, 3), datetime(2015, 7, 6)
|
||||
) # <-- different start and end dates
|
||||
holidays2 = us_fed_cal.holidays(
|
||||
datetime(2015, 7, 3), datetime(2015, 7, 3)
|
||||
) # <-- same start and end dates
|
||||
|
||||
# These should all produce the same result.
|
||||
#
|
||||
# In addition, calling with different start and end
|
||||
# dates should not alter the output if we call the
|
||||
# function again with the same start and end date.
|
||||
tm.assert_index_equal(holidays0, holidays1)
|
||||
tm.assert_index_equal(holidays0, holidays2)
|
||||
|
||||
|
||||
def test_rule_from_name():
|
||||
us_fed_cal = get_calendar("USFederalHolidayCalendar")
|
||||
assert us_fed_cal.rule_from_name("Thanksgiving Day") == USThanksgivingDay
|
||||
|
||||
|
||||
def test_calendar_2031():
|
||||
# See gh-27790
|
||||
#
|
||||
# Labor Day 2031 is on September 1. Saturday before is August 30.
|
||||
# Next working day after August 30 ought to be Tuesday, September 2.
|
||||
|
||||
class testCalendar(AbstractHolidayCalendar):
|
||||
rules = [USLaborDay]
|
||||
|
||||
cal = testCalendar()
|
||||
workDay = offsets.CustomBusinessDay(calendar=cal)
|
||||
Sat_before_Labor_Day_2031 = to_datetime("2031-08-30")
|
||||
next_working_day = Sat_before_Labor_Day_2031 + 0 * workDay
|
||||
assert next_working_day == to_datetime("2031-09-02")
|
||||
|
||||
|
||||
def test_no_holidays_calendar():
|
||||
# Test for issue #31415
|
||||
|
||||
class NoHolidaysCalendar(AbstractHolidayCalendar):
|
||||
pass
|
||||
|
||||
cal = NoHolidaysCalendar()
|
||||
holidays = cal.holidays(Timestamp("01-Jan-2020"), Timestamp("01-Jan-2021"))
|
||||
empty_index = DatetimeIndex([]) # Type is DatetimeIndex since return_name=False
|
||||
tm.assert_index_equal(holidays, empty_index)
|
@ -0,0 +1,58 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pandas import DatetimeIndex
|
||||
import pandas._testing as tm
|
||||
|
||||
from pandas.tseries.holiday import (
|
||||
AbstractHolidayCalendar,
|
||||
USFederalHolidayCalendar,
|
||||
USMartinLutherKingJr,
|
||||
USMemorialDay,
|
||||
)
|
||||
|
||||
|
||||
def test_no_mlk_before_1986():
|
||||
# see gh-10278
|
||||
class MLKCalendar(AbstractHolidayCalendar):
|
||||
rules = [USMartinLutherKingJr]
|
||||
|
||||
holidays = MLKCalendar().holidays(start="1984", end="1988").to_pydatetime().tolist()
|
||||
|
||||
# Testing to make sure holiday is not incorrectly observed before 1986.
|
||||
assert holidays == [datetime(1986, 1, 20, 0, 0), datetime(1987, 1, 19, 0, 0)]
|
||||
|
||||
|
||||
def test_memorial_day():
|
||||
class MemorialDay(AbstractHolidayCalendar):
|
||||
rules = [USMemorialDay]
|
||||
|
||||
holidays = MemorialDay().holidays(start="1971", end="1980").to_pydatetime().tolist()
|
||||
|
||||
# Fixes 5/31 error and checked manually against Wikipedia.
|
||||
assert holidays == [
|
||||
datetime(1971, 5, 31, 0, 0),
|
||||
datetime(1972, 5, 29, 0, 0),
|
||||
datetime(1973, 5, 28, 0, 0),
|
||||
datetime(1974, 5, 27, 0, 0),
|
||||
datetime(1975, 5, 26, 0, 0),
|
||||
datetime(1976, 5, 31, 0, 0),
|
||||
datetime(1977, 5, 30, 0, 0),
|
||||
datetime(1978, 5, 29, 0, 0),
|
||||
datetime(1979, 5, 28, 0, 0),
|
||||
]
|
||||
|
||||
|
||||
def test_federal_holiday_inconsistent_returntype():
|
||||
# GH 49075 test case
|
||||
# Instantiate two calendars to rule out _cache
|
||||
cal1 = USFederalHolidayCalendar()
|
||||
cal2 = USFederalHolidayCalendar()
|
||||
|
||||
results_2018 = cal1.holidays(start=datetime(2018, 8, 1), end=datetime(2018, 8, 31))
|
||||
results_2019 = cal2.holidays(start=datetime(2019, 8, 1), end=datetime(2019, 8, 31))
|
||||
expected_results = DatetimeIndex([], dtype="datetime64[ns]", freq=None)
|
||||
|
||||
# Check against expected results to ensure both date
|
||||
# ranges generate expected results as per GH49075 submission
|
||||
tm.assert_index_equal(results_2018, expected_results)
|
||||
tm.assert_index_equal(results_2019, expected_results)
|
@ -0,0 +1,332 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from pytz import utc
|
||||
|
||||
from pandas import (
|
||||
DatetimeIndex,
|
||||
Series,
|
||||
)
|
||||
import pandas._testing as tm
|
||||
|
||||
from pandas.tseries.holiday import (
|
||||
MO,
|
||||
SA,
|
||||
AbstractHolidayCalendar,
|
||||
DateOffset,
|
||||
EasterMonday,
|
||||
GoodFriday,
|
||||
Holiday,
|
||||
HolidayCalendarFactory,
|
||||
Timestamp,
|
||||
USColumbusDay,
|
||||
USFederalHolidayCalendar,
|
||||
USLaborDay,
|
||||
USMartinLutherKingJr,
|
||||
USMemorialDay,
|
||||
USPresidentsDay,
|
||||
USThanksgivingDay,
|
||||
get_calendar,
|
||||
next_monday,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"holiday,start_date,end_date,expected",
|
||||
[
|
||||
(
|
||||
USMemorialDay,
|
||||
datetime(2011, 1, 1),
|
||||
datetime(2020, 12, 31),
|
||||
[
|
||||
datetime(2011, 5, 30),
|
||||
datetime(2012, 5, 28),
|
||||
datetime(2013, 5, 27),
|
||||
datetime(2014, 5, 26),
|
||||
datetime(2015, 5, 25),
|
||||
datetime(2016, 5, 30),
|
||||
datetime(2017, 5, 29),
|
||||
datetime(2018, 5, 28),
|
||||
datetime(2019, 5, 27),
|
||||
datetime(2020, 5, 25),
|
||||
],
|
||||
),
|
||||
(
|
||||
Holiday("July 4th Eve", month=7, day=3),
|
||||
"2001-01-01",
|
||||
"2003-03-03",
|
||||
[Timestamp("2001-07-03 00:00:00"), Timestamp("2002-07-03 00:00:00")],
|
||||
),
|
||||
(
|
||||
Holiday("July 4th Eve", month=7, day=3, days_of_week=(0, 1, 2, 3)),
|
||||
"2001-01-01",
|
||||
"2008-03-03",
|
||||
[
|
||||
Timestamp("2001-07-03 00:00:00"),
|
||||
Timestamp("2002-07-03 00:00:00"),
|
||||
Timestamp("2003-07-03 00:00:00"),
|
||||
Timestamp("2006-07-03 00:00:00"),
|
||||
Timestamp("2007-07-03 00:00:00"),
|
||||
],
|
||||
),
|
||||
(
|
||||
EasterMonday,
|
||||
datetime(2011, 1, 1),
|
||||
datetime(2020, 12, 31),
|
||||
[
|
||||
Timestamp("2011-04-25 00:00:00"),
|
||||
Timestamp("2012-04-09 00:00:00"),
|
||||
Timestamp("2013-04-01 00:00:00"),
|
||||
Timestamp("2014-04-21 00:00:00"),
|
||||
Timestamp("2015-04-06 00:00:00"),
|
||||
Timestamp("2016-03-28 00:00:00"),
|
||||
Timestamp("2017-04-17 00:00:00"),
|
||||
Timestamp("2018-04-02 00:00:00"),
|
||||
Timestamp("2019-04-22 00:00:00"),
|
||||
Timestamp("2020-04-13 00:00:00"),
|
||||
],
|
||||
),
|
||||
(
|
||||
GoodFriday,
|
||||
datetime(2011, 1, 1),
|
||||
datetime(2020, 12, 31),
|
||||
[
|
||||
Timestamp("2011-04-22 00:00:00"),
|
||||
Timestamp("2012-04-06 00:00:00"),
|
||||
Timestamp("2013-03-29 00:00:00"),
|
||||
Timestamp("2014-04-18 00:00:00"),
|
||||
Timestamp("2015-04-03 00:00:00"),
|
||||
Timestamp("2016-03-25 00:00:00"),
|
||||
Timestamp("2017-04-14 00:00:00"),
|
||||
Timestamp("2018-03-30 00:00:00"),
|
||||
Timestamp("2019-04-19 00:00:00"),
|
||||
Timestamp("2020-04-10 00:00:00"),
|
||||
],
|
||||
),
|
||||
(
|
||||
USThanksgivingDay,
|
||||
datetime(2011, 1, 1),
|
||||
datetime(2020, 12, 31),
|
||||
[
|
||||
datetime(2011, 11, 24),
|
||||
datetime(2012, 11, 22),
|
||||
datetime(2013, 11, 28),
|
||||
datetime(2014, 11, 27),
|
||||
datetime(2015, 11, 26),
|
||||
datetime(2016, 11, 24),
|
||||
datetime(2017, 11, 23),
|
||||
datetime(2018, 11, 22),
|
||||
datetime(2019, 11, 28),
|
||||
datetime(2020, 11, 26),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_holiday_dates(holiday, start_date, end_date, expected):
|
||||
assert list(holiday.dates(start_date, end_date)) == expected
|
||||
|
||||
# Verify that timezone info is preserved.
|
||||
assert list(
|
||||
holiday.dates(
|
||||
utc.localize(Timestamp(start_date)), utc.localize(Timestamp(end_date))
|
||||
)
|
||||
) == [utc.localize(dt) for dt in expected]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"holiday,start,expected",
|
||||
[
|
||||
(USMemorialDay, datetime(2015, 7, 1), []),
|
||||
(USMemorialDay, "2015-05-25", [Timestamp("2015-05-25")]),
|
||||
(USLaborDay, datetime(2015, 7, 1), []),
|
||||
(USLaborDay, "2015-09-07", [Timestamp("2015-09-07")]),
|
||||
(USColumbusDay, datetime(2015, 7, 1), []),
|
||||
(USColumbusDay, "2015-10-12", [Timestamp("2015-10-12")]),
|
||||
(USThanksgivingDay, datetime(2015, 7, 1), []),
|
||||
(USThanksgivingDay, "2015-11-26", [Timestamp("2015-11-26")]),
|
||||
(USMartinLutherKingJr, datetime(2015, 7, 1), []),
|
||||
(USMartinLutherKingJr, "2015-01-19", [Timestamp("2015-01-19")]),
|
||||
(USPresidentsDay, datetime(2015, 7, 1), []),
|
||||
(USPresidentsDay, "2015-02-16", [Timestamp("2015-02-16")]),
|
||||
(GoodFriday, datetime(2015, 7, 1), []),
|
||||
(GoodFriday, "2015-04-03", [Timestamp("2015-04-03")]),
|
||||
(EasterMonday, "2015-04-06", [Timestamp("2015-04-06")]),
|
||||
(EasterMonday, datetime(2015, 7, 1), []),
|
||||
(EasterMonday, "2015-04-05", []),
|
||||
("New Year's Day", "2015-01-01", [Timestamp("2015-01-01")]),
|
||||
("New Year's Day", "2010-12-31", [Timestamp("2010-12-31")]),
|
||||
("New Year's Day", datetime(2015, 7, 1), []),
|
||||
("New Year's Day", "2011-01-01", []),
|
||||
("Independence Day", "2015-07-03", [Timestamp("2015-07-03")]),
|
||||
("Independence Day", datetime(2015, 7, 1), []),
|
||||
("Independence Day", "2015-07-04", []),
|
||||
("Veterans Day", "2012-11-12", [Timestamp("2012-11-12")]),
|
||||
("Veterans Day", datetime(2015, 7, 1), []),
|
||||
("Veterans Day", "2012-11-11", []),
|
||||
("Christmas Day", "2011-12-26", [Timestamp("2011-12-26")]),
|
||||
("Christmas Day", datetime(2015, 7, 1), []),
|
||||
("Christmas Day", "2011-12-25", []),
|
||||
("Juneteenth National Independence Day", "2020-06-19", []),
|
||||
(
|
||||
"Juneteenth National Independence Day",
|
||||
"2021-06-18",
|
||||
[Timestamp("2021-06-18")],
|
||||
),
|
||||
("Juneteenth National Independence Day", "2022-06-19", []),
|
||||
(
|
||||
"Juneteenth National Independence Day",
|
||||
"2022-06-20",
|
||||
[Timestamp("2022-06-20")],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_holidays_within_dates(holiday, start, expected):
|
||||
# see gh-11477
|
||||
#
|
||||
# Fix holiday behavior where holiday.dates returned dates outside
|
||||
# start/end date, or observed rules could not be applied because the
|
||||
# holiday was not in the original date range (e.g., 7/4/2015 -> 7/3/2015).
|
||||
if isinstance(holiday, str):
|
||||
calendar = get_calendar("USFederalHolidayCalendar")
|
||||
holiday = calendar.rule_from_name(holiday)
|
||||
|
||||
assert list(holiday.dates(start, start)) == expected
|
||||
|
||||
# Verify that timezone info is preserved.
|
||||
assert list(
|
||||
holiday.dates(utc.localize(Timestamp(start)), utc.localize(Timestamp(start)))
|
||||
) == [utc.localize(dt) for dt in expected]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"transform", [lambda x: x.strftime("%Y-%m-%d"), lambda x: Timestamp(x)]
|
||||
)
|
||||
def test_argument_types(transform):
|
||||
start_date = datetime(2011, 1, 1)
|
||||
end_date = datetime(2020, 12, 31)
|
||||
|
||||
holidays = USThanksgivingDay.dates(start_date, end_date)
|
||||
holidays2 = USThanksgivingDay.dates(transform(start_date), transform(end_date))
|
||||
tm.assert_index_equal(holidays, holidays2)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"name,kwargs",
|
||||
[
|
||||
("One-Time", {"year": 2012, "month": 5, "day": 28}),
|
||||
(
|
||||
"Range",
|
||||
{
|
||||
"month": 5,
|
||||
"day": 28,
|
||||
"start_date": datetime(2012, 1, 1),
|
||||
"end_date": datetime(2012, 12, 31),
|
||||
"offset": DateOffset(weekday=MO(1)),
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_special_holidays(name, kwargs):
|
||||
base_date = [datetime(2012, 5, 28)]
|
||||
holiday = Holiday(name, **kwargs)
|
||||
|
||||
start_date = datetime(2011, 1, 1)
|
||||
end_date = datetime(2020, 12, 31)
|
||||
|
||||
assert base_date == holiday.dates(start_date, end_date)
|
||||
|
||||
|
||||
def test_get_calendar():
|
||||
class TestCalendar(AbstractHolidayCalendar):
|
||||
rules = []
|
||||
|
||||
calendar = get_calendar("TestCalendar")
|
||||
assert TestCalendar == type(calendar)
|
||||
|
||||
|
||||
def test_factory():
|
||||
class_1 = HolidayCalendarFactory(
|
||||
"MemorialDay", AbstractHolidayCalendar, USMemorialDay
|
||||
)
|
||||
class_2 = HolidayCalendarFactory(
|
||||
"Thanksgiving", AbstractHolidayCalendar, USThanksgivingDay
|
||||
)
|
||||
class_3 = HolidayCalendarFactory("Combined", class_1, class_2)
|
||||
|
||||
assert len(class_1.rules) == 1
|
||||
assert len(class_2.rules) == 1
|
||||
assert len(class_3.rules) == 2
|
||||
|
||||
|
||||
def test_both_offset_observance_raises():
|
||||
# see gh-10217
|
||||
msg = "Cannot use both offset and observance"
|
||||
with pytest.raises(NotImplementedError, match=msg):
|
||||
Holiday(
|
||||
"Cyber Monday",
|
||||
month=11,
|
||||
day=1,
|
||||
offset=[DateOffset(weekday=SA(4))],
|
||||
observance=next_monday,
|
||||
)
|
||||
|
||||
|
||||
def test_half_open_interval_with_observance():
|
||||
# Prompted by GH 49075
|
||||
# Check for holidays that have a half-open date interval where
|
||||
# they have either a start_date or end_date defined along
|
||||
# with a defined observance pattern to make sure that the return type
|
||||
# for Holiday.dates() remains consistent before & after the year that
|
||||
# marks the 'edge' of the half-open date interval.
|
||||
|
||||
holiday_1 = Holiday(
|
||||
"Arbitrary Holiday - start 2022-03-14",
|
||||
start_date=datetime(2022, 3, 14),
|
||||
month=3,
|
||||
day=14,
|
||||
observance=next_monday,
|
||||
)
|
||||
holiday_2 = Holiday(
|
||||
"Arbitrary Holiday 2 - end 2022-03-20",
|
||||
end_date=datetime(2022, 3, 20),
|
||||
month=3,
|
||||
day=20,
|
||||
observance=next_monday,
|
||||
)
|
||||
|
||||
class TestHolidayCalendar(AbstractHolidayCalendar):
|
||||
rules = [
|
||||
USMartinLutherKingJr,
|
||||
holiday_1,
|
||||
holiday_2,
|
||||
USLaborDay,
|
||||
]
|
||||
|
||||
start = Timestamp("2022-08-01")
|
||||
end = Timestamp("2022-08-31")
|
||||
year_offset = DateOffset(years=5)
|
||||
expected_results = DatetimeIndex([], dtype="datetime64[ns]", freq=None)
|
||||
test_cal = TestHolidayCalendar()
|
||||
|
||||
date_interval_low = test_cal.holidays(start - year_offset, end - year_offset)
|
||||
date_window_edge = test_cal.holidays(start, end)
|
||||
date_interval_high = test_cal.holidays(start + year_offset, end + year_offset)
|
||||
|
||||
tm.assert_index_equal(date_interval_low, expected_results)
|
||||
tm.assert_index_equal(date_window_edge, expected_results)
|
||||
tm.assert_index_equal(date_interval_high, expected_results)
|
||||
|
||||
|
||||
def test_holidays_with_timezone_specified_but_no_occurences():
|
||||
# GH 54580
|
||||
# _apply_rule() in holiday.py was silently dropping timezones if you passed it
|
||||
# an empty list of holiday dates that had timezone information
|
||||
start_date = Timestamp("2018-01-01", tz="America/Chicago")
|
||||
end_date = Timestamp("2018-01-11", tz="America/Chicago")
|
||||
test_case = USFederalHolidayCalendar().holidays(
|
||||
start_date, end_date, return_name=True
|
||||
)
|
||||
expected_results = Series("New Year's Day", index=[start_date])
|
||||
expected_results.index = expected_results.index.as_unit("ns")
|
||||
|
||||
tm.assert_equal(test_case, expected_results)
|
@ -0,0 +1,105 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas.tseries.holiday import (
|
||||
after_nearest_workday,
|
||||
before_nearest_workday,
|
||||
nearest_workday,
|
||||
next_monday,
|
||||
next_monday_or_tuesday,
|
||||
next_workday,
|
||||
previous_friday,
|
||||
previous_workday,
|
||||
sunday_to_monday,
|
||||
weekend_to_monday,
|
||||
)
|
||||
|
||||
_WEDNESDAY = datetime(2014, 4, 9)
|
||||
_THURSDAY = datetime(2014, 4, 10)
|
||||
_FRIDAY = datetime(2014, 4, 11)
|
||||
_SATURDAY = datetime(2014, 4, 12)
|
||||
_SUNDAY = datetime(2014, 4, 13)
|
||||
_MONDAY = datetime(2014, 4, 14)
|
||||
_TUESDAY = datetime(2014, 4, 15)
|
||||
_NEXT_WEDNESDAY = datetime(2014, 4, 16)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("day", [_SATURDAY, _SUNDAY])
|
||||
def test_next_monday(day):
|
||||
assert next_monday(day) == _MONDAY
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"day,expected", [(_SATURDAY, _MONDAY), (_SUNDAY, _TUESDAY), (_MONDAY, _TUESDAY)]
|
||||
)
|
||||
def test_next_monday_or_tuesday(day, expected):
|
||||
assert next_monday_or_tuesday(day) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("day", [_SATURDAY, _SUNDAY])
|
||||
def test_previous_friday(day):
|
||||
assert previous_friday(day) == _FRIDAY
|
||||
|
||||
|
||||
def test_sunday_to_monday():
|
||||
assert sunday_to_monday(_SUNDAY) == _MONDAY
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"day,expected", [(_SATURDAY, _FRIDAY), (_SUNDAY, _MONDAY), (_MONDAY, _MONDAY)]
|
||||
)
|
||||
def test_nearest_workday(day, expected):
|
||||
assert nearest_workday(day) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"day,expected", [(_SATURDAY, _MONDAY), (_SUNDAY, _MONDAY), (_MONDAY, _MONDAY)]
|
||||
)
|
||||
def test_weekend_to_monday(day, expected):
|
||||
assert weekend_to_monday(day) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"day,expected",
|
||||
[
|
||||
(_WEDNESDAY, _THURSDAY),
|
||||
(_THURSDAY, _FRIDAY),
|
||||
(_SATURDAY, _MONDAY),
|
||||
(_SUNDAY, _MONDAY),
|
||||
(_MONDAY, _TUESDAY),
|
||||
(_TUESDAY, _NEXT_WEDNESDAY), # WED is same week as TUE
|
||||
],
|
||||
)
|
||||
def test_next_workday(day, expected):
|
||||
assert next_workday(day) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"day,expected", [(_SATURDAY, _FRIDAY), (_SUNDAY, _FRIDAY), (_TUESDAY, _MONDAY)]
|
||||
)
|
||||
def test_previous_workday(day, expected):
|
||||
assert previous_workday(day) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"day,expected",
|
||||
[
|
||||
(_THURSDAY, _WEDNESDAY),
|
||||
(_FRIDAY, _THURSDAY),
|
||||
(_SATURDAY, _THURSDAY),
|
||||
(_SUNDAY, _FRIDAY),
|
||||
(_MONDAY, _FRIDAY), # last week Friday
|
||||
(_TUESDAY, _MONDAY),
|
||||
(_NEXT_WEDNESDAY, _TUESDAY), # WED is same week as TUE
|
||||
],
|
||||
)
|
||||
def test_before_nearest_workday(day, expected):
|
||||
assert before_nearest_workday(day) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"day,expected", [(_SATURDAY, _MONDAY), (_SUNDAY, _TUESDAY), (_FRIDAY, _MONDAY)]
|
||||
)
|
||||
def test_after_nearest_workday(day, expected):
|
||||
assert after_nearest_workday(day) == expected
|
@ -0,0 +1,37 @@
|
||||
"""
|
||||
Assertion helpers and base class for offsets tests
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def assert_offset_equal(offset, base, expected):
|
||||
actual = offset + base
|
||||
actual_swapped = base + offset
|
||||
actual_apply = offset._apply(base)
|
||||
try:
|
||||
assert actual == expected
|
||||
assert actual_swapped == expected
|
||||
assert actual_apply == expected
|
||||
except AssertionError as err:
|
||||
raise AssertionError(
|
||||
f"\nExpected: {expected}\nActual: {actual}\nFor Offset: {offset})"
|
||||
f"\nAt Date: {base}"
|
||||
) from err
|
||||
|
||||
|
||||
def assert_is_on_offset(offset, date, expected):
|
||||
actual = offset.is_on_offset(date)
|
||||
assert actual == expected, (
|
||||
f"\nExpected: {expected}\nActual: {actual}\nFor Offset: {offset})"
|
||||
f"\nAt Date: {date}"
|
||||
)
|
||||
|
||||
|
||||
class WeekDay:
|
||||
MON = 0
|
||||
TUE = 1
|
||||
WED = 2
|
||||
THU = 3
|
||||
FRI = 4
|
||||
SAT = 5
|
||||
SUN = 6
|
@ -0,0 +1,236 @@
|
||||
"""
|
||||
Tests for offsets.BDay
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import (
|
||||
date,
|
||||
datetime,
|
||||
timedelta,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
ApplyTypeError,
|
||||
BDay,
|
||||
BMonthEnd,
|
||||
)
|
||||
|
||||
from pandas import (
|
||||
DatetimeIndex,
|
||||
Timedelta,
|
||||
_testing as tm,
|
||||
)
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries import offsets
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dt():
|
||||
return datetime(2008, 1, 1)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def _offset():
|
||||
return BDay
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def offset(_offset):
|
||||
return _offset()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def offset2(_offset):
|
||||
return _offset(2)
|
||||
|
||||
|
||||
class TestBusinessDay:
|
||||
def test_different_normalize_equals(self, _offset, offset2):
|
||||
# GH#21404 changed __eq__ to return False when `normalize` does not match
|
||||
offset = _offset()
|
||||
offset2 = _offset(normalize=True)
|
||||
assert offset != offset2
|
||||
|
||||
def test_repr(self, offset, offset2):
|
||||
assert repr(offset) == "<BusinessDay>"
|
||||
assert repr(offset2) == "<2 * BusinessDays>"
|
||||
|
||||
expected = "<BusinessDay: offset=datetime.timedelta(days=1)>"
|
||||
assert repr(offset + timedelta(1)) == expected
|
||||
|
||||
def test_with_offset(self, dt, offset):
|
||||
offset = offset + timedelta(hours=2)
|
||||
|
||||
assert (dt + offset) == datetime(2008, 1, 2, 2)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"td",
|
||||
[
|
||||
Timedelta(hours=2),
|
||||
Timedelta(hours=2).to_pytimedelta(),
|
||||
Timedelta(hours=2).to_timedelta64(),
|
||||
],
|
||||
ids=lambda x: type(x),
|
||||
)
|
||||
def test_with_offset_index(self, td, dt, offset):
|
||||
dti = DatetimeIndex([dt])
|
||||
expected = DatetimeIndex([datetime(2008, 1, 2, 2)])
|
||||
|
||||
result = dti + (td + offset)
|
||||
tm.assert_index_equal(result, expected)
|
||||
|
||||
result = dti + (offset + td)
|
||||
tm.assert_index_equal(result, expected)
|
||||
|
||||
def test_eq(self, offset2):
|
||||
assert offset2 == offset2
|
||||
|
||||
def test_hash(self, offset2):
|
||||
assert hash(offset2) == hash(offset2)
|
||||
|
||||
def test_add_datetime(self, dt, offset2):
|
||||
assert offset2 + dt == datetime(2008, 1, 3)
|
||||
assert offset2 + np.datetime64("2008-01-01 00:00:00") == datetime(2008, 1, 3)
|
||||
|
||||
def testRollback1(self, dt, _offset):
|
||||
assert _offset(10).rollback(dt) == dt
|
||||
|
||||
def testRollback2(self, _offset):
|
||||
assert _offset(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4)
|
||||
|
||||
def testRollforward1(self, dt, _offset):
|
||||
assert _offset(10).rollforward(dt) == dt
|
||||
|
||||
def testRollforward2(self, _offset):
|
||||
assert _offset(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7)
|
||||
|
||||
def test_roll_date_object(self, offset):
|
||||
dt = date(2012, 9, 15)
|
||||
|
||||
result = offset.rollback(dt)
|
||||
assert result == datetime(2012, 9, 14)
|
||||
|
||||
result = offset.rollforward(dt)
|
||||
assert result == datetime(2012, 9, 17)
|
||||
|
||||
offset = offsets.Day()
|
||||
result = offset.rollback(dt)
|
||||
assert result == datetime(2012, 9, 15)
|
||||
|
||||
result = offset.rollforward(dt)
|
||||
assert result == datetime(2012, 9, 15)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dt, expected",
|
||||
[
|
||||
(datetime(2008, 1, 1), True),
|
||||
(datetime(2008, 1, 5), False),
|
||||
],
|
||||
)
|
||||
def test_is_on_offset(self, offset, dt, expected):
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
apply_cases: list[tuple[int, dict[datetime, datetime]]] = [
|
||||
(
|
||||
1,
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 2),
|
||||
datetime(2008, 1, 4): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 5): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 6): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 7): datetime(2008, 1, 8),
|
||||
},
|
||||
),
|
||||
(
|
||||
2,
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 3),
|
||||
datetime(2008, 1, 4): datetime(2008, 1, 8),
|
||||
datetime(2008, 1, 5): datetime(2008, 1, 8),
|
||||
datetime(2008, 1, 6): datetime(2008, 1, 8),
|
||||
datetime(2008, 1, 7): datetime(2008, 1, 9),
|
||||
},
|
||||
),
|
||||
(
|
||||
-1,
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 12, 31),
|
||||
datetime(2008, 1, 4): datetime(2008, 1, 3),
|
||||
datetime(2008, 1, 5): datetime(2008, 1, 4),
|
||||
datetime(2008, 1, 6): datetime(2008, 1, 4),
|
||||
datetime(2008, 1, 7): datetime(2008, 1, 4),
|
||||
datetime(2008, 1, 8): datetime(2008, 1, 7),
|
||||
},
|
||||
),
|
||||
(
|
||||
-2,
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 12, 28),
|
||||
datetime(2008, 1, 4): datetime(2008, 1, 2),
|
||||
datetime(2008, 1, 5): datetime(2008, 1, 3),
|
||||
datetime(2008, 1, 6): datetime(2008, 1, 3),
|
||||
datetime(2008, 1, 7): datetime(2008, 1, 3),
|
||||
datetime(2008, 1, 8): datetime(2008, 1, 4),
|
||||
datetime(2008, 1, 9): datetime(2008, 1, 7),
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2008, 1, 4): datetime(2008, 1, 4),
|
||||
datetime(2008, 1, 5): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 6): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 7): datetime(2008, 1, 7),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", apply_cases)
|
||||
def test_apply(self, case, _offset):
|
||||
n, cases = case
|
||||
offset = _offset(n)
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
def test_apply_large_n(self, _offset):
|
||||
dt = datetime(2012, 10, 23)
|
||||
|
||||
result = dt + _offset(10)
|
||||
assert result == datetime(2012, 11, 6)
|
||||
|
||||
result = dt + _offset(100) - _offset(100)
|
||||
assert result == dt
|
||||
|
||||
off = _offset() * 6
|
||||
rs = datetime(2012, 1, 1) - off
|
||||
xp = datetime(2011, 12, 23)
|
||||
assert rs == xp
|
||||
|
||||
st = datetime(2011, 12, 18)
|
||||
rs = st + off
|
||||
xp = datetime(2011, 12, 26)
|
||||
assert rs == xp
|
||||
|
||||
off = _offset() * 10
|
||||
rs = datetime(2014, 1, 5) + off # see #5890
|
||||
xp = datetime(2014, 1, 17)
|
||||
assert rs == xp
|
||||
|
||||
def test_apply_corner(self, _offset):
|
||||
if _offset is BDay:
|
||||
msg = "Only know how to combine business day with datetime or timedelta"
|
||||
else:
|
||||
msg = (
|
||||
"Only know how to combine trading day "
|
||||
"with datetime, datetime64 or timedelta"
|
||||
)
|
||||
with pytest.raises(ApplyTypeError, match=msg):
|
||||
_offset()._apply(BMonthEnd())
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,217 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- BMonthBegin
|
||||
- BMonthEnd
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
import pandas as pd
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
BMonthBegin,
|
||||
BMonthEnd,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("n", [-2, 1])
|
||||
@pytest.mark.parametrize(
|
||||
"cls",
|
||||
[
|
||||
BMonthBegin,
|
||||
BMonthEnd,
|
||||
],
|
||||
)
|
||||
def test_apply_index(cls, n):
|
||||
offset = cls(n=n)
|
||||
rng = pd.date_range(start="1/1/2000", periods=100000, freq="min")
|
||||
ser = pd.Series(rng)
|
||||
|
||||
res = rng + offset
|
||||
assert res.freq is None # not retained
|
||||
assert res[0] == rng[0] + offset
|
||||
assert res[-1] == rng[-1] + offset
|
||||
res2 = ser + offset
|
||||
# apply_index is only for indexes, not series, so no res2_v2
|
||||
assert res2.iloc[0] == ser.iloc[0] + offset
|
||||
assert res2.iloc[-1] == ser.iloc[-1] + offset
|
||||
|
||||
|
||||
class TestBMonthBegin:
|
||||
def test_offsets_compare_equal(self):
|
||||
# root cause of #456
|
||||
offset1 = BMonthBegin()
|
||||
offset2 = BMonthBegin()
|
||||
assert not offset1 != offset2
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
BMonthBegin(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 2, 1),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 1),
|
||||
datetime(2006, 12, 29): datetime(2007, 1, 1),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 1),
|
||||
datetime(2006, 9, 1): datetime(2006, 10, 2),
|
||||
datetime(2007, 1, 1): datetime(2007, 2, 1),
|
||||
datetime(2006, 12, 1): datetime(2007, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BMonthBegin(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2006, 10, 2): datetime(2006, 10, 2),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 1),
|
||||
datetime(2006, 12, 29): datetime(2007, 1, 1),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 1),
|
||||
datetime(2006, 9, 15): datetime(2006, 10, 2),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BMonthBegin(2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 3, 3),
|
||||
datetime(2008, 1, 15): datetime(2008, 3, 3),
|
||||
datetime(2006, 12, 29): datetime(2007, 2, 1),
|
||||
datetime(2006, 12, 31): datetime(2007, 2, 1),
|
||||
datetime(2007, 1, 1): datetime(2007, 3, 1),
|
||||
datetime(2006, 11, 1): datetime(2007, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BMonthBegin(-1),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 1),
|
||||
datetime(2008, 6, 30): datetime(2008, 6, 2),
|
||||
datetime(2008, 6, 1): datetime(2008, 5, 1),
|
||||
datetime(2008, 3, 10): datetime(2008, 3, 3),
|
||||
datetime(2008, 12, 31): datetime(2008, 12, 1),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 1),
|
||||
datetime(2006, 12, 30): datetime(2006, 12, 1),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
on_offset_cases = [
|
||||
(BMonthBegin(), datetime(2007, 12, 31), False),
|
||||
(BMonthBegin(), datetime(2008, 1, 1), True),
|
||||
(BMonthBegin(), datetime(2001, 4, 2), True),
|
||||
(BMonthBegin(), datetime(2008, 3, 3), True),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
|
||||
class TestBMonthEnd:
|
||||
def test_normalize(self):
|
||||
dt = datetime(2007, 1, 1, 3)
|
||||
|
||||
result = dt + BMonthEnd(normalize=True)
|
||||
expected = dt.replace(hour=0) + BMonthEnd()
|
||||
assert result == expected
|
||||
|
||||
def test_offsets_compare_equal(self):
|
||||
# root cause of #456
|
||||
offset1 = BMonthEnd()
|
||||
offset2 = BMonthEnd()
|
||||
assert not offset1 != offset2
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
BMonthEnd(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 29),
|
||||
datetime(2006, 12, 29): datetime(2007, 1, 31),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 31),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 31),
|
||||
datetime(2006, 12, 1): datetime(2006, 12, 29),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BMonthEnd(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 1, 31),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 29),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 31),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BMonthEnd(2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 2, 29),
|
||||
datetime(2008, 1, 31): datetime(2008, 3, 31),
|
||||
datetime(2006, 12, 29): datetime(2007, 2, 28),
|
||||
datetime(2006, 12, 31): datetime(2007, 2, 28),
|
||||
datetime(2007, 1, 1): datetime(2007, 2, 28),
|
||||
datetime(2006, 11, 1): datetime(2006, 12, 29),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BMonthEnd(-1),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 29),
|
||||
datetime(2008, 6, 30): datetime(2008, 5, 30),
|
||||
datetime(2008, 12, 31): datetime(2008, 11, 28),
|
||||
datetime(2006, 12, 29): datetime(2006, 11, 30),
|
||||
datetime(2006, 12, 30): datetime(2006, 12, 29),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 29),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
on_offset_cases = [
|
||||
(BMonthEnd(), datetime(2007, 12, 31), True),
|
||||
(BMonthEnd(), datetime(2008, 1, 1), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
@ -0,0 +1,315 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- BQuarterBegin
|
||||
- BQuarterEnd
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
import pandas._testing as tm
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
BQuarterBegin,
|
||||
BQuarterEnd,
|
||||
)
|
||||
|
||||
|
||||
def test_quarterly_dont_normalize():
|
||||
date = datetime(2012, 3, 31, 5, 30)
|
||||
|
||||
offsets = (BQuarterEnd, BQuarterBegin)
|
||||
|
||||
for klass in offsets:
|
||||
result = date + klass()
|
||||
assert result.time() == date.time()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("offset", [BQuarterBegin(), BQuarterEnd()])
|
||||
def test_on_offset(offset):
|
||||
dates = [
|
||||
datetime(2016, m, d)
|
||||
for m in [10, 11, 12]
|
||||
for d in [1, 2, 3, 28, 29, 30, 31]
|
||||
if not (m == 11 and d == 31)
|
||||
]
|
||||
for date in dates:
|
||||
res = offset.is_on_offset(date)
|
||||
slow_version = date == (date + offset) - offset
|
||||
assert res == slow_version
|
||||
|
||||
|
||||
class TestBQuarterBegin:
|
||||
def test_repr(self):
|
||||
expected = "<BusinessQuarterBegin: startingMonth=3>"
|
||||
assert repr(BQuarterBegin()) == expected
|
||||
expected = "<BusinessQuarterBegin: startingMonth=3>"
|
||||
assert repr(BQuarterBegin(startingMonth=3)) == expected
|
||||
expected = "<BusinessQuarterBegin: startingMonth=1>"
|
||||
assert repr(BQuarterBegin(startingMonth=1)) == expected
|
||||
|
||||
def test_is_anchored(self):
|
||||
msg = "BQuarterBegin.is_anchored is deprecated "
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
assert BQuarterBegin(startingMonth=1).is_anchored()
|
||||
assert BQuarterBegin().is_anchored()
|
||||
assert not BQuarterBegin(2, startingMonth=1).is_anchored()
|
||||
|
||||
def test_offset_corner_case(self):
|
||||
# corner
|
||||
offset = BQuarterBegin(n=-1, startingMonth=1)
|
||||
assert datetime(2007, 4, 3) + offset == datetime(2007, 4, 2)
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
BQuarterBegin(startingMonth=1),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 4, 1),
|
||||
datetime(2008, 1, 31): datetime(2008, 4, 1),
|
||||
datetime(2008, 2, 15): datetime(2008, 4, 1),
|
||||
datetime(2008, 2, 29): datetime(2008, 4, 1),
|
||||
datetime(2008, 3, 15): datetime(2008, 4, 1),
|
||||
datetime(2008, 3, 31): datetime(2008, 4, 1),
|
||||
datetime(2008, 4, 15): datetime(2008, 7, 1),
|
||||
datetime(2007, 3, 15): datetime(2007, 4, 2),
|
||||
datetime(2007, 2, 28): datetime(2007, 4, 2),
|
||||
datetime(2007, 1, 1): datetime(2007, 4, 2),
|
||||
datetime(2007, 4, 15): datetime(2007, 7, 2),
|
||||
datetime(2007, 7, 1): datetime(2007, 7, 2),
|
||||
datetime(2007, 4, 1): datetime(2007, 4, 2),
|
||||
datetime(2007, 4, 2): datetime(2007, 7, 2),
|
||||
datetime(2008, 4, 30): datetime(2008, 7, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BQuarterBegin(startingMonth=2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 2, 1),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 1),
|
||||
datetime(2008, 1, 15): datetime(2008, 2, 1),
|
||||
datetime(2008, 2, 29): datetime(2008, 5, 1),
|
||||
datetime(2008, 3, 15): datetime(2008, 5, 1),
|
||||
datetime(2008, 3, 31): datetime(2008, 5, 1),
|
||||
datetime(2008, 4, 15): datetime(2008, 5, 1),
|
||||
datetime(2008, 8, 15): datetime(2008, 11, 3),
|
||||
datetime(2008, 9, 15): datetime(2008, 11, 3),
|
||||
datetime(2008, 11, 1): datetime(2008, 11, 3),
|
||||
datetime(2008, 4, 30): datetime(2008, 5, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BQuarterBegin(startingMonth=1, n=0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2007, 12, 31): datetime(2008, 1, 1),
|
||||
datetime(2008, 2, 15): datetime(2008, 4, 1),
|
||||
datetime(2008, 2, 29): datetime(2008, 4, 1),
|
||||
datetime(2008, 1, 15): datetime(2008, 4, 1),
|
||||
datetime(2008, 2, 27): datetime(2008, 4, 1),
|
||||
datetime(2008, 3, 15): datetime(2008, 4, 1),
|
||||
datetime(2007, 4, 1): datetime(2007, 4, 2),
|
||||
datetime(2007, 4, 2): datetime(2007, 4, 2),
|
||||
datetime(2007, 7, 1): datetime(2007, 7, 2),
|
||||
datetime(2007, 4, 15): datetime(2007, 7, 2),
|
||||
datetime(2007, 7, 2): datetime(2007, 7, 2),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BQuarterBegin(startingMonth=1, n=-1),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 10, 1),
|
||||
datetime(2008, 1, 31): datetime(2008, 1, 1),
|
||||
datetime(2008, 2, 15): datetime(2008, 1, 1),
|
||||
datetime(2008, 2, 29): datetime(2008, 1, 1),
|
||||
datetime(2008, 3, 15): datetime(2008, 1, 1),
|
||||
datetime(2008, 3, 31): datetime(2008, 1, 1),
|
||||
datetime(2008, 4, 15): datetime(2008, 4, 1),
|
||||
datetime(2007, 7, 3): datetime(2007, 7, 2),
|
||||
datetime(2007, 4, 3): datetime(2007, 4, 2),
|
||||
datetime(2007, 7, 2): datetime(2007, 4, 2),
|
||||
datetime(2008, 4, 1): datetime(2008, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BQuarterBegin(startingMonth=1, n=2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 7, 1),
|
||||
datetime(2008, 1, 15): datetime(2008, 7, 1),
|
||||
datetime(2008, 2, 29): datetime(2008, 7, 1),
|
||||
datetime(2008, 3, 15): datetime(2008, 7, 1),
|
||||
datetime(2007, 3, 31): datetime(2007, 7, 2),
|
||||
datetime(2007, 4, 15): datetime(2007, 10, 1),
|
||||
datetime(2008, 4, 30): datetime(2008, 10, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
|
||||
class TestBQuarterEnd:
|
||||
def test_repr(self):
|
||||
expected = "<BusinessQuarterEnd: startingMonth=3>"
|
||||
assert repr(BQuarterEnd()) == expected
|
||||
expected = "<BusinessQuarterEnd: startingMonth=3>"
|
||||
assert repr(BQuarterEnd(startingMonth=3)) == expected
|
||||
expected = "<BusinessQuarterEnd: startingMonth=1>"
|
||||
assert repr(BQuarterEnd(startingMonth=1)) == expected
|
||||
|
||||
def test_is_anchored(self):
|
||||
msg = "BQuarterEnd.is_anchored is deprecated "
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
assert BQuarterEnd(startingMonth=1).is_anchored()
|
||||
assert BQuarterEnd().is_anchored()
|
||||
assert not BQuarterEnd(2, startingMonth=1).is_anchored()
|
||||
|
||||
def test_offset_corner_case(self):
|
||||
# corner
|
||||
offset = BQuarterEnd(n=-1, startingMonth=1)
|
||||
assert datetime(2010, 1, 31) + offset == datetime(2010, 1, 29)
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
BQuarterEnd(startingMonth=1),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 4, 30),
|
||||
datetime(2008, 2, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 2, 29): datetime(2008, 4, 30),
|
||||
datetime(2008, 3, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 3, 31): datetime(2008, 4, 30),
|
||||
datetime(2008, 4, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 4, 30): datetime(2008, 7, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BQuarterEnd(startingMonth=2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 2, 29),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 29),
|
||||
datetime(2008, 2, 15): datetime(2008, 2, 29),
|
||||
datetime(2008, 2, 29): datetime(2008, 5, 30),
|
||||
datetime(2008, 3, 15): datetime(2008, 5, 30),
|
||||
datetime(2008, 3, 31): datetime(2008, 5, 30),
|
||||
datetime(2008, 4, 15): datetime(2008, 5, 30),
|
||||
datetime(2008, 4, 30): datetime(2008, 5, 30),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BQuarterEnd(startingMonth=1, n=0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 1, 31),
|
||||
datetime(2008, 2, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 2, 29): datetime(2008, 4, 30),
|
||||
datetime(2008, 3, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 3, 31): datetime(2008, 4, 30),
|
||||
datetime(2008, 4, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 4, 30): datetime(2008, 4, 30),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BQuarterEnd(startingMonth=1, n=-1),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 10, 31),
|
||||
datetime(2008, 1, 31): datetime(2007, 10, 31),
|
||||
datetime(2008, 2, 15): datetime(2008, 1, 31),
|
||||
datetime(2008, 2, 29): datetime(2008, 1, 31),
|
||||
datetime(2008, 3, 15): datetime(2008, 1, 31),
|
||||
datetime(2008, 3, 31): datetime(2008, 1, 31),
|
||||
datetime(2008, 4, 15): datetime(2008, 1, 31),
|
||||
datetime(2008, 4, 30): datetime(2008, 1, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BQuarterEnd(startingMonth=1, n=2),
|
||||
{
|
||||
datetime(2008, 1, 31): datetime(2008, 7, 31),
|
||||
datetime(2008, 2, 15): datetime(2008, 7, 31),
|
||||
datetime(2008, 2, 29): datetime(2008, 7, 31),
|
||||
datetime(2008, 3, 15): datetime(2008, 7, 31),
|
||||
datetime(2008, 3, 31): datetime(2008, 7, 31),
|
||||
datetime(2008, 4, 15): datetime(2008, 7, 31),
|
||||
datetime(2008, 4, 30): datetime(2008, 10, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
on_offset_cases = [
|
||||
(BQuarterEnd(1, startingMonth=1), datetime(2008, 1, 31), True),
|
||||
(BQuarterEnd(1, startingMonth=1), datetime(2007, 12, 31), False),
|
||||
(BQuarterEnd(1, startingMonth=1), datetime(2008, 2, 29), False),
|
||||
(BQuarterEnd(1, startingMonth=1), datetime(2007, 3, 30), False),
|
||||
(BQuarterEnd(1, startingMonth=1), datetime(2007, 3, 31), False),
|
||||
(BQuarterEnd(1, startingMonth=1), datetime(2008, 4, 30), True),
|
||||
(BQuarterEnd(1, startingMonth=1), datetime(2008, 5, 30), False),
|
||||
(BQuarterEnd(1, startingMonth=1), datetime(2007, 6, 29), False),
|
||||
(BQuarterEnd(1, startingMonth=1), datetime(2007, 6, 30), False),
|
||||
(BQuarterEnd(1, startingMonth=2), datetime(2008, 1, 31), False),
|
||||
(BQuarterEnd(1, startingMonth=2), datetime(2007, 12, 31), False),
|
||||
(BQuarterEnd(1, startingMonth=2), datetime(2008, 2, 29), True),
|
||||
(BQuarterEnd(1, startingMonth=2), datetime(2007, 3, 30), False),
|
||||
(BQuarterEnd(1, startingMonth=2), datetime(2007, 3, 31), False),
|
||||
(BQuarterEnd(1, startingMonth=2), datetime(2008, 4, 30), False),
|
||||
(BQuarterEnd(1, startingMonth=2), datetime(2008, 5, 30), True),
|
||||
(BQuarterEnd(1, startingMonth=2), datetime(2007, 6, 29), False),
|
||||
(BQuarterEnd(1, startingMonth=2), datetime(2007, 6, 30), False),
|
||||
(BQuarterEnd(1, startingMonth=3), datetime(2008, 1, 31), False),
|
||||
(BQuarterEnd(1, startingMonth=3), datetime(2007, 12, 31), True),
|
||||
(BQuarterEnd(1, startingMonth=3), datetime(2008, 2, 29), False),
|
||||
(BQuarterEnd(1, startingMonth=3), datetime(2007, 3, 30), True),
|
||||
(BQuarterEnd(1, startingMonth=3), datetime(2007, 3, 31), False),
|
||||
(BQuarterEnd(1, startingMonth=3), datetime(2008, 4, 30), False),
|
||||
(BQuarterEnd(1, startingMonth=3), datetime(2008, 5, 30), False),
|
||||
(BQuarterEnd(1, startingMonth=3), datetime(2007, 6, 29), True),
|
||||
(BQuarterEnd(1, startingMonth=3), datetime(2007, 6, 30), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
@ -0,0 +1,215 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- BYearBegin
|
||||
- BYearEnd
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
BYearBegin,
|
||||
BYearEnd,
|
||||
)
|
||||
|
||||
|
||||
class TestBYearBegin:
|
||||
def test_misspecified(self):
|
||||
msg = "Month must go from 1 to 12"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
BYearBegin(month=13)
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
BYearEnd(month=13)
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
BYearBegin(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2009, 1, 1),
|
||||
datetime(2008, 6, 30): datetime(2009, 1, 1),
|
||||
datetime(2008, 12, 31): datetime(2009, 1, 1),
|
||||
datetime(2011, 1, 1): datetime(2011, 1, 3),
|
||||
datetime(2011, 1, 3): datetime(2012, 1, 2),
|
||||
datetime(2005, 12, 30): datetime(2006, 1, 2),
|
||||
datetime(2005, 12, 31): datetime(2006, 1, 2),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BYearBegin(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2008, 6, 30): datetime(2009, 1, 1),
|
||||
datetime(2008, 12, 31): datetime(2009, 1, 1),
|
||||
datetime(2005, 12, 30): datetime(2006, 1, 2),
|
||||
datetime(2005, 12, 31): datetime(2006, 1, 2),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BYearBegin(-1),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 1, 2),
|
||||
datetime(2009, 1, 4): datetime(2009, 1, 1),
|
||||
datetime(2009, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2008, 6, 30): datetime(2008, 1, 1),
|
||||
datetime(2008, 12, 31): datetime(2008, 1, 1),
|
||||
datetime(2006, 12, 29): datetime(2006, 1, 2),
|
||||
datetime(2006, 12, 30): datetime(2006, 1, 2),
|
||||
datetime(2006, 1, 1): datetime(2005, 1, 3),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BYearBegin(-2),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2005, 1, 3),
|
||||
datetime(2007, 6, 30): datetime(2006, 1, 2),
|
||||
datetime(2008, 12, 31): datetime(2007, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
|
||||
class TestBYearEnd:
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
BYearEnd(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 12, 31),
|
||||
datetime(2008, 6, 30): datetime(2008, 12, 31),
|
||||
datetime(2008, 12, 31): datetime(2009, 12, 31),
|
||||
datetime(2005, 12, 30): datetime(2006, 12, 29),
|
||||
datetime(2005, 12, 31): datetime(2006, 12, 29),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BYearEnd(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 12, 31),
|
||||
datetime(2008, 6, 30): datetime(2008, 12, 31),
|
||||
datetime(2008, 12, 31): datetime(2008, 12, 31),
|
||||
datetime(2005, 12, 31): datetime(2006, 12, 29),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BYearEnd(-1),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 29),
|
||||
datetime(2008, 6, 30): datetime(2007, 12, 31),
|
||||
datetime(2008, 12, 31): datetime(2007, 12, 31),
|
||||
datetime(2006, 12, 29): datetime(2005, 12, 30),
|
||||
datetime(2006, 12, 30): datetime(2006, 12, 29),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 29),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BYearEnd(-2),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2005, 12, 30),
|
||||
datetime(2008, 6, 30): datetime(2006, 12, 29),
|
||||
datetime(2008, 12, 31): datetime(2006, 12, 29),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
on_offset_cases = [
|
||||
(BYearEnd(), datetime(2007, 12, 31), True),
|
||||
(BYearEnd(), datetime(2008, 1, 1), False),
|
||||
(BYearEnd(), datetime(2006, 12, 31), False),
|
||||
(BYearEnd(), datetime(2006, 12, 29), True),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
|
||||
class TestBYearEndLagged:
|
||||
def test_bad_month_fail(self):
|
||||
msg = "Month must go from 1 to 12"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
BYearEnd(month=13)
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
BYearEnd(month=0)
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
BYearEnd(month=6),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 6, 30),
|
||||
datetime(2007, 6, 30): datetime(2008, 6, 30),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
BYearEnd(n=-1, month=6),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 6, 29),
|
||||
datetime(2007, 6, 30): datetime(2007, 6, 29),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
def test_roll(self):
|
||||
offset = BYearEnd(month=6)
|
||||
date = datetime(2009, 11, 30)
|
||||
|
||||
assert offset.rollforward(date) == datetime(2010, 6, 30)
|
||||
assert offset.rollback(date) == datetime(2009, 6, 30)
|
||||
|
||||
on_offset_cases = [
|
||||
(BYearEnd(month=2), datetime(2007, 2, 28), True),
|
||||
(BYearEnd(month=6), datetime(2007, 6, 30), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
@ -0,0 +1,268 @@
|
||||
from datetime import datetime
|
||||
|
||||
from dateutil.tz.tz import tzlocal
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
OutOfBoundsDatetime,
|
||||
Timestamp,
|
||||
)
|
||||
from pandas.compat import (
|
||||
IS64,
|
||||
is_platform_windows,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
FY5253,
|
||||
BDay,
|
||||
BMonthBegin,
|
||||
BMonthEnd,
|
||||
BQuarterBegin,
|
||||
BQuarterEnd,
|
||||
BusinessHour,
|
||||
BYearBegin,
|
||||
BYearEnd,
|
||||
CBMonthBegin,
|
||||
CBMonthEnd,
|
||||
CDay,
|
||||
CustomBusinessHour,
|
||||
DateOffset,
|
||||
FY5253Quarter,
|
||||
LastWeekOfMonth,
|
||||
MonthBegin,
|
||||
MonthEnd,
|
||||
QuarterEnd,
|
||||
SemiMonthBegin,
|
||||
SemiMonthEnd,
|
||||
Week,
|
||||
WeekOfMonth,
|
||||
YearBegin,
|
||||
YearEnd,
|
||||
)
|
||||
|
||||
|
||||
def _get_offset(klass, value=1, normalize=False):
|
||||
# create instance from offset class
|
||||
if klass is FY5253:
|
||||
klass = klass(
|
||||
n=value,
|
||||
startingMonth=1,
|
||||
weekday=1,
|
||||
variation="last",
|
||||
normalize=normalize,
|
||||
)
|
||||
elif klass is FY5253Quarter:
|
||||
klass = klass(
|
||||
n=value,
|
||||
startingMonth=1,
|
||||
weekday=1,
|
||||
qtr_with_extra_week=1,
|
||||
variation="last",
|
||||
normalize=normalize,
|
||||
)
|
||||
elif klass is LastWeekOfMonth:
|
||||
klass = klass(n=value, weekday=5, normalize=normalize)
|
||||
elif klass is WeekOfMonth:
|
||||
klass = klass(n=value, week=1, weekday=5, normalize=normalize)
|
||||
elif klass is Week:
|
||||
klass = klass(n=value, weekday=5, normalize=normalize)
|
||||
elif klass is DateOffset:
|
||||
klass = klass(days=value, normalize=normalize)
|
||||
else:
|
||||
klass = klass(value, normalize=normalize)
|
||||
return klass
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
params=[
|
||||
BDay,
|
||||
BusinessHour,
|
||||
BMonthEnd,
|
||||
BMonthBegin,
|
||||
BQuarterEnd,
|
||||
BQuarterBegin,
|
||||
BYearEnd,
|
||||
BYearBegin,
|
||||
CDay,
|
||||
CustomBusinessHour,
|
||||
CBMonthEnd,
|
||||
CBMonthBegin,
|
||||
MonthEnd,
|
||||
MonthBegin,
|
||||
SemiMonthBegin,
|
||||
SemiMonthEnd,
|
||||
QuarterEnd,
|
||||
LastWeekOfMonth,
|
||||
WeekOfMonth,
|
||||
Week,
|
||||
YearBegin,
|
||||
YearEnd,
|
||||
FY5253,
|
||||
FY5253Quarter,
|
||||
DateOffset,
|
||||
]
|
||||
)
|
||||
def _offset(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dt(_offset):
|
||||
if _offset in (CBMonthBegin, CBMonthEnd, BDay):
|
||||
return Timestamp(2008, 1, 1)
|
||||
elif _offset is (CustomBusinessHour, BusinessHour):
|
||||
return Timestamp(2014, 7, 1, 10, 00)
|
||||
return Timestamp(2008, 1, 2)
|
||||
|
||||
|
||||
def test_apply_out_of_range(request, tz_naive_fixture, _offset):
|
||||
tz = tz_naive_fixture
|
||||
|
||||
# try to create an out-of-bounds result timestamp; if we can't create
|
||||
# the offset skip
|
||||
try:
|
||||
if _offset in (BusinessHour, CustomBusinessHour):
|
||||
# Using 10000 in BusinessHour fails in tz check because of DST
|
||||
# difference
|
||||
offset = _get_offset(_offset, value=100000)
|
||||
else:
|
||||
offset = _get_offset(_offset, value=10000)
|
||||
|
||||
result = Timestamp("20080101") + offset
|
||||
assert isinstance(result, datetime)
|
||||
assert result.tzinfo is None
|
||||
|
||||
# Check tz is preserved
|
||||
t = Timestamp("20080101", tz=tz)
|
||||
result = t + offset
|
||||
assert isinstance(result, datetime)
|
||||
if tz is not None:
|
||||
assert t.tzinfo is not None
|
||||
|
||||
if isinstance(tz, tzlocal) and not IS64 and _offset is not DateOffset:
|
||||
# If we hit OutOfBoundsDatetime on non-64 bit machines
|
||||
# we'll drop out of the try clause before the next test
|
||||
request.applymarker(
|
||||
pytest.mark.xfail(reason="OverflowError inside tzlocal past 2038")
|
||||
)
|
||||
elif (
|
||||
isinstance(tz, tzlocal)
|
||||
and is_platform_windows()
|
||||
and _offset in (QuarterEnd, BQuarterBegin, BQuarterEnd)
|
||||
):
|
||||
request.applymarker(
|
||||
pytest.mark.xfail(reason="After GH#49737 t.tzinfo is None on CI")
|
||||
)
|
||||
assert str(t.tzinfo) == str(result.tzinfo)
|
||||
|
||||
except OutOfBoundsDatetime:
|
||||
pass
|
||||
except (ValueError, KeyError):
|
||||
# we are creating an invalid offset
|
||||
# so ignore
|
||||
pass
|
||||
|
||||
|
||||
def test_offsets_compare_equal(_offset):
|
||||
# root cause of GH#456: __ne__ was not implemented
|
||||
offset1 = _offset()
|
||||
offset2 = _offset()
|
||||
assert not offset1 != offset2
|
||||
assert offset1 == offset2
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date, offset2",
|
||||
[
|
||||
[Timestamp(2008, 1, 1), BDay(2)],
|
||||
[Timestamp(2014, 7, 1, 10, 00), BusinessHour(n=3)],
|
||||
[
|
||||
Timestamp(2014, 7, 1, 10),
|
||||
CustomBusinessHour(
|
||||
holidays=["2014-06-27", Timestamp(2014, 6, 30), Timestamp("2014-07-02")]
|
||||
),
|
||||
],
|
||||
[Timestamp(2008, 1, 2), SemiMonthEnd(2)],
|
||||
[Timestamp(2008, 1, 2), SemiMonthBegin(2)],
|
||||
[Timestamp(2008, 1, 2), Week(2)],
|
||||
[Timestamp(2008, 1, 2), WeekOfMonth(2)],
|
||||
[Timestamp(2008, 1, 2), LastWeekOfMonth(2)],
|
||||
],
|
||||
)
|
||||
def test_rsub(date, offset2):
|
||||
assert date - offset2 == (-offset2)._apply(date)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date, offset2",
|
||||
[
|
||||
[Timestamp(2008, 1, 1), BDay(2)],
|
||||
[Timestamp(2014, 7, 1, 10, 00), BusinessHour(n=3)],
|
||||
[
|
||||
Timestamp(2014, 7, 1, 10),
|
||||
CustomBusinessHour(
|
||||
holidays=["2014-06-27", Timestamp(2014, 6, 30), Timestamp("2014-07-02")]
|
||||
),
|
||||
],
|
||||
[Timestamp(2008, 1, 2), SemiMonthEnd(2)],
|
||||
[Timestamp(2008, 1, 2), SemiMonthBegin(2)],
|
||||
[Timestamp(2008, 1, 2), Week(2)],
|
||||
[Timestamp(2008, 1, 2), WeekOfMonth(2)],
|
||||
[Timestamp(2008, 1, 2), LastWeekOfMonth(2)],
|
||||
],
|
||||
)
|
||||
def test_radd(date, offset2):
|
||||
assert date + offset2 == offset2 + date
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date, offset_box, offset2",
|
||||
[
|
||||
[Timestamp(2008, 1, 1), BDay, BDay(2)],
|
||||
[Timestamp(2008, 1, 2), SemiMonthEnd, SemiMonthEnd(2)],
|
||||
[Timestamp(2008, 1, 2), SemiMonthBegin, SemiMonthBegin(2)],
|
||||
[Timestamp(2008, 1, 2), Week, Week(2)],
|
||||
[Timestamp(2008, 1, 2), WeekOfMonth, WeekOfMonth(2)],
|
||||
[Timestamp(2008, 1, 2), LastWeekOfMonth, LastWeekOfMonth(2)],
|
||||
],
|
||||
)
|
||||
def test_sub(date, offset_box, offset2):
|
||||
off = offset2
|
||||
msg = "Cannot subtract datetime from offset"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
off - date
|
||||
|
||||
assert 2 * off - off == off
|
||||
assert date - offset2 == date + offset_box(-2)
|
||||
assert date - offset2 == date - (2 * off - off)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"offset_box, offset1",
|
||||
[
|
||||
[BDay, BDay()],
|
||||
[LastWeekOfMonth, LastWeekOfMonth()],
|
||||
[WeekOfMonth, WeekOfMonth()],
|
||||
[Week, Week()],
|
||||
[SemiMonthBegin, SemiMonthBegin()],
|
||||
[SemiMonthEnd, SemiMonthEnd()],
|
||||
[CustomBusinessHour, CustomBusinessHour(weekmask="Tue Wed Thu Fri")],
|
||||
[BusinessHour, BusinessHour()],
|
||||
],
|
||||
)
|
||||
def test_Mult1(offset_box, offset1):
|
||||
dt = Timestamp(2008, 1, 2)
|
||||
assert dt + 10 * offset1 == dt + offset_box(10)
|
||||
assert dt + 5 * offset1 == dt + offset_box(5)
|
||||
|
||||
|
||||
def test_compare_str(_offset):
|
||||
# GH#23524
|
||||
# comparing to strings that cannot be cast to DateOffsets should
|
||||
# not raise for __eq__ or __ne__
|
||||
off = _get_offset(_offset)
|
||||
|
||||
assert not off == "infer"
|
||||
assert off != "foo"
|
||||
# Note: inequalities are only implemented for Tick subclasses;
|
||||
# tests for this are in test_ticks
|
@ -0,0 +1,98 @@
|
||||
"""
|
||||
Tests for offsets.CustomBusinessDay / CDay
|
||||
"""
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.offsets import CDay
|
||||
|
||||
from pandas import (
|
||||
_testing as tm,
|
||||
read_pickle,
|
||||
)
|
||||
from pandas.tests.tseries.offsets.common import assert_offset_equal
|
||||
|
||||
from pandas.tseries.holiday import USFederalHolidayCalendar
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def offset():
|
||||
return CDay()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def offset2():
|
||||
return CDay(2)
|
||||
|
||||
|
||||
class TestCustomBusinessDay:
|
||||
def test_repr(self, offset, offset2):
|
||||
assert repr(offset) == "<CustomBusinessDay>"
|
||||
assert repr(offset2) == "<2 * CustomBusinessDays>"
|
||||
|
||||
expected = "<BusinessDay: offset=datetime.timedelta(days=1)>"
|
||||
assert repr(offset + timedelta(1)) == expected
|
||||
|
||||
def test_holidays(self):
|
||||
# Define a TradingDay offset
|
||||
holidays = ["2012-05-01", datetime(2013, 5, 1), np.datetime64("2014-05-01")]
|
||||
tday = CDay(holidays=holidays)
|
||||
for year in range(2012, 2015):
|
||||
dt = datetime(year, 4, 30)
|
||||
xp = datetime(year, 5, 2)
|
||||
rs = dt + tday
|
||||
assert rs == xp
|
||||
|
||||
def test_weekmask(self):
|
||||
weekmask_saudi = "Sat Sun Mon Tue Wed" # Thu-Fri Weekend
|
||||
weekmask_uae = "1111001" # Fri-Sat Weekend
|
||||
weekmask_egypt = [1, 1, 1, 1, 0, 0, 1] # Fri-Sat Weekend
|
||||
bday_saudi = CDay(weekmask=weekmask_saudi)
|
||||
bday_uae = CDay(weekmask=weekmask_uae)
|
||||
bday_egypt = CDay(weekmask=weekmask_egypt)
|
||||
dt = datetime(2013, 5, 1)
|
||||
xp_saudi = datetime(2013, 5, 4)
|
||||
xp_uae = datetime(2013, 5, 2)
|
||||
xp_egypt = datetime(2013, 5, 2)
|
||||
assert xp_saudi == dt + bday_saudi
|
||||
assert xp_uae == dt + bday_uae
|
||||
assert xp_egypt == dt + bday_egypt
|
||||
xp2 = datetime(2013, 5, 5)
|
||||
assert xp2 == dt + 2 * bday_saudi
|
||||
assert xp2 == dt + 2 * bday_uae
|
||||
assert xp2 == dt + 2 * bday_egypt
|
||||
|
||||
def test_weekmask_and_holidays(self):
|
||||
weekmask_egypt = "Sun Mon Tue Wed Thu" # Fri-Sat Weekend
|
||||
holidays = ["2012-05-01", datetime(2013, 5, 1), np.datetime64("2014-05-01")]
|
||||
bday_egypt = CDay(holidays=holidays, weekmask=weekmask_egypt)
|
||||
dt = datetime(2013, 4, 30)
|
||||
xp_egypt = datetime(2013, 5, 5)
|
||||
assert xp_egypt == dt + 2 * bday_egypt
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning")
|
||||
def test_calendar(self):
|
||||
calendar = USFederalHolidayCalendar()
|
||||
dt = datetime(2014, 1, 17)
|
||||
assert_offset_equal(CDay(calendar=calendar), dt, datetime(2014, 1, 21))
|
||||
|
||||
def test_roundtrip_pickle(self, offset, offset2):
|
||||
def _check_roundtrip(obj):
|
||||
unpickled = tm.round_trip_pickle(obj)
|
||||
assert unpickled == obj
|
||||
|
||||
_check_roundtrip(offset)
|
||||
_check_roundtrip(offset2)
|
||||
_check_roundtrip(offset * 2)
|
||||
|
||||
def test_pickle_compat_0_14_1(self, datapath):
|
||||
hdays = [datetime(2013, 1, 1) for ele in range(4)]
|
||||
pth = datapath("tseries", "offsets", "data", "cday-0.14.1.pickle")
|
||||
cday0_14_1 = read_pickle(pth)
|
||||
cday = CDay(holidays=hdays)
|
||||
assert cday == cday0_14_1
|
@ -0,0 +1,329 @@
|
||||
"""
|
||||
Tests for offsets.CustomBusinessHour
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import (
|
||||
datetime,
|
||||
time as dt_time,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import Timestamp
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
BusinessHour,
|
||||
CustomBusinessHour,
|
||||
Nano,
|
||||
)
|
||||
|
||||
from pandas.tests.tseries.offsets.common import assert_offset_equal
|
||||
|
||||
from pandas.tseries.holiday import USFederalHolidayCalendar
|
||||
|
||||
holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dt():
|
||||
return datetime(2014, 7, 1, 10, 00)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def _offset():
|
||||
return CustomBusinessHour
|
||||
|
||||
|
||||
# 2014 Calendar to check custom holidays
|
||||
# Sun Mon Tue Wed Thu Fri Sat
|
||||
# 6/22 23 24 25 26 27 28
|
||||
# 29 30 7/1 2 3 4 5
|
||||
# 6 7 8 9 10 11 12
|
||||
@pytest.fixture
|
||||
def offset1():
|
||||
return CustomBusinessHour(weekmask="Tue Wed Thu Fri")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def offset2():
|
||||
return CustomBusinessHour(holidays=holidays)
|
||||
|
||||
|
||||
class TestCustomBusinessHour:
|
||||
def test_constructor_errors(self):
|
||||
msg = "time data must be specified only with hour and minute"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
CustomBusinessHour(start=dt_time(11, 0, 5))
|
||||
msg = "time data must match '%H:%M' format"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
CustomBusinessHour(start="AAA")
|
||||
msg = "time data must match '%H:%M' format"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
CustomBusinessHour(start="14:00:05")
|
||||
|
||||
def test_different_normalize_equals(self, _offset):
|
||||
# GH#21404 changed __eq__ to return False when `normalize` does not match
|
||||
offset = _offset()
|
||||
offset2 = _offset(normalize=True)
|
||||
assert offset != offset2
|
||||
|
||||
def test_repr(self, offset1, offset2):
|
||||
assert repr(offset1) == "<CustomBusinessHour: cbh=09:00-17:00>"
|
||||
assert repr(offset2) == "<CustomBusinessHour: cbh=09:00-17:00>"
|
||||
|
||||
def test_with_offset(self, dt):
|
||||
expected = Timestamp("2014-07-01 13:00")
|
||||
|
||||
assert dt + CustomBusinessHour() * 3 == expected
|
||||
assert dt + CustomBusinessHour(n=3) == expected
|
||||
|
||||
def test_eq(self, offset1, offset2):
|
||||
for offset in [offset1, offset2]:
|
||||
assert offset == offset
|
||||
|
||||
assert CustomBusinessHour() != CustomBusinessHour(-1)
|
||||
assert CustomBusinessHour(start="09:00") == CustomBusinessHour()
|
||||
assert CustomBusinessHour(start="09:00") != CustomBusinessHour(start="09:01")
|
||||
assert CustomBusinessHour(start="09:00", end="17:00") != CustomBusinessHour(
|
||||
start="17:00", end="09:01"
|
||||
)
|
||||
|
||||
assert CustomBusinessHour(weekmask="Tue Wed Thu Fri") != CustomBusinessHour(
|
||||
weekmask="Mon Tue Wed Thu Fri"
|
||||
)
|
||||
assert CustomBusinessHour(holidays=["2014-06-27"]) != CustomBusinessHour(
|
||||
holidays=["2014-06-28"]
|
||||
)
|
||||
|
||||
def test_hash(self, offset1, offset2):
|
||||
assert hash(offset1) == hash(offset1)
|
||||
assert hash(offset2) == hash(offset2)
|
||||
|
||||
def test_add_dateime(self, dt, offset1, offset2):
|
||||
assert offset1 + dt == datetime(2014, 7, 1, 11)
|
||||
assert offset2 + dt == datetime(2014, 7, 1, 11)
|
||||
|
||||
def testRollback1(self, dt, offset1, offset2):
|
||||
assert offset1.rollback(dt) == dt
|
||||
assert offset2.rollback(dt) == dt
|
||||
|
||||
d = datetime(2014, 7, 1, 0)
|
||||
|
||||
# 2014/07/01 is Tuesday, 06/30 is Monday(holiday)
|
||||
assert offset1.rollback(d) == datetime(2014, 6, 27, 17)
|
||||
|
||||
# 2014/6/30 and 2014/6/27 are holidays
|
||||
assert offset2.rollback(d) == datetime(2014, 6, 26, 17)
|
||||
|
||||
def testRollback2(self, _offset):
|
||||
assert _offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime(
|
||||
2014, 7, 4, 17, 0
|
||||
)
|
||||
|
||||
def testRollforward1(self, dt, offset1, offset2):
|
||||
assert offset1.rollforward(dt) == dt
|
||||
assert offset2.rollforward(dt) == dt
|
||||
|
||||
d = datetime(2014, 7, 1, 0)
|
||||
assert offset1.rollforward(d) == datetime(2014, 7, 1, 9)
|
||||
assert offset2.rollforward(d) == datetime(2014, 7, 1, 9)
|
||||
|
||||
def testRollforward2(self, _offset):
|
||||
assert _offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime(
|
||||
2014, 7, 7, 9
|
||||
)
|
||||
|
||||
def test_roll_date_object(self):
|
||||
offset = BusinessHour()
|
||||
|
||||
dt = datetime(2014, 7, 6, 15, 0)
|
||||
|
||||
result = offset.rollback(dt)
|
||||
assert result == datetime(2014, 7, 4, 17)
|
||||
|
||||
result = offset.rollforward(dt)
|
||||
assert result == datetime(2014, 7, 7, 9)
|
||||
|
||||
normalize_cases = [
|
||||
(
|
||||
CustomBusinessHour(normalize=True, holidays=holidays),
|
||||
{
|
||||
datetime(2014, 7, 1, 8): datetime(2014, 7, 1),
|
||||
datetime(2014, 7, 1, 17): datetime(2014, 7, 3),
|
||||
datetime(2014, 7, 1, 16): datetime(2014, 7, 3),
|
||||
datetime(2014, 7, 1, 23): datetime(2014, 7, 3),
|
||||
datetime(2014, 7, 1, 0): datetime(2014, 7, 1),
|
||||
datetime(2014, 7, 4, 15): datetime(2014, 7, 4),
|
||||
datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4),
|
||||
datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7),
|
||||
datetime(2014, 7, 5, 23): datetime(2014, 7, 7),
|
||||
datetime(2014, 7, 6, 10): datetime(2014, 7, 7),
|
||||
},
|
||||
),
|
||||
(
|
||||
CustomBusinessHour(-1, normalize=True, holidays=holidays),
|
||||
{
|
||||
datetime(2014, 7, 1, 8): datetime(2014, 6, 26),
|
||||
datetime(2014, 7, 1, 17): datetime(2014, 7, 1),
|
||||
datetime(2014, 7, 1, 16): datetime(2014, 7, 1),
|
||||
datetime(2014, 7, 1, 10): datetime(2014, 6, 26),
|
||||
datetime(2014, 7, 1, 0): datetime(2014, 6, 26),
|
||||
datetime(2014, 7, 7, 10): datetime(2014, 7, 4),
|
||||
datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7),
|
||||
datetime(2014, 7, 5, 23): datetime(2014, 7, 4),
|
||||
datetime(2014, 7, 6, 10): datetime(2014, 7, 4),
|
||||
},
|
||||
),
|
||||
(
|
||||
CustomBusinessHour(
|
||||
1, normalize=True, start="17:00", end="04:00", holidays=holidays
|
||||
),
|
||||
{
|
||||
datetime(2014, 7, 1, 8): datetime(2014, 7, 1),
|
||||
datetime(2014, 7, 1, 17): datetime(2014, 7, 1),
|
||||
datetime(2014, 7, 1, 23): datetime(2014, 7, 2),
|
||||
datetime(2014, 7, 2, 2): datetime(2014, 7, 2),
|
||||
datetime(2014, 7, 2, 3): datetime(2014, 7, 3),
|
||||
datetime(2014, 7, 4, 23): datetime(2014, 7, 5),
|
||||
datetime(2014, 7, 5, 2): datetime(2014, 7, 5),
|
||||
datetime(2014, 7, 7, 2): datetime(2014, 7, 7),
|
||||
datetime(2014, 7, 7, 17): datetime(2014, 7, 7),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("norm_cases", normalize_cases)
|
||||
def test_normalize(self, norm_cases):
|
||||
offset, cases = norm_cases
|
||||
for dt, expected in cases.items():
|
||||
assert offset._apply(dt) == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dt, expected",
|
||||
[
|
||||
[datetime(2014, 7, 1, 9), False],
|
||||
[datetime(2014, 7, 1, 10), True],
|
||||
[datetime(2014, 7, 1, 15), True],
|
||||
[datetime(2014, 7, 1, 15, 1), False],
|
||||
[datetime(2014, 7, 5, 12), False],
|
||||
[datetime(2014, 7, 6, 12), False],
|
||||
],
|
||||
)
|
||||
def test_is_on_offset(self, dt, expected):
|
||||
offset = CustomBusinessHour(start="10:00", end="15:00", holidays=holidays)
|
||||
assert offset.is_on_offset(dt) == expected
|
||||
|
||||
apply_cases = [
|
||||
(
|
||||
CustomBusinessHour(holidays=holidays),
|
||||
{
|
||||
datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12),
|
||||
datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14),
|
||||
datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16),
|
||||
datetime(2014, 7, 1, 19): datetime(2014, 7, 3, 10),
|
||||
datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 9),
|
||||
datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 3, 9, 30, 15),
|
||||
datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 10),
|
||||
datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 10),
|
||||
# out of business hours
|
||||
datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 10),
|
||||
datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10),
|
||||
datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10),
|
||||
datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10),
|
||||
# saturday
|
||||
datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10),
|
||||
datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10),
|
||||
datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30),
|
||||
datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30),
|
||||
},
|
||||
),
|
||||
(
|
||||
CustomBusinessHour(4, holidays=holidays),
|
||||
{
|
||||
datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15),
|
||||
datetime(2014, 7, 1, 13): datetime(2014, 7, 3, 9),
|
||||
datetime(2014, 7, 1, 15): datetime(2014, 7, 3, 11),
|
||||
datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 12),
|
||||
datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 13),
|
||||
datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 13),
|
||||
datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 13),
|
||||
datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13),
|
||||
datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13),
|
||||
datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13),
|
||||
datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13),
|
||||
datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13),
|
||||
datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30),
|
||||
datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("apply_case", apply_cases)
|
||||
def test_apply(self, apply_case):
|
||||
offset, cases = apply_case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
nano_cases = [
|
||||
(
|
||||
CustomBusinessHour(holidays=holidays),
|
||||
{
|
||||
Timestamp("2014-07-01 15:00")
|
||||
+ Nano(5): Timestamp("2014-07-01 16:00")
|
||||
+ Nano(5),
|
||||
Timestamp("2014-07-01 16:00")
|
||||
+ Nano(5): Timestamp("2014-07-03 09:00")
|
||||
+ Nano(5),
|
||||
Timestamp("2014-07-01 16:00")
|
||||
- Nano(5): Timestamp("2014-07-01 17:00")
|
||||
- Nano(5),
|
||||
},
|
||||
),
|
||||
(
|
||||
CustomBusinessHour(-1, holidays=holidays),
|
||||
{
|
||||
Timestamp("2014-07-01 15:00")
|
||||
+ Nano(5): Timestamp("2014-07-01 14:00")
|
||||
+ Nano(5),
|
||||
Timestamp("2014-07-01 10:00")
|
||||
+ Nano(5): Timestamp("2014-07-01 09:00")
|
||||
+ Nano(5),
|
||||
Timestamp("2014-07-01 10:00")
|
||||
- Nano(5): Timestamp("2014-06-26 17:00")
|
||||
- Nano(5),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("nano_case", nano_cases)
|
||||
def test_apply_nanoseconds(self, nano_case):
|
||||
offset, cases = nano_case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
def test_us_federal_holiday_with_datetime(self):
|
||||
# GH 16867
|
||||
bhour_us = CustomBusinessHour(calendar=USFederalHolidayCalendar())
|
||||
t0 = datetime(2014, 1, 17, 15)
|
||||
result = t0 + bhour_us * 8
|
||||
expected = Timestamp("2014-01-21 15:00:00")
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"weekmask, expected_time, mult",
|
||||
[
|
||||
["Mon Tue Wed Thu Fri Sat", "2018-11-10 09:00:00", 10],
|
||||
["Tue Wed Thu Fri Sat", "2018-11-13 08:00:00", 18],
|
||||
],
|
||||
)
|
||||
def test_custom_businesshour_weekmask_and_holidays(weekmask, expected_time, mult):
|
||||
# GH 23542
|
||||
holidays = ["2018-11-09"]
|
||||
bh = CustomBusinessHour(
|
||||
start="08:00", end="17:00", weekmask=weekmask, holidays=holidays
|
||||
)
|
||||
result = Timestamp("2018-11-08 08:00") + mult * bh
|
||||
expected = Timestamp(expected_time)
|
||||
assert result == expected
|
@ -0,0 +1,437 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- CustomBusinessMonthBase
|
||||
- CustomBusinessMonthBegin
|
||||
- CustomBusinessMonthEnd
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import (
|
||||
date,
|
||||
datetime,
|
||||
timedelta,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
CBMonthBegin,
|
||||
CBMonthEnd,
|
||||
CDay,
|
||||
)
|
||||
|
||||
import pandas._testing as tm
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries import offsets
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dt():
|
||||
return datetime(2008, 1, 1)
|
||||
|
||||
|
||||
class TestCommonCBM:
|
||||
@pytest.mark.parametrize("offset2", [CBMonthBegin(2), CBMonthEnd(2)])
|
||||
def test_eq(self, offset2):
|
||||
assert offset2 == offset2
|
||||
|
||||
@pytest.mark.parametrize("offset2", [CBMonthBegin(2), CBMonthEnd(2)])
|
||||
def test_hash(self, offset2):
|
||||
assert hash(offset2) == hash(offset2)
|
||||
|
||||
@pytest.mark.parametrize("_offset", [CBMonthBegin, CBMonthEnd])
|
||||
def test_roundtrip_pickle(self, _offset):
|
||||
def _check_roundtrip(obj):
|
||||
unpickled = tm.round_trip_pickle(obj)
|
||||
assert unpickled == obj
|
||||
|
||||
_check_roundtrip(_offset())
|
||||
_check_roundtrip(_offset(2))
|
||||
_check_roundtrip(_offset() * 2)
|
||||
|
||||
@pytest.mark.parametrize("_offset", [CBMonthBegin, CBMonthEnd])
|
||||
def test_copy(self, _offset):
|
||||
# GH 17452
|
||||
off = _offset(weekmask="Mon Wed Fri")
|
||||
assert off == off.copy()
|
||||
|
||||
|
||||
class TestCustomBusinessMonthBegin:
|
||||
@pytest.fixture
|
||||
def _offset(self):
|
||||
return CBMonthBegin
|
||||
|
||||
@pytest.fixture
|
||||
def offset(self):
|
||||
return CBMonthBegin()
|
||||
|
||||
@pytest.fixture
|
||||
def offset2(self):
|
||||
return CBMonthBegin(2)
|
||||
|
||||
def test_different_normalize_equals(self, _offset):
|
||||
# GH#21404 changed __eq__ to return False when `normalize` does not match
|
||||
offset = _offset()
|
||||
offset2 = _offset(normalize=True)
|
||||
assert offset != offset2
|
||||
|
||||
def test_repr(self, offset, offset2):
|
||||
assert repr(offset) == "<CustomBusinessMonthBegin>"
|
||||
assert repr(offset2) == "<2 * CustomBusinessMonthBegins>"
|
||||
|
||||
def test_add_datetime(self, dt, offset2):
|
||||
assert offset2 + dt == datetime(2008, 3, 3)
|
||||
|
||||
def testRollback1(self):
|
||||
assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31)
|
||||
|
||||
def testRollback2(self, dt):
|
||||
assert CBMonthBegin(10).rollback(dt) == datetime(2008, 1, 1)
|
||||
|
||||
def testRollforward1(self, dt):
|
||||
assert CBMonthBegin(10).rollforward(dt) == datetime(2008, 1, 1)
|
||||
|
||||
def test_roll_date_object(self):
|
||||
offset = CBMonthBegin()
|
||||
|
||||
dt = date(2012, 9, 15)
|
||||
|
||||
result = offset.rollback(dt)
|
||||
assert result == datetime(2012, 9, 3)
|
||||
|
||||
result = offset.rollforward(dt)
|
||||
assert result == datetime(2012, 10, 1)
|
||||
|
||||
offset = offsets.Day()
|
||||
result = offset.rollback(dt)
|
||||
assert result == datetime(2012, 9, 15)
|
||||
|
||||
result = offset.rollforward(dt)
|
||||
assert result == datetime(2012, 9, 15)
|
||||
|
||||
on_offset_cases = [
|
||||
(CBMonthBegin(), datetime(2008, 1, 1), True),
|
||||
(CBMonthBegin(), datetime(2008, 1, 31), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
apply_cases = [
|
||||
(
|
||||
CBMonthBegin(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 2, 1),
|
||||
datetime(2008, 2, 7): datetime(2008, 3, 3),
|
||||
},
|
||||
),
|
||||
(
|
||||
2 * CBMonthBegin(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 3, 3),
|
||||
datetime(2008, 2, 7): datetime(2008, 4, 1),
|
||||
},
|
||||
),
|
||||
(
|
||||
-CBMonthBegin(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 12, 3),
|
||||
datetime(2008, 2, 8): datetime(2008, 2, 1),
|
||||
},
|
||||
),
|
||||
(
|
||||
-2 * CBMonthBegin(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 11, 1),
|
||||
datetime(2008, 2, 9): datetime(2008, 1, 1),
|
||||
},
|
||||
),
|
||||
(
|
||||
CBMonthBegin(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2008, 1, 7): datetime(2008, 2, 1),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", apply_cases)
|
||||
def test_apply(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
def test_apply_large_n(self):
|
||||
dt = datetime(2012, 10, 23)
|
||||
|
||||
result = dt + CBMonthBegin(10)
|
||||
assert result == datetime(2013, 8, 1)
|
||||
|
||||
result = dt + CDay(100) - CDay(100)
|
||||
assert result == dt
|
||||
|
||||
off = CBMonthBegin() * 6
|
||||
rs = datetime(2012, 1, 1) - off
|
||||
xp = datetime(2011, 7, 1)
|
||||
assert rs == xp
|
||||
|
||||
st = datetime(2011, 12, 18)
|
||||
rs = st + off
|
||||
|
||||
xp = datetime(2012, 6, 1)
|
||||
assert rs == xp
|
||||
|
||||
def test_holidays(self):
|
||||
# Define a TradingDay offset
|
||||
holidays = ["2012-02-01", datetime(2012, 2, 2), np.datetime64("2012-03-01")]
|
||||
bm_offset = CBMonthBegin(holidays=holidays)
|
||||
dt = datetime(2012, 1, 1)
|
||||
|
||||
assert dt + bm_offset == datetime(2012, 1, 2)
|
||||
assert dt + 2 * bm_offset == datetime(2012, 2, 3)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"case",
|
||||
[
|
||||
(
|
||||
CBMonthBegin(n=1, offset=timedelta(days=5)),
|
||||
{
|
||||
datetime(2021, 3, 1): datetime(2021, 4, 1) + timedelta(days=5),
|
||||
datetime(2021, 4, 17): datetime(2021, 5, 3) + timedelta(days=5),
|
||||
},
|
||||
),
|
||||
(
|
||||
CBMonthBegin(n=2, offset=timedelta(days=40)),
|
||||
{
|
||||
datetime(2021, 3, 10): datetime(2021, 5, 3) + timedelta(days=40),
|
||||
datetime(2021, 4, 30): datetime(2021, 6, 1) + timedelta(days=40),
|
||||
},
|
||||
),
|
||||
(
|
||||
CBMonthBegin(n=1, offset=timedelta(days=-5)),
|
||||
{
|
||||
datetime(2021, 3, 1): datetime(2021, 4, 1) - timedelta(days=5),
|
||||
datetime(2021, 4, 11): datetime(2021, 5, 3) - timedelta(days=5),
|
||||
},
|
||||
),
|
||||
(
|
||||
-2 * CBMonthBegin(n=1, offset=timedelta(days=10)),
|
||||
{
|
||||
datetime(2021, 3, 1): datetime(2021, 1, 1) + timedelta(days=10),
|
||||
datetime(2021, 4, 3): datetime(2021, 3, 1) + timedelta(days=10),
|
||||
},
|
||||
),
|
||||
(
|
||||
CBMonthBegin(n=0, offset=timedelta(days=1)),
|
||||
{
|
||||
datetime(2021, 3, 2): datetime(2021, 4, 1) + timedelta(days=1),
|
||||
datetime(2021, 4, 1): datetime(2021, 4, 1) + timedelta(days=1),
|
||||
},
|
||||
),
|
||||
(
|
||||
CBMonthBegin(
|
||||
n=1, holidays=["2021-04-01", "2021-04-02"], offset=timedelta(days=1)
|
||||
),
|
||||
{
|
||||
datetime(2021, 3, 2): datetime(2021, 4, 5) + timedelta(days=1),
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_apply_with_extra_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
|
||||
class TestCustomBusinessMonthEnd:
|
||||
@pytest.fixture
|
||||
def _offset(self):
|
||||
return CBMonthEnd
|
||||
|
||||
@pytest.fixture
|
||||
def offset(self):
|
||||
return CBMonthEnd()
|
||||
|
||||
@pytest.fixture
|
||||
def offset2(self):
|
||||
return CBMonthEnd(2)
|
||||
|
||||
def test_different_normalize_equals(self, _offset):
|
||||
# GH#21404 changed __eq__ to return False when `normalize` does not match
|
||||
offset = _offset()
|
||||
offset2 = _offset(normalize=True)
|
||||
assert offset != offset2
|
||||
|
||||
def test_repr(self, offset, offset2):
|
||||
assert repr(offset) == "<CustomBusinessMonthEnd>"
|
||||
assert repr(offset2) == "<2 * CustomBusinessMonthEnds>"
|
||||
|
||||
def test_add_datetime(self, dt, offset2):
|
||||
assert offset2 + dt == datetime(2008, 2, 29)
|
||||
|
||||
def testRollback1(self):
|
||||
assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31)
|
||||
|
||||
def testRollback2(self, dt):
|
||||
assert CBMonthEnd(10).rollback(dt) == datetime(2007, 12, 31)
|
||||
|
||||
def testRollforward1(self, dt):
|
||||
assert CBMonthEnd(10).rollforward(dt) == datetime(2008, 1, 31)
|
||||
|
||||
def test_roll_date_object(self):
|
||||
offset = CBMonthEnd()
|
||||
|
||||
dt = date(2012, 9, 15)
|
||||
|
||||
result = offset.rollback(dt)
|
||||
assert result == datetime(2012, 8, 31)
|
||||
|
||||
result = offset.rollforward(dt)
|
||||
assert result == datetime(2012, 9, 28)
|
||||
|
||||
offset = offsets.Day()
|
||||
result = offset.rollback(dt)
|
||||
assert result == datetime(2012, 9, 15)
|
||||
|
||||
result = offset.rollforward(dt)
|
||||
assert result == datetime(2012, 9, 15)
|
||||
|
||||
on_offset_cases = [
|
||||
(CBMonthEnd(), datetime(2008, 1, 31), True),
|
||||
(CBMonthEnd(), datetime(2008, 1, 1), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
apply_cases = [
|
||||
(
|
||||
CBMonthEnd(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 2, 7): datetime(2008, 2, 29),
|
||||
},
|
||||
),
|
||||
(
|
||||
2 * CBMonthEnd(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 2, 29),
|
||||
datetime(2008, 2, 7): datetime(2008, 3, 31),
|
||||
},
|
||||
),
|
||||
(
|
||||
-CBMonthEnd(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 12, 31),
|
||||
datetime(2008, 2, 8): datetime(2008, 1, 31),
|
||||
},
|
||||
),
|
||||
(
|
||||
-2 * CBMonthEnd(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 11, 30),
|
||||
datetime(2008, 2, 9): datetime(2007, 12, 31),
|
||||
},
|
||||
),
|
||||
(
|
||||
CBMonthEnd(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 2, 7): datetime(2008, 2, 29),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", apply_cases)
|
||||
def test_apply(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
def test_apply_large_n(self):
|
||||
dt = datetime(2012, 10, 23)
|
||||
|
||||
result = dt + CBMonthEnd(10)
|
||||
assert result == datetime(2013, 7, 31)
|
||||
|
||||
result = dt + CDay(100) - CDay(100)
|
||||
assert result == dt
|
||||
|
||||
off = CBMonthEnd() * 6
|
||||
rs = datetime(2012, 1, 1) - off
|
||||
xp = datetime(2011, 7, 29)
|
||||
assert rs == xp
|
||||
|
||||
st = datetime(2011, 12, 18)
|
||||
rs = st + off
|
||||
xp = datetime(2012, 5, 31)
|
||||
assert rs == xp
|
||||
|
||||
def test_holidays(self):
|
||||
# Define a TradingDay offset
|
||||
holidays = ["2012-01-31", datetime(2012, 2, 28), np.datetime64("2012-02-29")]
|
||||
bm_offset = CBMonthEnd(holidays=holidays)
|
||||
dt = datetime(2012, 1, 1)
|
||||
assert dt + bm_offset == datetime(2012, 1, 30)
|
||||
assert dt + 2 * bm_offset == datetime(2012, 2, 27)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"case",
|
||||
[
|
||||
(
|
||||
CBMonthEnd(n=1, offset=timedelta(days=5)),
|
||||
{
|
||||
datetime(2021, 3, 1): datetime(2021, 3, 31) + timedelta(days=5),
|
||||
datetime(2021, 4, 17): datetime(2021, 4, 30) + timedelta(days=5),
|
||||
},
|
||||
),
|
||||
(
|
||||
CBMonthEnd(n=2, offset=timedelta(days=40)),
|
||||
{
|
||||
datetime(2021, 3, 10): datetime(2021, 4, 30) + timedelta(days=40),
|
||||
datetime(2021, 4, 30): datetime(2021, 6, 30) + timedelta(days=40),
|
||||
},
|
||||
),
|
||||
(
|
||||
CBMonthEnd(n=1, offset=timedelta(days=-5)),
|
||||
{
|
||||
datetime(2021, 3, 1): datetime(2021, 3, 31) - timedelta(days=5),
|
||||
datetime(2021, 4, 11): datetime(2021, 4, 30) - timedelta(days=5),
|
||||
},
|
||||
),
|
||||
(
|
||||
-2 * CBMonthEnd(n=1, offset=timedelta(days=10)),
|
||||
{
|
||||
datetime(2021, 3, 1): datetime(2021, 1, 29) + timedelta(days=10),
|
||||
datetime(2021, 4, 3): datetime(2021, 2, 26) + timedelta(days=10),
|
||||
},
|
||||
),
|
||||
(
|
||||
CBMonthEnd(n=0, offset=timedelta(days=1)),
|
||||
{
|
||||
datetime(2021, 3, 2): datetime(2021, 3, 31) + timedelta(days=1),
|
||||
datetime(2021, 4, 1): datetime(2021, 4, 30) + timedelta(days=1),
|
||||
},
|
||||
),
|
||||
(
|
||||
CBMonthEnd(n=1, holidays=["2021-03-31"], offset=timedelta(days=1)),
|
||||
{
|
||||
datetime(2021, 3, 2): datetime(2021, 3, 30) + timedelta(days=1),
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_apply_with_extra_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
@ -0,0 +1,260 @@
|
||||
"""
|
||||
Tests for DateOffset additions over Daylight Savings Time
|
||||
"""
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from pandas._libs.tslibs import Timestamp
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
BMonthBegin,
|
||||
BMonthEnd,
|
||||
BQuarterBegin,
|
||||
BQuarterEnd,
|
||||
BYearBegin,
|
||||
BYearEnd,
|
||||
CBMonthBegin,
|
||||
CBMonthEnd,
|
||||
CustomBusinessDay,
|
||||
DateOffset,
|
||||
Day,
|
||||
MonthBegin,
|
||||
MonthEnd,
|
||||
QuarterBegin,
|
||||
QuarterEnd,
|
||||
SemiMonthBegin,
|
||||
SemiMonthEnd,
|
||||
Week,
|
||||
YearBegin,
|
||||
YearEnd,
|
||||
)
|
||||
from pandas.errors import PerformanceWarning
|
||||
|
||||
from pandas import DatetimeIndex
|
||||
import pandas._testing as tm
|
||||
from pandas.util.version import Version
|
||||
|
||||
# error: Module has no attribute "__version__"
|
||||
pytz_version = Version(pytz.__version__) # type: ignore[attr-defined]
|
||||
|
||||
|
||||
def get_utc_offset_hours(ts):
|
||||
# take a Timestamp and compute total hours of utc offset
|
||||
o = ts.utcoffset()
|
||||
return (o.days * 24 * 3600 + o.seconds) / 3600.0
|
||||
|
||||
|
||||
class TestDST:
|
||||
# one microsecond before the DST transition
|
||||
ts_pre_fallback = "2013-11-03 01:59:59.999999"
|
||||
ts_pre_springfwd = "2013-03-10 01:59:59.999999"
|
||||
|
||||
# test both basic names and dateutil timezones
|
||||
timezone_utc_offsets = {
|
||||
"US/Eastern": {"utc_offset_daylight": -4, "utc_offset_standard": -5},
|
||||
"dateutil/US/Pacific": {"utc_offset_daylight": -7, "utc_offset_standard": -8},
|
||||
}
|
||||
valid_date_offsets_singular = [
|
||||
"weekday",
|
||||
"day",
|
||||
"hour",
|
||||
"minute",
|
||||
"second",
|
||||
"microsecond",
|
||||
]
|
||||
valid_date_offsets_plural = [
|
||||
"weeks",
|
||||
"days",
|
||||
"hours",
|
||||
"minutes",
|
||||
"seconds",
|
||||
"milliseconds",
|
||||
"microseconds",
|
||||
]
|
||||
|
||||
def _test_all_offsets(self, n, **kwds):
|
||||
valid_offsets = (
|
||||
self.valid_date_offsets_plural
|
||||
if n > 1
|
||||
else self.valid_date_offsets_singular
|
||||
)
|
||||
|
||||
for name in valid_offsets:
|
||||
self._test_offset(offset_name=name, offset_n=n, **kwds)
|
||||
|
||||
def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset):
|
||||
offset = DateOffset(**{offset_name: offset_n})
|
||||
|
||||
if (
|
||||
offset_name in ["hour", "minute", "second", "microsecond"]
|
||||
and offset_n == 1
|
||||
and tstart == Timestamp("2013-11-03 01:59:59.999999-0500", tz="US/Eastern")
|
||||
):
|
||||
# This addition results in an ambiguous wall time
|
||||
err_msg = {
|
||||
"hour": "2013-11-03 01:59:59.999999",
|
||||
"minute": "2013-11-03 01:01:59.999999",
|
||||
"second": "2013-11-03 01:59:01.999999",
|
||||
"microsecond": "2013-11-03 01:59:59.000001",
|
||||
}[offset_name]
|
||||
with pytest.raises(pytz.AmbiguousTimeError, match=err_msg):
|
||||
tstart + offset
|
||||
# While we're here, let's check that we get the same behavior in a
|
||||
# vectorized path
|
||||
dti = DatetimeIndex([tstart])
|
||||
warn_msg = "Non-vectorized DateOffset"
|
||||
with pytest.raises(pytz.AmbiguousTimeError, match=err_msg):
|
||||
with tm.assert_produces_warning(PerformanceWarning, match=warn_msg):
|
||||
dti + offset
|
||||
return
|
||||
|
||||
t = tstart + offset
|
||||
if expected_utc_offset is not None:
|
||||
assert get_utc_offset_hours(t) == expected_utc_offset
|
||||
|
||||
if offset_name == "weeks":
|
||||
# dates should match
|
||||
assert t.date() == timedelta(days=7 * offset.kwds["weeks"]) + tstart.date()
|
||||
# expect the same day of week, hour of day, minute, second, ...
|
||||
assert (
|
||||
t.dayofweek == tstart.dayofweek
|
||||
and t.hour == tstart.hour
|
||||
and t.minute == tstart.minute
|
||||
and t.second == tstart.second
|
||||
)
|
||||
elif offset_name == "days":
|
||||
# dates should match
|
||||
assert timedelta(offset.kwds["days"]) + tstart.date() == t.date()
|
||||
# expect the same hour of day, minute, second, ...
|
||||
assert (
|
||||
t.hour == tstart.hour
|
||||
and t.minute == tstart.minute
|
||||
and t.second == tstart.second
|
||||
)
|
||||
elif offset_name in self.valid_date_offsets_singular:
|
||||
# expect the singular offset value to match between tstart and t
|
||||
datepart_offset = getattr(
|
||||
t, offset_name if offset_name != "weekday" else "dayofweek"
|
||||
)
|
||||
assert datepart_offset == offset.kwds[offset_name]
|
||||
else:
|
||||
# the offset should be the same as if it was done in UTC
|
||||
assert t == (tstart.tz_convert("UTC") + offset).tz_convert("US/Pacific")
|
||||
|
||||
def _make_timestamp(self, string, hrs_offset, tz):
|
||||
if hrs_offset >= 0:
|
||||
offset_string = f"{hrs_offset:02d}00"
|
||||
else:
|
||||
offset_string = f"-{(hrs_offset * -1):02}00"
|
||||
return Timestamp(string + offset_string).tz_convert(tz)
|
||||
|
||||
def test_springforward_plural(self):
|
||||
# test moving from standard to daylight savings
|
||||
for tz, utc_offsets in self.timezone_utc_offsets.items():
|
||||
hrs_pre = utc_offsets["utc_offset_standard"]
|
||||
hrs_post = utc_offsets["utc_offset_daylight"]
|
||||
self._test_all_offsets(
|
||||
n=3,
|
||||
tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz),
|
||||
expected_utc_offset=hrs_post,
|
||||
)
|
||||
|
||||
def test_fallback_singular(self):
|
||||
# in the case of singular offsets, we don't necessarily know which utc
|
||||
# offset the new Timestamp will wind up in (the tz for 1 month may be
|
||||
# different from 1 second) so we don't specify an expected_utc_offset
|
||||
for tz, utc_offsets in self.timezone_utc_offsets.items():
|
||||
hrs_pre = utc_offsets["utc_offset_standard"]
|
||||
self._test_all_offsets(
|
||||
n=1,
|
||||
tstart=self._make_timestamp(self.ts_pre_fallback, hrs_pre, tz),
|
||||
expected_utc_offset=None,
|
||||
)
|
||||
|
||||
def test_springforward_singular(self):
|
||||
for tz, utc_offsets in self.timezone_utc_offsets.items():
|
||||
hrs_pre = utc_offsets["utc_offset_standard"]
|
||||
self._test_all_offsets(
|
||||
n=1,
|
||||
tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz),
|
||||
expected_utc_offset=None,
|
||||
)
|
||||
|
||||
offset_classes = {
|
||||
MonthBegin: ["11/2/2012", "12/1/2012"],
|
||||
MonthEnd: ["11/2/2012", "11/30/2012"],
|
||||
BMonthBegin: ["11/2/2012", "12/3/2012"],
|
||||
BMonthEnd: ["11/2/2012", "11/30/2012"],
|
||||
CBMonthBegin: ["11/2/2012", "12/3/2012"],
|
||||
CBMonthEnd: ["11/2/2012", "11/30/2012"],
|
||||
SemiMonthBegin: ["11/2/2012", "11/15/2012"],
|
||||
SemiMonthEnd: ["11/2/2012", "11/15/2012"],
|
||||
Week: ["11/2/2012", "11/9/2012"],
|
||||
YearBegin: ["11/2/2012", "1/1/2013"],
|
||||
YearEnd: ["11/2/2012", "12/31/2012"],
|
||||
BYearBegin: ["11/2/2012", "1/1/2013"],
|
||||
BYearEnd: ["11/2/2012", "12/31/2012"],
|
||||
QuarterBegin: ["11/2/2012", "12/1/2012"],
|
||||
QuarterEnd: ["11/2/2012", "12/31/2012"],
|
||||
BQuarterBegin: ["11/2/2012", "12/3/2012"],
|
||||
BQuarterEnd: ["11/2/2012", "12/31/2012"],
|
||||
Day: ["11/4/2012", "11/4/2012 23:00"],
|
||||
}.items()
|
||||
|
||||
@pytest.mark.parametrize("tup", offset_classes)
|
||||
def test_all_offset_classes(self, tup):
|
||||
offset, test_values = tup
|
||||
|
||||
first = Timestamp(test_values[0], tz="US/Eastern") + offset()
|
||||
second = Timestamp(test_values[1], tz="US/Eastern")
|
||||
assert first == second
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"original_dt, target_dt, offset, tz",
|
||||
[
|
||||
pytest.param(
|
||||
Timestamp("1900-01-01"),
|
||||
Timestamp("1905-07-01"),
|
||||
MonthBegin(66),
|
||||
"Africa/Lagos",
|
||||
marks=pytest.mark.xfail(
|
||||
pytz_version < Version("2020.5") or pytz_version == Version("2022.2"),
|
||||
reason="GH#41906: pytz utc transition dates changed",
|
||||
),
|
||||
),
|
||||
(
|
||||
Timestamp("2021-10-01 01:15"),
|
||||
Timestamp("2021-10-31 01:15"),
|
||||
MonthEnd(1),
|
||||
"Europe/London",
|
||||
),
|
||||
(
|
||||
Timestamp("2010-12-05 02:59"),
|
||||
Timestamp("2010-10-31 02:59"),
|
||||
SemiMonthEnd(-3),
|
||||
"Europe/Paris",
|
||||
),
|
||||
(
|
||||
Timestamp("2021-10-31 01:20"),
|
||||
Timestamp("2021-11-07 01:20"),
|
||||
CustomBusinessDay(2, weekmask="Sun Mon"),
|
||||
"US/Eastern",
|
||||
),
|
||||
(
|
||||
Timestamp("2020-04-03 01:30"),
|
||||
Timestamp("2020-11-01 01:30"),
|
||||
YearBegin(1, month=11),
|
||||
"America/Chicago",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_nontick_offset_with_ambiguous_time_error(original_dt, target_dt, offset, tz):
|
||||
# .apply for non-Tick offsets throws AmbiguousTimeError when the target dt
|
||||
# is dst-ambiguous
|
||||
localized_dt = original_dt.tz_localize(tz)
|
||||
|
||||
msg = f"Cannot infer dst time from {target_dt}, try using the 'ambiguous' argument"
|
||||
with pytest.raises(pytz.AmbiguousTimeError, match=msg):
|
||||
localized_dt + offset
|
@ -0,0 +1,33 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- Easter
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas.tests.tseries.offsets.common import assert_offset_equal
|
||||
|
||||
from pandas.tseries.offsets import Easter
|
||||
|
||||
|
||||
class TestEaster:
|
||||
@pytest.mark.parametrize(
|
||||
"offset,date,expected",
|
||||
[
|
||||
(Easter(), datetime(2010, 1, 1), datetime(2010, 4, 4)),
|
||||
(Easter(), datetime(2010, 4, 5), datetime(2011, 4, 24)),
|
||||
(Easter(2), datetime(2010, 1, 1), datetime(2011, 4, 24)),
|
||||
(Easter(), datetime(2010, 4, 4), datetime(2011, 4, 24)),
|
||||
(Easter(2), datetime(2010, 4, 4), datetime(2012, 4, 8)),
|
||||
(-Easter(), datetime(2011, 1, 1), datetime(2010, 4, 4)),
|
||||
(-Easter(), datetime(2010, 4, 5), datetime(2010, 4, 4)),
|
||||
(-Easter(2), datetime(2011, 1, 1), datetime(2009, 4, 12)),
|
||||
(-Easter(), datetime(2010, 4, 4), datetime(2009, 4, 12)),
|
||||
(-Easter(2), datetime(2010, 4, 4), datetime(2008, 3, 23)),
|
||||
],
|
||||
)
|
||||
def test_offset(self, offset, date, expected):
|
||||
assert_offset_equal(offset, date, expected)
|
@ -0,0 +1,656 @@
|
||||
"""
|
||||
Tests for Fiscal Year and Fiscal Quarter offset classes
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import pytest
|
||||
|
||||
from pandas import Timestamp
|
||||
import pandas._testing as tm
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
WeekDay,
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
FY5253,
|
||||
FY5253Quarter,
|
||||
)
|
||||
|
||||
|
||||
def makeFY5253LastOfMonthQuarter(*args, **kwds):
|
||||
return FY5253Quarter(*args, variation="last", **kwds)
|
||||
|
||||
|
||||
def makeFY5253NearestEndMonthQuarter(*args, **kwds):
|
||||
return FY5253Quarter(*args, variation="nearest", **kwds)
|
||||
|
||||
|
||||
def makeFY5253NearestEndMonth(*args, **kwds):
|
||||
return FY5253(*args, variation="nearest", **kwds)
|
||||
|
||||
|
||||
def makeFY5253LastOfMonth(*args, **kwds):
|
||||
return FY5253(*args, variation="last", **kwds)
|
||||
|
||||
|
||||
def test_get_offset_name():
|
||||
assert (
|
||||
makeFY5253LastOfMonthQuarter(
|
||||
weekday=1, startingMonth=3, qtr_with_extra_week=4
|
||||
).freqstr
|
||||
== "REQ-L-MAR-TUE-4"
|
||||
)
|
||||
assert (
|
||||
makeFY5253NearestEndMonthQuarter(
|
||||
weekday=1, startingMonth=3, qtr_with_extra_week=3
|
||||
).freqstr
|
||||
== "REQ-N-MAR-TUE-3"
|
||||
)
|
||||
|
||||
|
||||
class TestFY5253LastOfMonth:
|
||||
offset_lom_sat_aug = makeFY5253LastOfMonth(1, startingMonth=8, weekday=WeekDay.SAT)
|
||||
offset_lom_sat_sep = makeFY5253LastOfMonth(1, startingMonth=9, weekday=WeekDay.SAT)
|
||||
|
||||
on_offset_cases = [
|
||||
# From Wikipedia (see:
|
||||
# https://en.wikipedia.org/wiki/4%E2%80%934%E2%80%935_calendar#Last_Saturday_of_the_month_at_fiscal_year_end)
|
||||
(offset_lom_sat_aug, datetime(2006, 8, 26), True),
|
||||
(offset_lom_sat_aug, datetime(2007, 8, 25), True),
|
||||
(offset_lom_sat_aug, datetime(2008, 8, 30), True),
|
||||
(offset_lom_sat_aug, datetime(2009, 8, 29), True),
|
||||
(offset_lom_sat_aug, datetime(2010, 8, 28), True),
|
||||
(offset_lom_sat_aug, datetime(2011, 8, 27), True),
|
||||
(offset_lom_sat_aug, datetime(2012, 8, 25), True),
|
||||
(offset_lom_sat_aug, datetime(2013, 8, 31), True),
|
||||
(offset_lom_sat_aug, datetime(2014, 8, 30), True),
|
||||
(offset_lom_sat_aug, datetime(2015, 8, 29), True),
|
||||
(offset_lom_sat_aug, datetime(2016, 8, 27), True),
|
||||
(offset_lom_sat_aug, datetime(2017, 8, 26), True),
|
||||
(offset_lom_sat_aug, datetime(2018, 8, 25), True),
|
||||
(offset_lom_sat_aug, datetime(2019, 8, 31), True),
|
||||
(offset_lom_sat_aug, datetime(2006, 8, 27), False),
|
||||
(offset_lom_sat_aug, datetime(2007, 8, 28), False),
|
||||
(offset_lom_sat_aug, datetime(2008, 8, 31), False),
|
||||
(offset_lom_sat_aug, datetime(2009, 8, 30), False),
|
||||
(offset_lom_sat_aug, datetime(2010, 8, 29), False),
|
||||
(offset_lom_sat_aug, datetime(2011, 8, 28), False),
|
||||
(offset_lom_sat_aug, datetime(2006, 8, 25), False),
|
||||
(offset_lom_sat_aug, datetime(2007, 8, 24), False),
|
||||
(offset_lom_sat_aug, datetime(2008, 8, 29), False),
|
||||
(offset_lom_sat_aug, datetime(2009, 8, 28), False),
|
||||
(offset_lom_sat_aug, datetime(2010, 8, 27), False),
|
||||
(offset_lom_sat_aug, datetime(2011, 8, 26), False),
|
||||
(offset_lom_sat_aug, datetime(2019, 8, 30), False),
|
||||
# From GMCR (see for example:
|
||||
# http://yahoo.brand.edgar-online.com/Default.aspx?
|
||||
# companyid=3184&formtypeID=7)
|
||||
(offset_lom_sat_sep, datetime(2010, 9, 25), True),
|
||||
(offset_lom_sat_sep, datetime(2011, 9, 24), True),
|
||||
(offset_lom_sat_sep, datetime(2012, 9, 29), True),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
def test_apply(self):
|
||||
offset_lom_aug_sat = makeFY5253LastOfMonth(startingMonth=8, weekday=WeekDay.SAT)
|
||||
offset_lom_aug_sat_1 = makeFY5253LastOfMonth(
|
||||
n=1, startingMonth=8, weekday=WeekDay.SAT
|
||||
)
|
||||
|
||||
date_seq_lom_aug_sat = [
|
||||
datetime(2006, 8, 26),
|
||||
datetime(2007, 8, 25),
|
||||
datetime(2008, 8, 30),
|
||||
datetime(2009, 8, 29),
|
||||
datetime(2010, 8, 28),
|
||||
datetime(2011, 8, 27),
|
||||
datetime(2012, 8, 25),
|
||||
datetime(2013, 8, 31),
|
||||
datetime(2014, 8, 30),
|
||||
datetime(2015, 8, 29),
|
||||
datetime(2016, 8, 27),
|
||||
]
|
||||
|
||||
tests = [
|
||||
(offset_lom_aug_sat, date_seq_lom_aug_sat),
|
||||
(offset_lom_aug_sat_1, date_seq_lom_aug_sat),
|
||||
(offset_lom_aug_sat, [datetime(2006, 8, 25)] + date_seq_lom_aug_sat),
|
||||
(offset_lom_aug_sat_1, [datetime(2006, 8, 27)] + date_seq_lom_aug_sat[1:]),
|
||||
(
|
||||
makeFY5253LastOfMonth(n=-1, startingMonth=8, weekday=WeekDay.SAT),
|
||||
list(reversed(date_seq_lom_aug_sat)),
|
||||
),
|
||||
]
|
||||
for test in tests:
|
||||
offset, data = test
|
||||
current = data[0]
|
||||
for datum in data[1:]:
|
||||
current = current + offset
|
||||
assert current == datum
|
||||
|
||||
|
||||
class TestFY5253NearestEndMonth:
|
||||
def test_get_year_end(self):
|
||||
assert makeFY5253NearestEndMonth(
|
||||
startingMonth=8, weekday=WeekDay.SAT
|
||||
).get_year_end(datetime(2013, 1, 1)) == datetime(2013, 8, 31)
|
||||
assert makeFY5253NearestEndMonth(
|
||||
startingMonth=8, weekday=WeekDay.SUN
|
||||
).get_year_end(datetime(2013, 1, 1)) == datetime(2013, 9, 1)
|
||||
assert makeFY5253NearestEndMonth(
|
||||
startingMonth=8, weekday=WeekDay.FRI
|
||||
).get_year_end(datetime(2013, 1, 1)) == datetime(2013, 8, 30)
|
||||
|
||||
offset_n = FY5253(weekday=WeekDay.TUE, startingMonth=12, variation="nearest")
|
||||
assert offset_n.get_year_end(datetime(2012, 1, 1)) == datetime(2013, 1, 1)
|
||||
assert offset_n.get_year_end(datetime(2012, 1, 10)) == datetime(2013, 1, 1)
|
||||
|
||||
assert offset_n.get_year_end(datetime(2013, 1, 1)) == datetime(2013, 12, 31)
|
||||
assert offset_n.get_year_end(datetime(2013, 1, 2)) == datetime(2013, 12, 31)
|
||||
assert offset_n.get_year_end(datetime(2013, 1, 3)) == datetime(2013, 12, 31)
|
||||
assert offset_n.get_year_end(datetime(2013, 1, 10)) == datetime(2013, 12, 31)
|
||||
|
||||
JNJ = FY5253(n=1, startingMonth=12, weekday=6, variation="nearest")
|
||||
assert JNJ.get_year_end(datetime(2006, 1, 1)) == datetime(2006, 12, 31)
|
||||
|
||||
offset_lom_aug_sat = makeFY5253NearestEndMonth(
|
||||
1, startingMonth=8, weekday=WeekDay.SAT
|
||||
)
|
||||
offset_lom_aug_thu = makeFY5253NearestEndMonth(
|
||||
1, startingMonth=8, weekday=WeekDay.THU
|
||||
)
|
||||
offset_n = FY5253(weekday=WeekDay.TUE, startingMonth=12, variation="nearest")
|
||||
|
||||
on_offset_cases = [
|
||||
# From Wikipedia (see:
|
||||
# https://en.wikipedia.org/wiki/4%E2%80%934%E2%80%935_calendar
|
||||
# #Saturday_nearest_the_end_of_month)
|
||||
# 2006-09-02 2006 September 2
|
||||
# 2007-09-01 2007 September 1
|
||||
# 2008-08-30 2008 August 30 (leap year)
|
||||
# 2009-08-29 2009 August 29
|
||||
# 2010-08-28 2010 August 28
|
||||
# 2011-09-03 2011 September 3
|
||||
# 2012-09-01 2012 September 1 (leap year)
|
||||
# 2013-08-31 2013 August 31
|
||||
# 2014-08-30 2014 August 30
|
||||
# 2015-08-29 2015 August 29
|
||||
# 2016-09-03 2016 September 3 (leap year)
|
||||
# 2017-09-02 2017 September 2
|
||||
# 2018-09-01 2018 September 1
|
||||
# 2019-08-31 2019 August 31
|
||||
(offset_lom_aug_sat, datetime(2006, 9, 2), True),
|
||||
(offset_lom_aug_sat, datetime(2007, 9, 1), True),
|
||||
(offset_lom_aug_sat, datetime(2008, 8, 30), True),
|
||||
(offset_lom_aug_sat, datetime(2009, 8, 29), True),
|
||||
(offset_lom_aug_sat, datetime(2010, 8, 28), True),
|
||||
(offset_lom_aug_sat, datetime(2011, 9, 3), True),
|
||||
(offset_lom_aug_sat, datetime(2016, 9, 3), True),
|
||||
(offset_lom_aug_sat, datetime(2017, 9, 2), True),
|
||||
(offset_lom_aug_sat, datetime(2018, 9, 1), True),
|
||||
(offset_lom_aug_sat, datetime(2019, 8, 31), True),
|
||||
(offset_lom_aug_sat, datetime(2006, 8, 27), False),
|
||||
(offset_lom_aug_sat, datetime(2007, 8, 28), False),
|
||||
(offset_lom_aug_sat, datetime(2008, 8, 31), False),
|
||||
(offset_lom_aug_sat, datetime(2009, 8, 30), False),
|
||||
(offset_lom_aug_sat, datetime(2010, 8, 29), False),
|
||||
(offset_lom_aug_sat, datetime(2011, 8, 28), False),
|
||||
(offset_lom_aug_sat, datetime(2006, 8, 25), False),
|
||||
(offset_lom_aug_sat, datetime(2007, 8, 24), False),
|
||||
(offset_lom_aug_sat, datetime(2008, 8, 29), False),
|
||||
(offset_lom_aug_sat, datetime(2009, 8, 28), False),
|
||||
(offset_lom_aug_sat, datetime(2010, 8, 27), False),
|
||||
(offset_lom_aug_sat, datetime(2011, 8, 26), False),
|
||||
(offset_lom_aug_sat, datetime(2019, 8, 30), False),
|
||||
# From Micron, see:
|
||||
# http://google.brand.edgar-online.com/?sym=MU&formtypeID=7
|
||||
(offset_lom_aug_thu, datetime(2012, 8, 30), True),
|
||||
(offset_lom_aug_thu, datetime(2011, 9, 1), True),
|
||||
(offset_n, datetime(2012, 12, 31), False),
|
||||
(offset_n, datetime(2013, 1, 1), True),
|
||||
(offset_n, datetime(2013, 1, 2), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
def test_apply(self):
|
||||
date_seq_nem_8_sat = [
|
||||
datetime(2006, 9, 2),
|
||||
datetime(2007, 9, 1),
|
||||
datetime(2008, 8, 30),
|
||||
datetime(2009, 8, 29),
|
||||
datetime(2010, 8, 28),
|
||||
datetime(2011, 9, 3),
|
||||
]
|
||||
|
||||
JNJ = [
|
||||
datetime(2005, 1, 2),
|
||||
datetime(2006, 1, 1),
|
||||
datetime(2006, 12, 31),
|
||||
datetime(2007, 12, 30),
|
||||
datetime(2008, 12, 28),
|
||||
datetime(2010, 1, 3),
|
||||
datetime(2011, 1, 2),
|
||||
datetime(2012, 1, 1),
|
||||
datetime(2012, 12, 30),
|
||||
]
|
||||
|
||||
DEC_SAT = FY5253(n=-1, startingMonth=12, weekday=5, variation="nearest")
|
||||
|
||||
tests = [
|
||||
(
|
||||
makeFY5253NearestEndMonth(startingMonth=8, weekday=WeekDay.SAT),
|
||||
date_seq_nem_8_sat,
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=1, startingMonth=8, weekday=WeekDay.SAT),
|
||||
date_seq_nem_8_sat,
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(startingMonth=8, weekday=WeekDay.SAT),
|
||||
[datetime(2006, 9, 1)] + date_seq_nem_8_sat,
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=1, startingMonth=8, weekday=WeekDay.SAT),
|
||||
[datetime(2006, 9, 3)] + date_seq_nem_8_sat[1:],
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=-1, startingMonth=8, weekday=WeekDay.SAT),
|
||||
list(reversed(date_seq_nem_8_sat)),
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=1, startingMonth=12, weekday=WeekDay.SUN),
|
||||
JNJ,
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=-1, startingMonth=12, weekday=WeekDay.SUN),
|
||||
list(reversed(JNJ)),
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=1, startingMonth=12, weekday=WeekDay.SUN),
|
||||
[datetime(2005, 1, 2), datetime(2006, 1, 1)],
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=1, startingMonth=12, weekday=WeekDay.SUN),
|
||||
[datetime(2006, 1, 2), datetime(2006, 12, 31)],
|
||||
),
|
||||
(DEC_SAT, [datetime(2013, 1, 15), datetime(2012, 12, 29)]),
|
||||
]
|
||||
for test in tests:
|
||||
offset, data = test
|
||||
current = data[0]
|
||||
for datum in data[1:]:
|
||||
current = current + offset
|
||||
assert current == datum
|
||||
|
||||
|
||||
class TestFY5253LastOfMonthQuarter:
|
||||
def test_is_anchored(self):
|
||||
msg = "FY5253Quarter.is_anchored is deprecated "
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
).is_anchored()
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
weekday=WeekDay.SAT, startingMonth=3, qtr_with_extra_week=4
|
||||
).is_anchored()
|
||||
assert not makeFY5253LastOfMonthQuarter(
|
||||
2, startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
).is_anchored()
|
||||
|
||||
def test_equality(self):
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
) == makeFY5253LastOfMonthQuarter(
|
||||
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
) != makeFY5253LastOfMonthQuarter(
|
||||
startingMonth=1, weekday=WeekDay.SUN, qtr_with_extra_week=4
|
||||
)
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
) != makeFY5253LastOfMonthQuarter(
|
||||
startingMonth=2, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
|
||||
def test_offset(self):
|
||||
offset = makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
offset2 = makeFY5253LastOfMonthQuarter(
|
||||
2, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
offset4 = makeFY5253LastOfMonthQuarter(
|
||||
4, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
|
||||
offset_neg1 = makeFY5253LastOfMonthQuarter(
|
||||
-1, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
offset_neg2 = makeFY5253LastOfMonthQuarter(
|
||||
-2, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
|
||||
GMCR = [
|
||||
datetime(2010, 3, 27),
|
||||
datetime(2010, 6, 26),
|
||||
datetime(2010, 9, 25),
|
||||
datetime(2010, 12, 25),
|
||||
datetime(2011, 3, 26),
|
||||
datetime(2011, 6, 25),
|
||||
datetime(2011, 9, 24),
|
||||
datetime(2011, 12, 24),
|
||||
datetime(2012, 3, 24),
|
||||
datetime(2012, 6, 23),
|
||||
datetime(2012, 9, 29),
|
||||
datetime(2012, 12, 29),
|
||||
datetime(2013, 3, 30),
|
||||
datetime(2013, 6, 29),
|
||||
]
|
||||
|
||||
assert_offset_equal(offset, base=GMCR[0], expected=GMCR[1])
|
||||
assert_offset_equal(
|
||||
offset, base=GMCR[0] + relativedelta(days=-1), expected=GMCR[0]
|
||||
)
|
||||
assert_offset_equal(offset, base=GMCR[1], expected=GMCR[2])
|
||||
|
||||
assert_offset_equal(offset2, base=GMCR[0], expected=GMCR[2])
|
||||
assert_offset_equal(offset4, base=GMCR[0], expected=GMCR[4])
|
||||
|
||||
assert_offset_equal(offset_neg1, base=GMCR[-1], expected=GMCR[-2])
|
||||
assert_offset_equal(
|
||||
offset_neg1, base=GMCR[-1] + relativedelta(days=+1), expected=GMCR[-1]
|
||||
)
|
||||
assert_offset_equal(offset_neg2, base=GMCR[-1], expected=GMCR[-3])
|
||||
|
||||
date = GMCR[0] + relativedelta(days=-1)
|
||||
for expected in GMCR:
|
||||
assert_offset_equal(offset, date, expected)
|
||||
date = date + offset
|
||||
|
||||
date = GMCR[-1] + relativedelta(days=+1)
|
||||
for expected in reversed(GMCR):
|
||||
assert_offset_equal(offset_neg1, date, expected)
|
||||
date = date + offset_neg1
|
||||
|
||||
lomq_aug_sat_4 = makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=8, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
lomq_sep_sat_4 = makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
|
||||
on_offset_cases = [
|
||||
# From Wikipedia
|
||||
(lomq_aug_sat_4, datetime(2006, 8, 26), True),
|
||||
(lomq_aug_sat_4, datetime(2007, 8, 25), True),
|
||||
(lomq_aug_sat_4, datetime(2008, 8, 30), True),
|
||||
(lomq_aug_sat_4, datetime(2009, 8, 29), True),
|
||||
(lomq_aug_sat_4, datetime(2010, 8, 28), True),
|
||||
(lomq_aug_sat_4, datetime(2011, 8, 27), True),
|
||||
(lomq_aug_sat_4, datetime(2019, 8, 31), True),
|
||||
(lomq_aug_sat_4, datetime(2006, 8, 27), False),
|
||||
(lomq_aug_sat_4, datetime(2007, 8, 28), False),
|
||||
(lomq_aug_sat_4, datetime(2008, 8, 31), False),
|
||||
(lomq_aug_sat_4, datetime(2009, 8, 30), False),
|
||||
(lomq_aug_sat_4, datetime(2010, 8, 29), False),
|
||||
(lomq_aug_sat_4, datetime(2011, 8, 28), False),
|
||||
(lomq_aug_sat_4, datetime(2006, 8, 25), False),
|
||||
(lomq_aug_sat_4, datetime(2007, 8, 24), False),
|
||||
(lomq_aug_sat_4, datetime(2008, 8, 29), False),
|
||||
(lomq_aug_sat_4, datetime(2009, 8, 28), False),
|
||||
(lomq_aug_sat_4, datetime(2010, 8, 27), False),
|
||||
(lomq_aug_sat_4, datetime(2011, 8, 26), False),
|
||||
(lomq_aug_sat_4, datetime(2019, 8, 30), False),
|
||||
# From GMCR
|
||||
(lomq_sep_sat_4, datetime(2010, 9, 25), True),
|
||||
(lomq_sep_sat_4, datetime(2011, 9, 24), True),
|
||||
(lomq_sep_sat_4, datetime(2012, 9, 29), True),
|
||||
(lomq_sep_sat_4, datetime(2013, 6, 29), True),
|
||||
(lomq_sep_sat_4, datetime(2012, 6, 23), True),
|
||||
(lomq_sep_sat_4, datetime(2012, 6, 30), False),
|
||||
(lomq_sep_sat_4, datetime(2013, 3, 30), True),
|
||||
(lomq_sep_sat_4, datetime(2012, 3, 24), True),
|
||||
(lomq_sep_sat_4, datetime(2012, 12, 29), True),
|
||||
(lomq_sep_sat_4, datetime(2011, 12, 24), True),
|
||||
# INTC (extra week in Q1)
|
||||
# See: http://www.intc.com/releasedetail.cfm?ReleaseID=542844
|
||||
(
|
||||
makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
),
|
||||
datetime(2011, 4, 2),
|
||||
True,
|
||||
),
|
||||
# see: http://google.brand.edgar-online.com/?sym=INTC&formtypeID=7
|
||||
(
|
||||
makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
),
|
||||
datetime(2012, 12, 29),
|
||||
True,
|
||||
),
|
||||
(
|
||||
makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
),
|
||||
datetime(2011, 12, 31),
|
||||
True,
|
||||
),
|
||||
(
|
||||
makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
),
|
||||
datetime(2010, 12, 25),
|
||||
True,
|
||||
),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
def test_year_has_extra_week(self):
|
||||
# End of long Q1
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(2011, 4, 2))
|
||||
|
||||
# Start of long Q1
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(2010, 12, 26))
|
||||
|
||||
# End of year before year with long Q1
|
||||
assert not makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(2010, 12, 25))
|
||||
|
||||
for year in [
|
||||
x for x in range(1994, 2011 + 1) if x not in [2011, 2005, 2000, 1994]
|
||||
]:
|
||||
assert not makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(year, 4, 2))
|
||||
|
||||
# Other long years
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(2005, 4, 2))
|
||||
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(2000, 4, 2))
|
||||
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(1994, 4, 2))
|
||||
|
||||
def test_get_weeks(self):
|
||||
sat_dec_1 = makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
)
|
||||
sat_dec_4 = makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
|
||||
assert sat_dec_1.get_weeks(datetime(2011, 4, 2)) == [14, 13, 13, 13]
|
||||
assert sat_dec_4.get_weeks(datetime(2011, 4, 2)) == [13, 13, 13, 14]
|
||||
assert sat_dec_1.get_weeks(datetime(2010, 12, 25)) == [13, 13, 13, 13]
|
||||
|
||||
|
||||
class TestFY5253NearestEndMonthQuarter:
|
||||
offset_nem_sat_aug_4 = makeFY5253NearestEndMonthQuarter(
|
||||
1, startingMonth=8, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
offset_nem_thu_aug_4 = makeFY5253NearestEndMonthQuarter(
|
||||
1, startingMonth=8, weekday=WeekDay.THU, qtr_with_extra_week=4
|
||||
)
|
||||
offset_n = FY5253(weekday=WeekDay.TUE, startingMonth=12, variation="nearest")
|
||||
|
||||
on_offset_cases = [
|
||||
# From Wikipedia
|
||||
(offset_nem_sat_aug_4, datetime(2006, 9, 2), True),
|
||||
(offset_nem_sat_aug_4, datetime(2007, 9, 1), True),
|
||||
(offset_nem_sat_aug_4, datetime(2008, 8, 30), True),
|
||||
(offset_nem_sat_aug_4, datetime(2009, 8, 29), True),
|
||||
(offset_nem_sat_aug_4, datetime(2010, 8, 28), True),
|
||||
(offset_nem_sat_aug_4, datetime(2011, 9, 3), True),
|
||||
(offset_nem_sat_aug_4, datetime(2016, 9, 3), True),
|
||||
(offset_nem_sat_aug_4, datetime(2017, 9, 2), True),
|
||||
(offset_nem_sat_aug_4, datetime(2018, 9, 1), True),
|
||||
(offset_nem_sat_aug_4, datetime(2019, 8, 31), True),
|
||||
(offset_nem_sat_aug_4, datetime(2006, 8, 27), False),
|
||||
(offset_nem_sat_aug_4, datetime(2007, 8, 28), False),
|
||||
(offset_nem_sat_aug_4, datetime(2008, 8, 31), False),
|
||||
(offset_nem_sat_aug_4, datetime(2009, 8, 30), False),
|
||||
(offset_nem_sat_aug_4, datetime(2010, 8, 29), False),
|
||||
(offset_nem_sat_aug_4, datetime(2011, 8, 28), False),
|
||||
(offset_nem_sat_aug_4, datetime(2006, 8, 25), False),
|
||||
(offset_nem_sat_aug_4, datetime(2007, 8, 24), False),
|
||||
(offset_nem_sat_aug_4, datetime(2008, 8, 29), False),
|
||||
(offset_nem_sat_aug_4, datetime(2009, 8, 28), False),
|
||||
(offset_nem_sat_aug_4, datetime(2010, 8, 27), False),
|
||||
(offset_nem_sat_aug_4, datetime(2011, 8, 26), False),
|
||||
(offset_nem_sat_aug_4, datetime(2019, 8, 30), False),
|
||||
# From Micron, see:
|
||||
# http://google.brand.edgar-online.com/?sym=MU&formtypeID=7
|
||||
(offset_nem_thu_aug_4, datetime(2012, 8, 30), True),
|
||||
(offset_nem_thu_aug_4, datetime(2011, 9, 1), True),
|
||||
# See: http://google.brand.edgar-online.com/?sym=MU&formtypeID=13
|
||||
(offset_nem_thu_aug_4, datetime(2013, 5, 30), True),
|
||||
(offset_nem_thu_aug_4, datetime(2013, 2, 28), True),
|
||||
(offset_nem_thu_aug_4, datetime(2012, 11, 29), True),
|
||||
(offset_nem_thu_aug_4, datetime(2012, 5, 31), True),
|
||||
(offset_nem_thu_aug_4, datetime(2007, 3, 1), True),
|
||||
(offset_nem_thu_aug_4, datetime(1994, 3, 3), True),
|
||||
(offset_n, datetime(2012, 12, 31), False),
|
||||
(offset_n, datetime(2013, 1, 1), True),
|
||||
(offset_n, datetime(2013, 1, 2), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
def test_offset(self):
|
||||
offset = makeFY5253NearestEndMonthQuarter(
|
||||
1, startingMonth=8, weekday=WeekDay.THU, qtr_with_extra_week=4
|
||||
)
|
||||
|
||||
MU = [
|
||||
datetime(2012, 5, 31),
|
||||
datetime(2012, 8, 30),
|
||||
datetime(2012, 11, 29),
|
||||
datetime(2013, 2, 28),
|
||||
datetime(2013, 5, 30),
|
||||
]
|
||||
|
||||
date = MU[0] + relativedelta(days=-1)
|
||||
for expected in MU:
|
||||
assert_offset_equal(offset, date, expected)
|
||||
date = date + offset
|
||||
|
||||
assert_offset_equal(offset, datetime(2012, 5, 31), datetime(2012, 8, 30))
|
||||
assert_offset_equal(offset, datetime(2012, 5, 30), datetime(2012, 5, 31))
|
||||
|
||||
offset2 = FY5253Quarter(
|
||||
weekday=5, startingMonth=12, variation="last", qtr_with_extra_week=4
|
||||
)
|
||||
|
||||
assert_offset_equal(offset2, datetime(2013, 1, 15), datetime(2013, 3, 30))
|
||||
|
||||
|
||||
def test_bunched_yearends():
|
||||
# GH#14774 cases with two fiscal year-ends in the same calendar-year
|
||||
fy = FY5253(n=1, weekday=5, startingMonth=12, variation="nearest")
|
||||
dt = Timestamp("2004-01-01")
|
||||
assert fy.rollback(dt) == Timestamp("2002-12-28")
|
||||
assert (-fy)._apply(dt) == Timestamp("2002-12-28")
|
||||
assert dt - fy == Timestamp("2002-12-28")
|
||||
|
||||
assert fy.rollforward(dt) == Timestamp("2004-01-03")
|
||||
assert fy._apply(dt) == Timestamp("2004-01-03")
|
||||
assert fy + dt == Timestamp("2004-01-03")
|
||||
assert dt + fy == Timestamp("2004-01-03")
|
||||
|
||||
# Same thing, but starting from a Timestamp in the previous year.
|
||||
dt = Timestamp("2003-12-31")
|
||||
assert fy.rollback(dt) == Timestamp("2002-12-28")
|
||||
assert (-fy)._apply(dt) == Timestamp("2002-12-28")
|
||||
assert dt - fy == Timestamp("2002-12-28")
|
||||
|
||||
|
||||
def test_fy5253_last_onoffset():
|
||||
# GH#18877 dates on the year-end but not normalized to midnight
|
||||
offset = FY5253(n=-5, startingMonth=5, variation="last", weekday=0)
|
||||
ts = Timestamp("1984-05-28 06:29:43.955911354+0200", tz="Europe/San_Marino")
|
||||
fast = offset.is_on_offset(ts)
|
||||
slow = (ts + offset) - offset == ts
|
||||
assert fast == slow
|
||||
|
||||
|
||||
def test_fy5253_nearest_onoffset():
|
||||
# GH#18877 dates on the year-end but not normalized to midnight
|
||||
offset = FY5253(n=3, startingMonth=7, variation="nearest", weekday=2)
|
||||
ts = Timestamp("2032-07-28 00:12:59.035729419+0000", tz="Africa/Dakar")
|
||||
fast = offset.is_on_offset(ts)
|
||||
slow = (ts + offset) - offset == ts
|
||||
assert fast == slow
|
||||
|
||||
|
||||
def test_fy5253qtr_onoffset_nearest():
|
||||
# GH#19036
|
||||
ts = Timestamp("1985-09-02 23:57:46.232550356-0300", tz="Atlantic/Bermuda")
|
||||
offset = FY5253Quarter(
|
||||
n=3, qtr_with_extra_week=1, startingMonth=2, variation="nearest", weekday=0
|
||||
)
|
||||
fast = offset.is_on_offset(ts)
|
||||
slow = (ts + offset) - offset == ts
|
||||
assert fast == slow
|
||||
|
||||
|
||||
def test_fy5253qtr_onoffset_last():
|
||||
# GH#19036
|
||||
offset = FY5253Quarter(
|
||||
n=-2, qtr_with_extra_week=1, startingMonth=7, variation="last", weekday=2
|
||||
)
|
||||
ts = Timestamp("2011-01-26 19:03:40.331096129+0200", tz="Africa/Windhoek")
|
||||
slow = (ts + offset) - offset == ts
|
||||
fast = offset.is_on_offset(ts)
|
||||
assert fast == slow
|
@ -0,0 +1,57 @@
|
||||
"""
|
||||
Tests for offset behavior with indices.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from pandas import (
|
||||
Series,
|
||||
date_range,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
BMonthBegin,
|
||||
BMonthEnd,
|
||||
BQuarterBegin,
|
||||
BQuarterEnd,
|
||||
BYearBegin,
|
||||
BYearEnd,
|
||||
MonthBegin,
|
||||
MonthEnd,
|
||||
QuarterBegin,
|
||||
QuarterEnd,
|
||||
YearBegin,
|
||||
YearEnd,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("n", [-2, 1])
|
||||
@pytest.mark.parametrize(
|
||||
"cls",
|
||||
[
|
||||
MonthBegin,
|
||||
MonthEnd,
|
||||
BMonthBegin,
|
||||
BMonthEnd,
|
||||
QuarterBegin,
|
||||
QuarterEnd,
|
||||
BQuarterBegin,
|
||||
BQuarterEnd,
|
||||
YearBegin,
|
||||
YearEnd,
|
||||
BYearBegin,
|
||||
BYearEnd,
|
||||
],
|
||||
)
|
||||
def test_apply_index(cls, n):
|
||||
offset = cls(n=n)
|
||||
rng = date_range(start="1/1/2000", periods=100000, freq="min")
|
||||
ser = Series(rng)
|
||||
|
||||
res = rng + offset
|
||||
assert res.freq is None # not retained
|
||||
assert res[0] == rng[0] + offset
|
||||
assert res[-1] == rng[-1] + offset
|
||||
res2 = ser + offset
|
||||
# apply_index is only for indexes, not series, so no res2_v2
|
||||
assert res2.iloc[0] == ser.iloc[0] + offset
|
||||
assert res2.iloc[-1] == ser.iloc[-1] + offset
|
@ -0,0 +1,666 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- SemiMonthBegin
|
||||
- SemiMonthEnd
|
||||
- MonthBegin
|
||||
- MonthEnd
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import Timestamp
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
MonthBegin,
|
||||
MonthEnd,
|
||||
SemiMonthBegin,
|
||||
SemiMonthEnd,
|
||||
)
|
||||
|
||||
from pandas import (
|
||||
DatetimeIndex,
|
||||
Series,
|
||||
_testing as tm,
|
||||
)
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
|
||||
class TestSemiMonthEnd:
|
||||
def test_offset_whole_year(self):
|
||||
dates = (
|
||||
datetime(2007, 12, 31),
|
||||
datetime(2008, 1, 15),
|
||||
datetime(2008, 1, 31),
|
||||
datetime(2008, 2, 15),
|
||||
datetime(2008, 2, 29),
|
||||
datetime(2008, 3, 15),
|
||||
datetime(2008, 3, 31),
|
||||
datetime(2008, 4, 15),
|
||||
datetime(2008, 4, 30),
|
||||
datetime(2008, 5, 15),
|
||||
datetime(2008, 5, 31),
|
||||
datetime(2008, 6, 15),
|
||||
datetime(2008, 6, 30),
|
||||
datetime(2008, 7, 15),
|
||||
datetime(2008, 7, 31),
|
||||
datetime(2008, 8, 15),
|
||||
datetime(2008, 8, 31),
|
||||
datetime(2008, 9, 15),
|
||||
datetime(2008, 9, 30),
|
||||
datetime(2008, 10, 15),
|
||||
datetime(2008, 10, 31),
|
||||
datetime(2008, 11, 15),
|
||||
datetime(2008, 11, 30),
|
||||
datetime(2008, 12, 15),
|
||||
datetime(2008, 12, 31),
|
||||
)
|
||||
|
||||
for base, exp_date in zip(dates[:-1], dates[1:]):
|
||||
assert_offset_equal(SemiMonthEnd(), base, exp_date)
|
||||
|
||||
# ensure .apply_index works as expected
|
||||
shift = DatetimeIndex(dates[:-1])
|
||||
with tm.assert_produces_warning(None):
|
||||
# GH#22535 check that we don't get a FutureWarning from adding
|
||||
# an integer array to PeriodIndex
|
||||
result = SemiMonthEnd() + shift
|
||||
|
||||
exp = DatetimeIndex(dates[1:])
|
||||
tm.assert_index_equal(result, exp)
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
SemiMonthEnd(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 15),
|
||||
datetime(2008, 1, 15): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 15),
|
||||
datetime(2006, 12, 14): datetime(2006, 12, 15),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 31),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 15),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 15),
|
||||
datetime(2006, 12, 1): datetime(2006, 12, 15),
|
||||
datetime(2006, 12, 15): datetime(2006, 12, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
SemiMonthEnd(day_of_month=20),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 20),
|
||||
datetime(2008, 1, 15): datetime(2008, 1, 20),
|
||||
datetime(2008, 1, 21): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 20),
|
||||
datetime(2006, 12, 14): datetime(2006, 12, 20),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 31),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 20),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 20),
|
||||
datetime(2006, 12, 1): datetime(2006, 12, 20),
|
||||
datetime(2006, 12, 15): datetime(2006, 12, 20),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
SemiMonthEnd(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 15),
|
||||
datetime(2008, 1, 16): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 15): datetime(2008, 1, 15),
|
||||
datetime(2008, 1, 31): datetime(2008, 1, 31),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 31),
|
||||
datetime(2006, 12, 31): datetime(2006, 12, 31),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 15),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
SemiMonthEnd(0, day_of_month=16),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 16),
|
||||
datetime(2008, 1, 16): datetime(2008, 1, 16),
|
||||
datetime(2008, 1, 15): datetime(2008, 1, 16),
|
||||
datetime(2008, 1, 31): datetime(2008, 1, 31),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 31),
|
||||
datetime(2006, 12, 31): datetime(2006, 12, 31),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 16),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
SemiMonthEnd(2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 29),
|
||||
datetime(2006, 12, 29): datetime(2007, 1, 15),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 31),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 31),
|
||||
datetime(2007, 1, 16): datetime(2007, 2, 15),
|
||||
datetime(2006, 11, 1): datetime(2006, 11, 30),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
SemiMonthEnd(-1),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 31),
|
||||
datetime(2008, 6, 30): datetime(2008, 6, 15),
|
||||
datetime(2008, 12, 31): datetime(2008, 12, 15),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 15),
|
||||
datetime(2006, 12, 30): datetime(2006, 12, 15),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
SemiMonthEnd(-1, day_of_month=4),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 31),
|
||||
datetime(2007, 1, 4): datetime(2006, 12, 31),
|
||||
datetime(2008, 6, 30): datetime(2008, 6, 4),
|
||||
datetime(2008, 12, 31): datetime(2008, 12, 4),
|
||||
datetime(2006, 12, 5): datetime(2006, 12, 4),
|
||||
datetime(2006, 12, 30): datetime(2006, 12, 4),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
SemiMonthEnd(-2),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 15),
|
||||
datetime(2008, 6, 30): datetime(2008, 5, 31),
|
||||
datetime(2008, 3, 15): datetime(2008, 2, 15),
|
||||
datetime(2008, 12, 31): datetime(2008, 11, 30),
|
||||
datetime(2006, 12, 29): datetime(2006, 11, 30),
|
||||
datetime(2006, 12, 14): datetime(2006, 11, 15),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 15),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_apply_index(self, case):
|
||||
# https://github.com/pandas-dev/pandas/issues/34580
|
||||
offset, cases = case
|
||||
shift = DatetimeIndex(cases.keys())
|
||||
exp = DatetimeIndex(cases.values())
|
||||
|
||||
with tm.assert_produces_warning(None):
|
||||
# GH#22535 check that we don't get a FutureWarning from adding
|
||||
# an integer array to PeriodIndex
|
||||
result = offset + shift
|
||||
tm.assert_index_equal(result, exp)
|
||||
|
||||
on_offset_cases = [
|
||||
(datetime(2007, 12, 31), True),
|
||||
(datetime(2007, 12, 15), True),
|
||||
(datetime(2007, 12, 14), False),
|
||||
(datetime(2007, 12, 1), False),
|
||||
(datetime(2008, 2, 29), True),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
dt, expected = case
|
||||
assert_is_on_offset(SemiMonthEnd(), dt, expected)
|
||||
|
||||
@pytest.mark.parametrize("klass", [Series, DatetimeIndex])
|
||||
def test_vectorized_offset_addition(self, klass):
|
||||
shift = klass(
|
||||
[
|
||||
Timestamp("2000-01-15 00:15:00", tz="US/Central"),
|
||||
Timestamp("2000-02-15", tz="US/Central"),
|
||||
],
|
||||
name="a",
|
||||
)
|
||||
|
||||
with tm.assert_produces_warning(None):
|
||||
# GH#22535 check that we don't get a FutureWarning from adding
|
||||
# an integer array to PeriodIndex
|
||||
result = shift + SemiMonthEnd()
|
||||
result2 = SemiMonthEnd() + shift
|
||||
|
||||
exp = klass(
|
||||
[
|
||||
Timestamp("2000-01-31 00:15:00", tz="US/Central"),
|
||||
Timestamp("2000-02-29", tz="US/Central"),
|
||||
],
|
||||
name="a",
|
||||
)
|
||||
tm.assert_equal(result, exp)
|
||||
tm.assert_equal(result2, exp)
|
||||
|
||||
shift = klass(
|
||||
[
|
||||
Timestamp("2000-01-01 00:15:00", tz="US/Central"),
|
||||
Timestamp("2000-02-01", tz="US/Central"),
|
||||
],
|
||||
name="a",
|
||||
)
|
||||
|
||||
with tm.assert_produces_warning(None):
|
||||
# GH#22535 check that we don't get a FutureWarning from adding
|
||||
# an integer array to PeriodIndex
|
||||
result = shift + SemiMonthEnd()
|
||||
result2 = SemiMonthEnd() + shift
|
||||
|
||||
exp = klass(
|
||||
[
|
||||
Timestamp("2000-01-15 00:15:00", tz="US/Central"),
|
||||
Timestamp("2000-02-15", tz="US/Central"),
|
||||
],
|
||||
name="a",
|
||||
)
|
||||
tm.assert_equal(result, exp)
|
||||
tm.assert_equal(result2, exp)
|
||||
|
||||
|
||||
class TestSemiMonthBegin:
|
||||
def test_offset_whole_year(self):
|
||||
dates = (
|
||||
datetime(2007, 12, 15),
|
||||
datetime(2008, 1, 1),
|
||||
datetime(2008, 1, 15),
|
||||
datetime(2008, 2, 1),
|
||||
datetime(2008, 2, 15),
|
||||
datetime(2008, 3, 1),
|
||||
datetime(2008, 3, 15),
|
||||
datetime(2008, 4, 1),
|
||||
datetime(2008, 4, 15),
|
||||
datetime(2008, 5, 1),
|
||||
datetime(2008, 5, 15),
|
||||
datetime(2008, 6, 1),
|
||||
datetime(2008, 6, 15),
|
||||
datetime(2008, 7, 1),
|
||||
datetime(2008, 7, 15),
|
||||
datetime(2008, 8, 1),
|
||||
datetime(2008, 8, 15),
|
||||
datetime(2008, 9, 1),
|
||||
datetime(2008, 9, 15),
|
||||
datetime(2008, 10, 1),
|
||||
datetime(2008, 10, 15),
|
||||
datetime(2008, 11, 1),
|
||||
datetime(2008, 11, 15),
|
||||
datetime(2008, 12, 1),
|
||||
datetime(2008, 12, 15),
|
||||
)
|
||||
|
||||
for base, exp_date in zip(dates[:-1], dates[1:]):
|
||||
assert_offset_equal(SemiMonthBegin(), base, exp_date)
|
||||
|
||||
# ensure .apply_index works as expected
|
||||
shift = DatetimeIndex(dates[:-1])
|
||||
with tm.assert_produces_warning(None):
|
||||
# GH#22535 check that we don't get a FutureWarning from adding
|
||||
# an integer array to PeriodIndex
|
||||
result = SemiMonthBegin() + shift
|
||||
|
||||
exp = DatetimeIndex(dates[1:])
|
||||
tm.assert_index_equal(result, exp)
|
||||
|
||||
offset_cases = [
|
||||
(
|
||||
SemiMonthBegin(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 15),
|
||||
datetime(2008, 1, 15): datetime(2008, 2, 1),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 1),
|
||||
datetime(2006, 12, 14): datetime(2006, 12, 15),
|
||||
datetime(2006, 12, 29): datetime(2007, 1, 1),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 1),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 15),
|
||||
datetime(2006, 12, 1): datetime(2006, 12, 15),
|
||||
datetime(2006, 12, 15): datetime(2007, 1, 1),
|
||||
},
|
||||
),
|
||||
(
|
||||
SemiMonthBegin(day_of_month=20),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 20),
|
||||
datetime(2008, 1, 15): datetime(2008, 1, 20),
|
||||
datetime(2008, 1, 21): datetime(2008, 2, 1),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 1),
|
||||
datetime(2006, 12, 14): datetime(2006, 12, 20),
|
||||
datetime(2006, 12, 29): datetime(2007, 1, 1),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 1),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 20),
|
||||
datetime(2006, 12, 1): datetime(2006, 12, 20),
|
||||
datetime(2006, 12, 15): datetime(2006, 12, 20),
|
||||
},
|
||||
),
|
||||
(
|
||||
SemiMonthBegin(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2008, 1, 16): datetime(2008, 2, 1),
|
||||
datetime(2008, 1, 15): datetime(2008, 1, 15),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 1),
|
||||
datetime(2006, 12, 29): datetime(2007, 1, 1),
|
||||
datetime(2006, 12, 2): datetime(2006, 12, 15),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 1),
|
||||
},
|
||||
),
|
||||
(
|
||||
SemiMonthBegin(0, day_of_month=16),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2008, 1, 16): datetime(2008, 1, 16),
|
||||
datetime(2008, 1, 15): datetime(2008, 1, 16),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 1),
|
||||
datetime(2006, 12, 29): datetime(2007, 1, 1),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 1),
|
||||
datetime(2007, 1, 5): datetime(2007, 1, 16),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 1),
|
||||
},
|
||||
),
|
||||
(
|
||||
SemiMonthBegin(2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 2, 1),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 15),
|
||||
datetime(2006, 12, 1): datetime(2007, 1, 1),
|
||||
datetime(2006, 12, 29): datetime(2007, 1, 15),
|
||||
datetime(2006, 12, 15): datetime(2007, 1, 15),
|
||||
datetime(2007, 1, 1): datetime(2007, 2, 1),
|
||||
datetime(2007, 1, 16): datetime(2007, 2, 15),
|
||||
datetime(2006, 11, 1): datetime(2006, 12, 1),
|
||||
},
|
||||
),
|
||||
(
|
||||
SemiMonthBegin(-1),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 15),
|
||||
datetime(2008, 6, 30): datetime(2008, 6, 15),
|
||||
datetime(2008, 6, 14): datetime(2008, 6, 1),
|
||||
datetime(2008, 12, 31): datetime(2008, 12, 15),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 15),
|
||||
datetime(2006, 12, 15): datetime(2006, 12, 1),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 15),
|
||||
},
|
||||
),
|
||||
(
|
||||
SemiMonthBegin(-1, day_of_month=4),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 4),
|
||||
datetime(2007, 1, 4): datetime(2007, 1, 1),
|
||||
datetime(2008, 6, 30): datetime(2008, 6, 4),
|
||||
datetime(2008, 12, 31): datetime(2008, 12, 4),
|
||||
datetime(2006, 12, 5): datetime(2006, 12, 4),
|
||||
datetime(2006, 12, 30): datetime(2006, 12, 4),
|
||||
datetime(2006, 12, 2): datetime(2006, 12, 1),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 4),
|
||||
},
|
||||
),
|
||||
(
|
||||
SemiMonthBegin(-2),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 1),
|
||||
datetime(2008, 6, 30): datetime(2008, 6, 1),
|
||||
datetime(2008, 6, 14): datetime(2008, 5, 15),
|
||||
datetime(2008, 12, 31): datetime(2008, 12, 1),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 1),
|
||||
datetime(2006, 12, 15): datetime(2006, 11, 15),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 1),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_apply_index(self, case):
|
||||
offset, cases = case
|
||||
shift = DatetimeIndex(cases.keys())
|
||||
|
||||
with tm.assert_produces_warning(None):
|
||||
# GH#22535 check that we don't get a FutureWarning from adding
|
||||
# an integer array to PeriodIndex
|
||||
result = offset + shift
|
||||
|
||||
exp = DatetimeIndex(cases.values())
|
||||
tm.assert_index_equal(result, exp)
|
||||
|
||||
on_offset_cases = [
|
||||
(datetime(2007, 12, 1), True),
|
||||
(datetime(2007, 12, 15), True),
|
||||
(datetime(2007, 12, 14), False),
|
||||
(datetime(2007, 12, 31), False),
|
||||
(datetime(2008, 2, 15), True),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
dt, expected = case
|
||||
assert_is_on_offset(SemiMonthBegin(), dt, expected)
|
||||
|
||||
@pytest.mark.parametrize("klass", [Series, DatetimeIndex])
|
||||
def test_vectorized_offset_addition(self, klass):
|
||||
shift = klass(
|
||||
[
|
||||
Timestamp("2000-01-15 00:15:00", tz="US/Central"),
|
||||
Timestamp("2000-02-15", tz="US/Central"),
|
||||
],
|
||||
name="a",
|
||||
)
|
||||
with tm.assert_produces_warning(None):
|
||||
# GH#22535 check that we don't get a FutureWarning from adding
|
||||
# an integer array to PeriodIndex
|
||||
result = shift + SemiMonthBegin()
|
||||
result2 = SemiMonthBegin() + shift
|
||||
|
||||
exp = klass(
|
||||
[
|
||||
Timestamp("2000-02-01 00:15:00", tz="US/Central"),
|
||||
Timestamp("2000-03-01", tz="US/Central"),
|
||||
],
|
||||
name="a",
|
||||
)
|
||||
tm.assert_equal(result, exp)
|
||||
tm.assert_equal(result2, exp)
|
||||
|
||||
shift = klass(
|
||||
[
|
||||
Timestamp("2000-01-01 00:15:00", tz="US/Central"),
|
||||
Timestamp("2000-02-01", tz="US/Central"),
|
||||
],
|
||||
name="a",
|
||||
)
|
||||
with tm.assert_produces_warning(None):
|
||||
# GH#22535 check that we don't get a FutureWarning from adding
|
||||
# an integer array to PeriodIndex
|
||||
result = shift + SemiMonthBegin()
|
||||
result2 = SemiMonthBegin() + shift
|
||||
|
||||
exp = klass(
|
||||
[
|
||||
Timestamp("2000-01-15 00:15:00", tz="US/Central"),
|
||||
Timestamp("2000-02-15", tz="US/Central"),
|
||||
],
|
||||
name="a",
|
||||
)
|
||||
tm.assert_equal(result, exp)
|
||||
tm.assert_equal(result2, exp)
|
||||
|
||||
|
||||
class TestMonthBegin:
|
||||
offset_cases = []
|
||||
# NOTE: I'm not entirely happy with the logic here for Begin -ss
|
||||
# see thread 'offset conventions' on the ML
|
||||
offset_cases.append(
|
||||
(
|
||||
MonthBegin(),
|
||||
{
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 1),
|
||||
datetime(2008, 2, 1): datetime(2008, 3, 1),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 1),
|
||||
datetime(2006, 12, 1): datetime(2007, 1, 1),
|
||||
datetime(2007, 1, 31): datetime(2007, 2, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
MonthBegin(0),
|
||||
{
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 1),
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2006, 12, 3): datetime(2007, 1, 1),
|
||||
datetime(2007, 1, 31): datetime(2007, 2, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
MonthBegin(2),
|
||||
{
|
||||
datetime(2008, 2, 29): datetime(2008, 4, 1),
|
||||
datetime(2008, 1, 31): datetime(2008, 3, 1),
|
||||
datetime(2006, 12, 31): datetime(2007, 2, 1),
|
||||
datetime(2007, 12, 28): datetime(2008, 2, 1),
|
||||
datetime(2007, 1, 1): datetime(2007, 3, 1),
|
||||
datetime(2006, 11, 1): datetime(2007, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
MonthBegin(-1),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 1),
|
||||
datetime(2008, 5, 31): datetime(2008, 5, 1),
|
||||
datetime(2008, 12, 31): datetime(2008, 12, 1),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 1),
|
||||
datetime(2006, 1, 2): datetime(2006, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
|
||||
class TestMonthEnd:
|
||||
def test_day_of_month(self):
|
||||
dt = datetime(2007, 1, 1)
|
||||
offset = MonthEnd()
|
||||
|
||||
result = dt + offset
|
||||
assert result == Timestamp(2007, 1, 31)
|
||||
|
||||
result = result + offset
|
||||
assert result == Timestamp(2007, 2, 28)
|
||||
|
||||
def test_normalize(self):
|
||||
dt = datetime(2007, 1, 1, 3)
|
||||
|
||||
result = dt + MonthEnd(normalize=True)
|
||||
expected = dt.replace(hour=0) + MonthEnd()
|
||||
assert result == expected
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
MonthEnd(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 29),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 31),
|
||||
datetime(2006, 12, 31): datetime(2007, 1, 31),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 31),
|
||||
datetime(2006, 12, 1): datetime(2006, 12, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
MonthEnd(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 1, 31),
|
||||
datetime(2006, 12, 29): datetime(2006, 12, 31),
|
||||
datetime(2006, 12, 31): datetime(2006, 12, 31),
|
||||
datetime(2007, 1, 1): datetime(2007, 1, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
MonthEnd(2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 2, 29),
|
||||
datetime(2008, 1, 31): datetime(2008, 3, 31),
|
||||
datetime(2006, 12, 29): datetime(2007, 1, 31),
|
||||
datetime(2006, 12, 31): datetime(2007, 2, 28),
|
||||
datetime(2007, 1, 1): datetime(2007, 2, 28),
|
||||
datetime(2006, 11, 1): datetime(2006, 12, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
MonthEnd(-1),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 31),
|
||||
datetime(2008, 6, 30): datetime(2008, 5, 31),
|
||||
datetime(2008, 12, 31): datetime(2008, 11, 30),
|
||||
datetime(2006, 12, 29): datetime(2006, 11, 30),
|
||||
datetime(2006, 12, 30): datetime(2006, 11, 30),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
on_offset_cases = [
|
||||
(MonthEnd(), datetime(2007, 12, 31), True),
|
||||
(MonthEnd(), datetime(2008, 1, 1), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,60 @@
|
||||
"""
|
||||
Behavioral based tests for offsets and date_range.
|
||||
|
||||
This file is adapted from https://github.com/pandas-dev/pandas/pull/18761 -
|
||||
which was more ambitious but less idiomatic in its use of Hypothesis.
|
||||
|
||||
You may wish to consult the previous version for inspiration on further
|
||||
tests, or when trying to pin down the bugs exposed by the tests below.
|
||||
"""
|
||||
from hypothesis import (
|
||||
assume,
|
||||
given,
|
||||
)
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
import pandas as pd
|
||||
from pandas._testing._hypothesis import (
|
||||
DATETIME_JAN_1_1900_OPTIONAL_TZ,
|
||||
YQM_OFFSET,
|
||||
)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# Offset-specific behaviour tests
|
||||
|
||||
|
||||
@pytest.mark.arm_slow
|
||||
@given(DATETIME_JAN_1_1900_OPTIONAL_TZ, YQM_OFFSET)
|
||||
def test_on_offset_implementations(dt, offset):
|
||||
assume(not offset.normalize)
|
||||
# check that the class-specific implementations of is_on_offset match
|
||||
# the general case definition:
|
||||
# (dt + offset) - offset == dt
|
||||
try:
|
||||
compare = (dt + offset) - offset
|
||||
except (pytz.NonExistentTimeError, pytz.AmbiguousTimeError):
|
||||
# When dt + offset does not exist or is DST-ambiguous, assume(False) to
|
||||
# indicate to hypothesis that this is not a valid test case
|
||||
# DST-ambiguous example (GH41906):
|
||||
# dt = datetime.datetime(1900, 1, 1, tzinfo=pytz.timezone('Africa/Kinshasa'))
|
||||
# offset = MonthBegin(66)
|
||||
assume(False)
|
||||
|
||||
assert offset.is_on_offset(dt) == (compare == dt)
|
||||
|
||||
|
||||
@given(YQM_OFFSET)
|
||||
def test_shift_across_dst(offset):
|
||||
# GH#18319 check that 1) timezone is correctly normalized and
|
||||
# 2) that hour is not incorrectly changed by this normalization
|
||||
assume(not offset.normalize)
|
||||
|
||||
# Note that dti includes a transition across DST boundary
|
||||
dti = pd.date_range(
|
||||
start="2017-10-30 12:00:00", end="2017-11-06", freq="D", tz="US/Eastern"
|
||||
)
|
||||
assert (dti.hour == 12).all() # we haven't screwed up yet
|
||||
|
||||
res = dti + offset
|
||||
assert (res.hour == 12).all()
|
@ -0,0 +1,303 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- QuarterBegin
|
||||
- QuarterEnd
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
import pandas._testing as tm
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
QuarterBegin,
|
||||
QuarterEnd,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("klass", (QuarterBegin, QuarterEnd))
|
||||
def test_quarterly_dont_normalize(klass):
|
||||
date = datetime(2012, 3, 31, 5, 30)
|
||||
result = date + klass()
|
||||
assert result.time() == date.time()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("offset", [QuarterBegin(), QuarterEnd()])
|
||||
@pytest.mark.parametrize(
|
||||
"date",
|
||||
[
|
||||
datetime(2016, m, d)
|
||||
for m in [10, 11, 12]
|
||||
for d in [1, 2, 3, 28, 29, 30, 31]
|
||||
if not (m == 11 and d == 31)
|
||||
],
|
||||
)
|
||||
def test_on_offset(offset, date):
|
||||
res = offset.is_on_offset(date)
|
||||
slow_version = date == (date + offset) - offset
|
||||
assert res == slow_version
|
||||
|
||||
|
||||
class TestQuarterBegin:
|
||||
def test_repr(self):
|
||||
expected = "<QuarterBegin: startingMonth=3>"
|
||||
assert repr(QuarterBegin()) == expected
|
||||
expected = "<QuarterBegin: startingMonth=3>"
|
||||
assert repr(QuarterBegin(startingMonth=3)) == expected
|
||||
expected = "<QuarterBegin: startingMonth=1>"
|
||||
assert repr(QuarterBegin(startingMonth=1)) == expected
|
||||
|
||||
def test_is_anchored(self):
|
||||
msg = "QuarterBegin.is_anchored is deprecated "
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
assert QuarterBegin(startingMonth=1).is_anchored()
|
||||
assert QuarterBegin().is_anchored()
|
||||
assert not QuarterBegin(2, startingMonth=1).is_anchored()
|
||||
|
||||
def test_offset_corner_case(self):
|
||||
# corner
|
||||
offset = QuarterBegin(n=-1, startingMonth=1)
|
||||
assert datetime(2010, 2, 1) + offset == datetime(2010, 1, 1)
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
QuarterBegin(startingMonth=1),
|
||||
{
|
||||
datetime(2007, 12, 1): datetime(2008, 1, 1),
|
||||
datetime(2008, 1, 1): datetime(2008, 4, 1),
|
||||
datetime(2008, 2, 15): datetime(2008, 4, 1),
|
||||
datetime(2008, 2, 29): datetime(2008, 4, 1),
|
||||
datetime(2008, 3, 15): datetime(2008, 4, 1),
|
||||
datetime(2008, 3, 31): datetime(2008, 4, 1),
|
||||
datetime(2008, 4, 15): datetime(2008, 7, 1),
|
||||
datetime(2008, 4, 1): datetime(2008, 7, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
QuarterBegin(startingMonth=2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 2, 1),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 1),
|
||||
datetime(2008, 1, 15): datetime(2008, 2, 1),
|
||||
datetime(2008, 2, 29): datetime(2008, 5, 1),
|
||||
datetime(2008, 3, 15): datetime(2008, 5, 1),
|
||||
datetime(2008, 3, 31): datetime(2008, 5, 1),
|
||||
datetime(2008, 4, 15): datetime(2008, 5, 1),
|
||||
datetime(2008, 4, 30): datetime(2008, 5, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
QuarterBegin(startingMonth=1, n=0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2008, 12, 1): datetime(2009, 1, 1),
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2008, 2, 15): datetime(2008, 4, 1),
|
||||
datetime(2008, 2, 29): datetime(2008, 4, 1),
|
||||
datetime(2008, 3, 15): datetime(2008, 4, 1),
|
||||
datetime(2008, 3, 31): datetime(2008, 4, 1),
|
||||
datetime(2008, 4, 15): datetime(2008, 7, 1),
|
||||
datetime(2008, 4, 30): datetime(2008, 7, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
QuarterBegin(startingMonth=1, n=-1),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 10, 1),
|
||||
datetime(2008, 1, 31): datetime(2008, 1, 1),
|
||||
datetime(2008, 2, 15): datetime(2008, 1, 1),
|
||||
datetime(2008, 2, 29): datetime(2008, 1, 1),
|
||||
datetime(2008, 3, 15): datetime(2008, 1, 1),
|
||||
datetime(2008, 3, 31): datetime(2008, 1, 1),
|
||||
datetime(2008, 4, 15): datetime(2008, 4, 1),
|
||||
datetime(2008, 4, 30): datetime(2008, 4, 1),
|
||||
datetime(2008, 7, 1): datetime(2008, 4, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
QuarterBegin(startingMonth=1, n=2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 7, 1),
|
||||
datetime(2008, 2, 15): datetime(2008, 7, 1),
|
||||
datetime(2008, 2, 29): datetime(2008, 7, 1),
|
||||
datetime(2008, 3, 15): datetime(2008, 7, 1),
|
||||
datetime(2008, 3, 31): datetime(2008, 7, 1),
|
||||
datetime(2008, 4, 15): datetime(2008, 10, 1),
|
||||
datetime(2008, 4, 1): datetime(2008, 10, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
|
||||
class TestQuarterEnd:
|
||||
def test_repr(self):
|
||||
expected = "<QuarterEnd: startingMonth=3>"
|
||||
assert repr(QuarterEnd()) == expected
|
||||
expected = "<QuarterEnd: startingMonth=3>"
|
||||
assert repr(QuarterEnd(startingMonth=3)) == expected
|
||||
expected = "<QuarterEnd: startingMonth=1>"
|
||||
assert repr(QuarterEnd(startingMonth=1)) == expected
|
||||
|
||||
def test_is_anchored(self):
|
||||
msg = "QuarterEnd.is_anchored is deprecated "
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
assert QuarterEnd(startingMonth=1).is_anchored()
|
||||
assert QuarterEnd().is_anchored()
|
||||
assert not QuarterEnd(2, startingMonth=1).is_anchored()
|
||||
|
||||
def test_offset_corner_case(self):
|
||||
# corner
|
||||
offset = QuarterEnd(n=-1, startingMonth=1)
|
||||
assert datetime(2010, 2, 1) + offset == datetime(2010, 1, 31)
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
QuarterEnd(startingMonth=1),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 4, 30),
|
||||
datetime(2008, 2, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 2, 29): datetime(2008, 4, 30),
|
||||
datetime(2008, 3, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 3, 31): datetime(2008, 4, 30),
|
||||
datetime(2008, 4, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 4, 30): datetime(2008, 7, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
QuarterEnd(startingMonth=2),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 2, 29),
|
||||
datetime(2008, 1, 31): datetime(2008, 2, 29),
|
||||
datetime(2008, 2, 15): datetime(2008, 2, 29),
|
||||
datetime(2008, 2, 29): datetime(2008, 5, 31),
|
||||
datetime(2008, 3, 15): datetime(2008, 5, 31),
|
||||
datetime(2008, 3, 31): datetime(2008, 5, 31),
|
||||
datetime(2008, 4, 15): datetime(2008, 5, 31),
|
||||
datetime(2008, 4, 30): datetime(2008, 5, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
QuarterEnd(startingMonth=1, n=0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 31),
|
||||
datetime(2008, 1, 31): datetime(2008, 1, 31),
|
||||
datetime(2008, 2, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 2, 29): datetime(2008, 4, 30),
|
||||
datetime(2008, 3, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 3, 31): datetime(2008, 4, 30),
|
||||
datetime(2008, 4, 15): datetime(2008, 4, 30),
|
||||
datetime(2008, 4, 30): datetime(2008, 4, 30),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
QuarterEnd(startingMonth=1, n=-1),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2007, 10, 31),
|
||||
datetime(2008, 1, 31): datetime(2007, 10, 31),
|
||||
datetime(2008, 2, 15): datetime(2008, 1, 31),
|
||||
datetime(2008, 2, 29): datetime(2008, 1, 31),
|
||||
datetime(2008, 3, 15): datetime(2008, 1, 31),
|
||||
datetime(2008, 3, 31): datetime(2008, 1, 31),
|
||||
datetime(2008, 4, 15): datetime(2008, 1, 31),
|
||||
datetime(2008, 4, 30): datetime(2008, 1, 31),
|
||||
datetime(2008, 7, 1): datetime(2008, 4, 30),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
QuarterEnd(startingMonth=1, n=2),
|
||||
{
|
||||
datetime(2008, 1, 31): datetime(2008, 7, 31),
|
||||
datetime(2008, 2, 15): datetime(2008, 7, 31),
|
||||
datetime(2008, 2, 29): datetime(2008, 7, 31),
|
||||
datetime(2008, 3, 15): datetime(2008, 7, 31),
|
||||
datetime(2008, 3, 31): datetime(2008, 7, 31),
|
||||
datetime(2008, 4, 15): datetime(2008, 7, 31),
|
||||
datetime(2008, 4, 30): datetime(2008, 10, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
on_offset_cases = [
|
||||
(QuarterEnd(1, startingMonth=1), datetime(2008, 1, 31), True),
|
||||
(QuarterEnd(1, startingMonth=1), datetime(2007, 12, 31), False),
|
||||
(QuarterEnd(1, startingMonth=1), datetime(2008, 2, 29), False),
|
||||
(QuarterEnd(1, startingMonth=1), datetime(2007, 3, 30), False),
|
||||
(QuarterEnd(1, startingMonth=1), datetime(2007, 3, 31), False),
|
||||
(QuarterEnd(1, startingMonth=1), datetime(2008, 4, 30), True),
|
||||
(QuarterEnd(1, startingMonth=1), datetime(2008, 5, 30), False),
|
||||
(QuarterEnd(1, startingMonth=1), datetime(2008, 5, 31), False),
|
||||
(QuarterEnd(1, startingMonth=1), datetime(2007, 6, 29), False),
|
||||
(QuarterEnd(1, startingMonth=1), datetime(2007, 6, 30), False),
|
||||
(QuarterEnd(1, startingMonth=2), datetime(2008, 1, 31), False),
|
||||
(QuarterEnd(1, startingMonth=2), datetime(2007, 12, 31), False),
|
||||
(QuarterEnd(1, startingMonth=2), datetime(2008, 2, 29), True),
|
||||
(QuarterEnd(1, startingMonth=2), datetime(2007, 3, 30), False),
|
||||
(QuarterEnd(1, startingMonth=2), datetime(2007, 3, 31), False),
|
||||
(QuarterEnd(1, startingMonth=2), datetime(2008, 4, 30), False),
|
||||
(QuarterEnd(1, startingMonth=2), datetime(2008, 5, 30), False),
|
||||
(QuarterEnd(1, startingMonth=2), datetime(2008, 5, 31), True),
|
||||
(QuarterEnd(1, startingMonth=2), datetime(2007, 6, 29), False),
|
||||
(QuarterEnd(1, startingMonth=2), datetime(2007, 6, 30), False),
|
||||
(QuarterEnd(1, startingMonth=3), datetime(2008, 1, 31), False),
|
||||
(QuarterEnd(1, startingMonth=3), datetime(2007, 12, 31), True),
|
||||
(QuarterEnd(1, startingMonth=3), datetime(2008, 2, 29), False),
|
||||
(QuarterEnd(1, startingMonth=3), datetime(2007, 3, 30), False),
|
||||
(QuarterEnd(1, startingMonth=3), datetime(2007, 3, 31), True),
|
||||
(QuarterEnd(1, startingMonth=3), datetime(2008, 4, 30), False),
|
||||
(QuarterEnd(1, startingMonth=3), datetime(2008, 5, 30), False),
|
||||
(QuarterEnd(1, startingMonth=3), datetime(2008, 5, 31), False),
|
||||
(QuarterEnd(1, startingMonth=3), datetime(2007, 6, 29), False),
|
||||
(QuarterEnd(1, startingMonth=3), datetime(2007, 6, 30), True),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
@ -0,0 +1,405 @@
|
||||
"""
|
||||
Tests for offsets.Tick and subclasses
|
||||
"""
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
)
|
||||
|
||||
from hypothesis import (
|
||||
assume,
|
||||
example,
|
||||
given,
|
||||
)
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.offsets import delta_to_tick
|
||||
from pandas.errors import OutOfBoundsTimedelta
|
||||
|
||||
from pandas import (
|
||||
Timedelta,
|
||||
Timestamp,
|
||||
)
|
||||
import pandas._testing as tm
|
||||
from pandas._testing._hypothesis import INT_NEG_999_TO_POS_999
|
||||
from pandas.tests.tseries.offsets.common import assert_offset_equal
|
||||
|
||||
from pandas.tseries import offsets
|
||||
from pandas.tseries.offsets import (
|
||||
Hour,
|
||||
Micro,
|
||||
Milli,
|
||||
Minute,
|
||||
Nano,
|
||||
Second,
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Test Helpers
|
||||
|
||||
tick_classes = [Hour, Minute, Second, Milli, Micro, Nano]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_apply_ticks():
|
||||
result = offsets.Hour(3) + offsets.Hour(4)
|
||||
exp = offsets.Hour(7)
|
||||
assert result == exp
|
||||
|
||||
|
||||
def test_delta_to_tick():
|
||||
delta = timedelta(3)
|
||||
|
||||
tick = delta_to_tick(delta)
|
||||
assert tick == offsets.Day(3)
|
||||
|
||||
td = Timedelta(nanoseconds=5)
|
||||
tick = delta_to_tick(td)
|
||||
assert tick == Nano(5)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
@example(n=2, m=3)
|
||||
@example(n=800, m=300)
|
||||
@example(n=1000, m=5)
|
||||
@given(n=INT_NEG_999_TO_POS_999, m=INT_NEG_999_TO_POS_999)
|
||||
def test_tick_add_sub(cls, n, m):
|
||||
# For all Tick subclasses and all integers n, m, we should have
|
||||
# tick(n) + tick(m) == tick(n+m)
|
||||
# tick(n) - tick(m) == tick(n-m)
|
||||
left = cls(n)
|
||||
right = cls(m)
|
||||
expected = cls(n + m)
|
||||
|
||||
assert left + right == expected
|
||||
|
||||
expected = cls(n - m)
|
||||
assert left - right == expected
|
||||
|
||||
|
||||
@pytest.mark.arm_slow
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
@example(n=2, m=3)
|
||||
@given(n=INT_NEG_999_TO_POS_999, m=INT_NEG_999_TO_POS_999)
|
||||
def test_tick_equality(cls, n, m):
|
||||
assume(m != n)
|
||||
# tick == tock iff tick.n == tock.n
|
||||
left = cls(n)
|
||||
right = cls(m)
|
||||
assert left != right
|
||||
|
||||
right = cls(n)
|
||||
assert left == right
|
||||
assert not left != right
|
||||
|
||||
if n != 0:
|
||||
assert cls(n) != cls(-n)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_Hour():
|
||||
assert_offset_equal(Hour(), datetime(2010, 1, 1), datetime(2010, 1, 1, 1))
|
||||
assert_offset_equal(Hour(-1), datetime(2010, 1, 1, 1), datetime(2010, 1, 1))
|
||||
assert_offset_equal(2 * Hour(), datetime(2010, 1, 1), datetime(2010, 1, 1, 2))
|
||||
assert_offset_equal(-1 * Hour(), datetime(2010, 1, 1, 1), datetime(2010, 1, 1))
|
||||
|
||||
assert Hour(3) + Hour(2) == Hour(5)
|
||||
assert Hour(3) - Hour(2) == Hour()
|
||||
|
||||
assert Hour(4) != Hour(1)
|
||||
|
||||
|
||||
def test_Minute():
|
||||
assert_offset_equal(Minute(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 1))
|
||||
assert_offset_equal(Minute(-1), datetime(2010, 1, 1, 0, 1), datetime(2010, 1, 1))
|
||||
assert_offset_equal(2 * Minute(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 2))
|
||||
assert_offset_equal(-1 * Minute(), datetime(2010, 1, 1, 0, 1), datetime(2010, 1, 1))
|
||||
|
||||
assert Minute(3) + Minute(2) == Minute(5)
|
||||
assert Minute(3) - Minute(2) == Minute()
|
||||
assert Minute(5) != Minute()
|
||||
|
||||
|
||||
def test_Second():
|
||||
assert_offset_equal(Second(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 1))
|
||||
assert_offset_equal(Second(-1), datetime(2010, 1, 1, 0, 0, 1), datetime(2010, 1, 1))
|
||||
assert_offset_equal(
|
||||
2 * Second(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 2)
|
||||
)
|
||||
assert_offset_equal(
|
||||
-1 * Second(), datetime(2010, 1, 1, 0, 0, 1), datetime(2010, 1, 1)
|
||||
)
|
||||
|
||||
assert Second(3) + Second(2) == Second(5)
|
||||
assert Second(3) - Second(2) == Second()
|
||||
|
||||
|
||||
def test_Millisecond():
|
||||
assert_offset_equal(
|
||||
Milli(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 1000)
|
||||
)
|
||||
assert_offset_equal(
|
||||
Milli(-1), datetime(2010, 1, 1, 0, 0, 0, 1000), datetime(2010, 1, 1)
|
||||
)
|
||||
assert_offset_equal(
|
||||
Milli(2), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2000)
|
||||
)
|
||||
assert_offset_equal(
|
||||
2 * Milli(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2000)
|
||||
)
|
||||
assert_offset_equal(
|
||||
-1 * Milli(), datetime(2010, 1, 1, 0, 0, 0, 1000), datetime(2010, 1, 1)
|
||||
)
|
||||
|
||||
assert Milli(3) + Milli(2) == Milli(5)
|
||||
assert Milli(3) - Milli(2) == Milli()
|
||||
|
||||
|
||||
def test_MillisecondTimestampArithmetic():
|
||||
assert_offset_equal(
|
||||
Milli(), Timestamp("2010-01-01"), Timestamp("2010-01-01 00:00:00.001")
|
||||
)
|
||||
assert_offset_equal(
|
||||
Milli(-1), Timestamp("2010-01-01 00:00:00.001"), Timestamp("2010-01-01")
|
||||
)
|
||||
|
||||
|
||||
def test_Microsecond():
|
||||
assert_offset_equal(Micro(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 1))
|
||||
assert_offset_equal(
|
||||
Micro(-1), datetime(2010, 1, 1, 0, 0, 0, 1), datetime(2010, 1, 1)
|
||||
)
|
||||
|
||||
assert_offset_equal(
|
||||
2 * Micro(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2)
|
||||
)
|
||||
assert_offset_equal(
|
||||
-1 * Micro(), datetime(2010, 1, 1, 0, 0, 0, 1), datetime(2010, 1, 1)
|
||||
)
|
||||
|
||||
assert Micro(3) + Micro(2) == Micro(5)
|
||||
assert Micro(3) - Micro(2) == Micro()
|
||||
|
||||
|
||||
def test_NanosecondGeneric():
|
||||
timestamp = Timestamp(datetime(2010, 1, 1))
|
||||
assert timestamp.nanosecond == 0
|
||||
|
||||
result = timestamp + Nano(10)
|
||||
assert result.nanosecond == 10
|
||||
|
||||
reverse_result = Nano(10) + timestamp
|
||||
assert reverse_result.nanosecond == 10
|
||||
|
||||
|
||||
def test_Nanosecond():
|
||||
timestamp = Timestamp(datetime(2010, 1, 1))
|
||||
assert_offset_equal(Nano(), timestamp, timestamp + np.timedelta64(1, "ns"))
|
||||
assert_offset_equal(Nano(-1), timestamp + np.timedelta64(1, "ns"), timestamp)
|
||||
assert_offset_equal(2 * Nano(), timestamp, timestamp + np.timedelta64(2, "ns"))
|
||||
assert_offset_equal(-1 * Nano(), timestamp + np.timedelta64(1, "ns"), timestamp)
|
||||
|
||||
assert Nano(3) + Nano(2) == Nano(5)
|
||||
assert Nano(3) - Nano(2) == Nano()
|
||||
|
||||
# GH9284
|
||||
assert Nano(1) + Nano(10) == Nano(11)
|
||||
assert Nano(5) + Micro(1) == Nano(1005)
|
||||
assert Micro(5) + Nano(1) == Nano(5001)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"kls, expected",
|
||||
[
|
||||
(Hour, Timedelta(hours=5)),
|
||||
(Minute, Timedelta(hours=2, minutes=3)),
|
||||
(Second, Timedelta(hours=2, seconds=3)),
|
||||
(Milli, Timedelta(hours=2, milliseconds=3)),
|
||||
(Micro, Timedelta(hours=2, microseconds=3)),
|
||||
(Nano, Timedelta(hours=2, nanoseconds=3)),
|
||||
],
|
||||
)
|
||||
def test_tick_addition(kls, expected):
|
||||
offset = kls(3)
|
||||
td = Timedelta(hours=2)
|
||||
|
||||
for other in [td, td.to_pytimedelta(), td.to_timedelta64()]:
|
||||
result = offset + other
|
||||
assert isinstance(result, Timedelta)
|
||||
assert result == expected
|
||||
|
||||
result = other + offset
|
||||
assert isinstance(result, Timedelta)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_tick_delta_overflow():
|
||||
# GH#55503 raise OutOfBoundsTimedelta, not OverflowError
|
||||
tick = offsets.Day(10**9)
|
||||
msg = "Cannot cast 1000000000 days 00:00:00 to unit='ns' without overflow"
|
||||
depr_msg = "Day.delta is deprecated"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
|
||||
tick.delta
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_tick_division(cls):
|
||||
off = cls(10)
|
||||
|
||||
assert off / cls(5) == 2
|
||||
assert off / 2 == cls(5)
|
||||
assert off / 2.0 == cls(5)
|
||||
|
||||
assert off / off._as_pd_timedelta == 1
|
||||
assert off / off._as_pd_timedelta.to_timedelta64() == 1
|
||||
|
||||
assert off / Nano(1) == off._as_pd_timedelta / Nano(1)._as_pd_timedelta
|
||||
|
||||
if cls is not Nano:
|
||||
# A case where we end up with a smaller class
|
||||
result = off / 1000
|
||||
assert isinstance(result, offsets.Tick)
|
||||
assert not isinstance(result, cls)
|
||||
assert result._as_pd_timedelta == off._as_pd_timedelta / 1000
|
||||
|
||||
if cls._nanos_inc < Timedelta(seconds=1)._value:
|
||||
# Case where we end up with a bigger class
|
||||
result = off / 0.001
|
||||
assert isinstance(result, offsets.Tick)
|
||||
assert not isinstance(result, cls)
|
||||
assert result._as_pd_timedelta == off._as_pd_timedelta / 0.001
|
||||
|
||||
|
||||
def test_tick_mul_float():
|
||||
off = Micro(2)
|
||||
|
||||
# Case where we retain type
|
||||
result = off * 1.5
|
||||
expected = Micro(3)
|
||||
assert result == expected
|
||||
assert isinstance(result, Micro)
|
||||
|
||||
# Case where we bump up to the next type
|
||||
result = off * 1.25
|
||||
expected = Nano(2500)
|
||||
assert result == expected
|
||||
assert isinstance(result, Nano)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_tick_rdiv(cls):
|
||||
off = cls(10)
|
||||
delta = off._as_pd_timedelta
|
||||
td64 = delta.to_timedelta64()
|
||||
instance__type = ".".join([cls.__module__, cls.__name__])
|
||||
msg = (
|
||||
"unsupported operand type\\(s\\) for \\/: 'int'|'float' and "
|
||||
f"'{instance__type}'"
|
||||
)
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
2 / off
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
2.0 / off
|
||||
|
||||
assert (td64 * 2.5) / off == 2.5
|
||||
|
||||
if cls is not Nano:
|
||||
# skip pytimedelta for Nano since it gets dropped
|
||||
assert (delta.to_pytimedelta() * 2) / off == 2
|
||||
|
||||
result = np.array([2 * td64, td64]) / off
|
||||
expected = np.array([2.0, 1.0])
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls1", tick_classes)
|
||||
@pytest.mark.parametrize("cls2", tick_classes)
|
||||
def test_tick_zero(cls1, cls2):
|
||||
assert cls1(0) == cls2(0)
|
||||
assert cls1(0) + cls2(0) == cls1(0)
|
||||
|
||||
if cls1 is not Nano:
|
||||
assert cls1(2) + cls2(0) == cls1(2)
|
||||
|
||||
if cls1 is Nano:
|
||||
assert cls1(2) + Nano(0) == cls1(2)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_tick_equalities(cls):
|
||||
assert cls() == cls(1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_tick_offset(cls):
|
||||
msg = f"{cls.__name__}.is_anchored is deprecated "
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
assert not cls().is_anchored()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_compare_ticks(cls):
|
||||
three = cls(3)
|
||||
four = cls(4)
|
||||
|
||||
assert three < cls(4)
|
||||
assert cls(3) < four
|
||||
assert four > cls(3)
|
||||
assert cls(4) > three
|
||||
assert cls(3) == cls(3)
|
||||
assert cls(3) != cls(4)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_compare_ticks_to_strs(cls):
|
||||
# GH#23524
|
||||
off = cls(19)
|
||||
|
||||
# These tests should work with any strings, but we particularly are
|
||||
# interested in "infer" as that comparison is convenient to make in
|
||||
# Datetime/Timedelta Array/Index constructors
|
||||
assert not off == "infer"
|
||||
assert not "foo" == off
|
||||
|
||||
instance_type = ".".join([cls.__module__, cls.__name__])
|
||||
msg = (
|
||||
"'<'|'<='|'>'|'>=' not supported between instances of "
|
||||
f"'str' and '{instance_type}'|'{instance_type}' and 'str'"
|
||||
)
|
||||
|
||||
for left, right in [("infer", off), (off, "infer")]:
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_compare_ticks_to_timedeltalike(cls):
|
||||
off = cls(19)
|
||||
|
||||
td = off._as_pd_timedelta
|
||||
|
||||
others = [td, td.to_timedelta64()]
|
||||
if cls is not Nano:
|
||||
others.append(td.to_pytimedelta())
|
||||
|
||||
for other in others:
|
||||
assert off == other
|
||||
assert not off != other
|
||||
assert not off < other
|
||||
assert not off > other
|
||||
assert off <= other
|
||||
assert off >= other
|
@ -0,0 +1,351 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- Week
|
||||
- WeekOfMonth
|
||||
- LastWeekOfMonth
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
)
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import Timestamp
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
Day,
|
||||
LastWeekOfMonth,
|
||||
Week,
|
||||
WeekOfMonth,
|
||||
)
|
||||
|
||||
import pandas._testing as tm
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
WeekDay,
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
|
||||
class TestWeek:
|
||||
def test_repr(self):
|
||||
assert repr(Week(weekday=0)) == "<Week: weekday=0>"
|
||||
assert repr(Week(n=-1, weekday=0)) == "<-1 * Week: weekday=0>"
|
||||
assert repr(Week(n=-2, weekday=0)) == "<-2 * Weeks: weekday=0>"
|
||||
|
||||
def test_corner(self):
|
||||
with pytest.raises(ValueError, match="Day must be"):
|
||||
Week(weekday=7)
|
||||
|
||||
with pytest.raises(ValueError, match="Day must be"):
|
||||
Week(weekday=-1)
|
||||
|
||||
def test_is_anchored(self):
|
||||
msg = "Week.is_anchored is deprecated "
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
assert Week(weekday=0).is_anchored()
|
||||
assert not Week().is_anchored()
|
||||
assert not Week(2, weekday=2).is_anchored()
|
||||
assert not Week(2).is_anchored()
|
||||
|
||||
offset_cases = []
|
||||
# not business week
|
||||
offset_cases.append(
|
||||
(
|
||||
Week(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 8),
|
||||
datetime(2008, 1, 4): datetime(2008, 1, 11),
|
||||
datetime(2008, 1, 5): datetime(2008, 1, 12),
|
||||
datetime(2008, 1, 6): datetime(2008, 1, 13),
|
||||
datetime(2008, 1, 7): datetime(2008, 1, 14),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
# Mon
|
||||
offset_cases.append(
|
||||
(
|
||||
Week(weekday=0),
|
||||
{
|
||||
datetime(2007, 12, 31): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 4): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 5): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 6): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 7): datetime(2008, 1, 14),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
# n=0 -> roll forward. Mon
|
||||
offset_cases.append(
|
||||
(
|
||||
Week(0, weekday=0),
|
||||
{
|
||||
datetime(2007, 12, 31): datetime(2007, 12, 31),
|
||||
datetime(2008, 1, 4): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 5): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 6): datetime(2008, 1, 7),
|
||||
datetime(2008, 1, 7): datetime(2008, 1, 7),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
# n=0 -> roll forward. Mon
|
||||
offset_cases.append(
|
||||
(
|
||||
Week(-2, weekday=1),
|
||||
{
|
||||
datetime(2010, 4, 6): datetime(2010, 3, 23),
|
||||
datetime(2010, 4, 8): datetime(2010, 3, 30),
|
||||
datetime(2010, 4, 5): datetime(2010, 3, 23),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
@pytest.mark.parametrize("weekday", range(7))
|
||||
def test_is_on_offset(self, weekday):
|
||||
offset = Week(weekday=weekday)
|
||||
|
||||
for day in range(1, 8):
|
||||
date = datetime(2008, 1, day)
|
||||
expected = day % 7 == weekday
|
||||
assert_is_on_offset(offset, date, expected)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"n,date",
|
||||
[
|
||||
(2, "1862-01-13 09:03:34.873477378+0210"),
|
||||
(-2, "1856-10-24 16:18:36.556360110-0717"),
|
||||
],
|
||||
)
|
||||
def test_is_on_offset_weekday_none(self, n, date):
|
||||
# GH 18510 Week with weekday = None, normalize = False
|
||||
# should always be is_on_offset
|
||||
offset = Week(n=n, weekday=None)
|
||||
ts = Timestamp(date, tz="Africa/Lusaka")
|
||||
fast = offset.is_on_offset(ts)
|
||||
slow = (ts + offset) - offset == ts
|
||||
assert fast == slow
|
||||
|
||||
def test_week_add_invalid(self):
|
||||
# Week with weekday should raise TypeError and _not_ AttributeError
|
||||
# when adding invalid offset
|
||||
offset = Week(weekday=1)
|
||||
other = Day()
|
||||
with pytest.raises(TypeError, match="Cannot add"):
|
||||
offset + other
|
||||
|
||||
|
||||
class TestWeekOfMonth:
|
||||
def test_constructor(self):
|
||||
with pytest.raises(ValueError, match="^Week"):
|
||||
WeekOfMonth(n=1, week=4, weekday=0)
|
||||
|
||||
with pytest.raises(ValueError, match="^Week"):
|
||||
WeekOfMonth(n=1, week=-1, weekday=0)
|
||||
|
||||
with pytest.raises(ValueError, match="^Day"):
|
||||
WeekOfMonth(n=1, week=0, weekday=-1)
|
||||
|
||||
with pytest.raises(ValueError, match="^Day"):
|
||||
WeekOfMonth(n=1, week=0, weekday=-7)
|
||||
|
||||
def test_repr(self):
|
||||
assert (
|
||||
repr(WeekOfMonth(weekday=1, week=2)) == "<WeekOfMonth: week=2, weekday=1>"
|
||||
)
|
||||
|
||||
def test_offset(self):
|
||||
date1 = datetime(2011, 1, 4) # 1st Tuesday of Month
|
||||
date2 = datetime(2011, 1, 11) # 2nd Tuesday of Month
|
||||
date3 = datetime(2011, 1, 18) # 3rd Tuesday of Month
|
||||
date4 = datetime(2011, 1, 25) # 4th Tuesday of Month
|
||||
|
||||
# see for loop for structure
|
||||
test_cases = [
|
||||
(-2, 2, 1, date1, datetime(2010, 11, 16)),
|
||||
(-2, 2, 1, date2, datetime(2010, 11, 16)),
|
||||
(-2, 2, 1, date3, datetime(2010, 11, 16)),
|
||||
(-2, 2, 1, date4, datetime(2010, 12, 21)),
|
||||
(-1, 2, 1, date1, datetime(2010, 12, 21)),
|
||||
(-1, 2, 1, date2, datetime(2010, 12, 21)),
|
||||
(-1, 2, 1, date3, datetime(2010, 12, 21)),
|
||||
(-1, 2, 1, date4, datetime(2011, 1, 18)),
|
||||
(0, 0, 1, date1, datetime(2011, 1, 4)),
|
||||
(0, 0, 1, date2, datetime(2011, 2, 1)),
|
||||
(0, 0, 1, date3, datetime(2011, 2, 1)),
|
||||
(0, 0, 1, date4, datetime(2011, 2, 1)),
|
||||
(0, 1, 1, date1, datetime(2011, 1, 11)),
|
||||
(0, 1, 1, date2, datetime(2011, 1, 11)),
|
||||
(0, 1, 1, date3, datetime(2011, 2, 8)),
|
||||
(0, 1, 1, date4, datetime(2011, 2, 8)),
|
||||
(0, 0, 1, date1, datetime(2011, 1, 4)),
|
||||
(0, 1, 1, date2, datetime(2011, 1, 11)),
|
||||
(0, 2, 1, date3, datetime(2011, 1, 18)),
|
||||
(0, 3, 1, date4, datetime(2011, 1, 25)),
|
||||
(1, 0, 0, date1, datetime(2011, 2, 7)),
|
||||
(1, 0, 0, date2, datetime(2011, 2, 7)),
|
||||
(1, 0, 0, date3, datetime(2011, 2, 7)),
|
||||
(1, 0, 0, date4, datetime(2011, 2, 7)),
|
||||
(1, 0, 1, date1, datetime(2011, 2, 1)),
|
||||
(1, 0, 1, date2, datetime(2011, 2, 1)),
|
||||
(1, 0, 1, date3, datetime(2011, 2, 1)),
|
||||
(1, 0, 1, date4, datetime(2011, 2, 1)),
|
||||
(1, 0, 2, date1, datetime(2011, 1, 5)),
|
||||
(1, 0, 2, date2, datetime(2011, 2, 2)),
|
||||
(1, 0, 2, date3, datetime(2011, 2, 2)),
|
||||
(1, 0, 2, date4, datetime(2011, 2, 2)),
|
||||
(1, 2, 1, date1, datetime(2011, 1, 18)),
|
||||
(1, 2, 1, date2, datetime(2011, 1, 18)),
|
||||
(1, 2, 1, date3, datetime(2011, 2, 15)),
|
||||
(1, 2, 1, date4, datetime(2011, 2, 15)),
|
||||
(2, 2, 1, date1, datetime(2011, 2, 15)),
|
||||
(2, 2, 1, date2, datetime(2011, 2, 15)),
|
||||
(2, 2, 1, date3, datetime(2011, 3, 15)),
|
||||
(2, 2, 1, date4, datetime(2011, 3, 15)),
|
||||
]
|
||||
|
||||
for n, week, weekday, dt, expected in test_cases:
|
||||
offset = WeekOfMonth(n, week=week, weekday=weekday)
|
||||
assert_offset_equal(offset, dt, expected)
|
||||
|
||||
# try subtracting
|
||||
result = datetime(2011, 2, 1) - WeekOfMonth(week=1, weekday=2)
|
||||
assert result == datetime(2011, 1, 12)
|
||||
|
||||
result = datetime(2011, 2, 3) - WeekOfMonth(week=0, weekday=2)
|
||||
assert result == datetime(2011, 2, 2)
|
||||
|
||||
on_offset_cases = [
|
||||
(0, 0, datetime(2011, 2, 7), True),
|
||||
(0, 0, datetime(2011, 2, 6), False),
|
||||
(0, 0, datetime(2011, 2, 14), False),
|
||||
(1, 0, datetime(2011, 2, 14), True),
|
||||
(0, 1, datetime(2011, 2, 1), True),
|
||||
(0, 1, datetime(2011, 2, 8), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
week, weekday, dt, expected = case
|
||||
offset = WeekOfMonth(week=week, weekday=weekday)
|
||||
assert offset.is_on_offset(dt) == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"n,week,date,tz",
|
||||
[
|
||||
(2, 2, "1916-05-15 01:14:49.583410462+0422", "Asia/Qyzylorda"),
|
||||
(-3, 1, "1980-12-08 03:38:52.878321185+0500", "Asia/Oral"),
|
||||
],
|
||||
)
|
||||
def test_is_on_offset_nanoseconds(self, n, week, date, tz):
|
||||
# GH 18864
|
||||
# Make sure that nanoseconds don't trip up is_on_offset (and with it apply)
|
||||
offset = WeekOfMonth(n=n, week=week, weekday=0)
|
||||
ts = Timestamp(date, tz=tz)
|
||||
fast = offset.is_on_offset(ts)
|
||||
slow = (ts + offset) - offset == ts
|
||||
assert fast == slow
|
||||
|
||||
|
||||
class TestLastWeekOfMonth:
|
||||
def test_constructor(self):
|
||||
with pytest.raises(ValueError, match="^N cannot be 0"):
|
||||
LastWeekOfMonth(n=0, weekday=1)
|
||||
|
||||
with pytest.raises(ValueError, match="^Day"):
|
||||
LastWeekOfMonth(n=1, weekday=-1)
|
||||
|
||||
with pytest.raises(ValueError, match="^Day"):
|
||||
LastWeekOfMonth(n=1, weekday=7)
|
||||
|
||||
def test_offset(self):
|
||||
# Saturday
|
||||
last_sat = datetime(2013, 8, 31)
|
||||
next_sat = datetime(2013, 9, 28)
|
||||
offset_sat = LastWeekOfMonth(n=1, weekday=5)
|
||||
|
||||
one_day_before = last_sat + timedelta(days=-1)
|
||||
assert one_day_before + offset_sat == last_sat
|
||||
|
||||
one_day_after = last_sat + timedelta(days=+1)
|
||||
assert one_day_after + offset_sat == next_sat
|
||||
|
||||
# Test On that day
|
||||
assert last_sat + offset_sat == next_sat
|
||||
|
||||
# Thursday
|
||||
|
||||
offset_thur = LastWeekOfMonth(n=1, weekday=3)
|
||||
last_thurs = datetime(2013, 1, 31)
|
||||
next_thurs = datetime(2013, 2, 28)
|
||||
|
||||
one_day_before = last_thurs + timedelta(days=-1)
|
||||
assert one_day_before + offset_thur == last_thurs
|
||||
|
||||
one_day_after = last_thurs + timedelta(days=+1)
|
||||
assert one_day_after + offset_thur == next_thurs
|
||||
|
||||
# Test on that day
|
||||
assert last_thurs + offset_thur == next_thurs
|
||||
|
||||
three_before = last_thurs + timedelta(days=-3)
|
||||
assert three_before + offset_thur == last_thurs
|
||||
|
||||
two_after = last_thurs + timedelta(days=+2)
|
||||
assert two_after + offset_thur == next_thurs
|
||||
|
||||
offset_sunday = LastWeekOfMonth(n=1, weekday=WeekDay.SUN)
|
||||
assert datetime(2013, 7, 31) + offset_sunday == datetime(2013, 8, 25)
|
||||
|
||||
on_offset_cases = [
|
||||
(WeekDay.SUN, datetime(2013, 1, 27), True),
|
||||
(WeekDay.SAT, datetime(2013, 3, 30), True),
|
||||
(WeekDay.MON, datetime(2013, 2, 18), False), # Not the last Mon
|
||||
(WeekDay.SUN, datetime(2013, 2, 25), False), # Not a SUN
|
||||
(WeekDay.MON, datetime(2013, 2, 25), True),
|
||||
(WeekDay.SAT, datetime(2013, 11, 30), True),
|
||||
(WeekDay.SAT, datetime(2006, 8, 26), True),
|
||||
(WeekDay.SAT, datetime(2007, 8, 25), True),
|
||||
(WeekDay.SAT, datetime(2008, 8, 30), True),
|
||||
(WeekDay.SAT, datetime(2009, 8, 29), True),
|
||||
(WeekDay.SAT, datetime(2010, 8, 28), True),
|
||||
(WeekDay.SAT, datetime(2011, 8, 27), True),
|
||||
(WeekDay.SAT, datetime(2019, 8, 31), True),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
weekday, dt, expected = case
|
||||
offset = LastWeekOfMonth(weekday=weekday)
|
||||
assert offset.is_on_offset(dt) == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"n,weekday,date,tz",
|
||||
[
|
||||
(4, 6, "1917-05-27 20:55:27.084284178+0200", "Europe/Warsaw"),
|
||||
(-4, 5, "2005-08-27 05:01:42.799392561-0500", "America/Rainy_River"),
|
||||
],
|
||||
)
|
||||
def test_last_week_of_month_on_offset(self, n, weekday, date, tz):
|
||||
# GH 19036, GH 18977 _adjust_dst was incorrect for LastWeekOfMonth
|
||||
offset = LastWeekOfMonth(n=n, weekday=weekday)
|
||||
ts = Timestamp(date, tz=tz)
|
||||
slow = (ts + offset) - offset == ts
|
||||
fast = offset.is_on_offset(ts)
|
||||
assert fast == slow
|
||||
|
||||
def test_repr(self):
|
||||
assert (
|
||||
repr(LastWeekOfMonth(n=2, weekday=1)) == "<2 * LastWeekOfMonths: weekday=1>"
|
||||
)
|
@ -0,0 +1,339 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- YearBegin
|
||||
- YearEnd
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas import Timestamp
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
YearBegin,
|
||||
YearEnd,
|
||||
)
|
||||
|
||||
|
||||
class TestYearBegin:
|
||||
def test_misspecified(self):
|
||||
with pytest.raises(ValueError, match="Month must go from 1 to 12"):
|
||||
YearBegin(month=13)
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
YearBegin(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2009, 1, 1),
|
||||
datetime(2008, 6, 30): datetime(2009, 1, 1),
|
||||
datetime(2008, 12, 31): datetime(2009, 1, 1),
|
||||
datetime(2005, 12, 30): datetime(2006, 1, 1),
|
||||
datetime(2005, 12, 31): datetime(2006, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearBegin(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 1, 1),
|
||||
datetime(2008, 6, 30): datetime(2009, 1, 1),
|
||||
datetime(2008, 12, 31): datetime(2009, 1, 1),
|
||||
datetime(2005, 12, 30): datetime(2006, 1, 1),
|
||||
datetime(2005, 12, 31): datetime(2006, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearBegin(3),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2011, 1, 1),
|
||||
datetime(2008, 6, 30): datetime(2011, 1, 1),
|
||||
datetime(2008, 12, 31): datetime(2011, 1, 1),
|
||||
datetime(2005, 12, 30): datetime(2008, 1, 1),
|
||||
datetime(2005, 12, 31): datetime(2008, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearBegin(-1),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 1, 1),
|
||||
datetime(2007, 1, 15): datetime(2007, 1, 1),
|
||||
datetime(2008, 6, 30): datetime(2008, 1, 1),
|
||||
datetime(2008, 12, 31): datetime(2008, 1, 1),
|
||||
datetime(2006, 12, 29): datetime(2006, 1, 1),
|
||||
datetime(2006, 12, 30): datetime(2006, 1, 1),
|
||||
datetime(2007, 1, 1): datetime(2006, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearBegin(-2),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2005, 1, 1),
|
||||
datetime(2008, 6, 30): datetime(2007, 1, 1),
|
||||
datetime(2008, 12, 31): datetime(2007, 1, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearBegin(month=4),
|
||||
{
|
||||
datetime(2007, 4, 1): datetime(2008, 4, 1),
|
||||
datetime(2007, 4, 15): datetime(2008, 4, 1),
|
||||
datetime(2007, 3, 1): datetime(2007, 4, 1),
|
||||
datetime(2007, 12, 15): datetime(2008, 4, 1),
|
||||
datetime(2012, 1, 31): datetime(2012, 4, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearBegin(0, month=4),
|
||||
{
|
||||
datetime(2007, 4, 1): datetime(2007, 4, 1),
|
||||
datetime(2007, 3, 1): datetime(2007, 4, 1),
|
||||
datetime(2007, 12, 15): datetime(2008, 4, 1),
|
||||
datetime(2012, 1, 31): datetime(2012, 4, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearBegin(4, month=4),
|
||||
{
|
||||
datetime(2007, 4, 1): datetime(2011, 4, 1),
|
||||
datetime(2007, 4, 15): datetime(2011, 4, 1),
|
||||
datetime(2007, 3, 1): datetime(2010, 4, 1),
|
||||
datetime(2007, 12, 15): datetime(2011, 4, 1),
|
||||
datetime(2012, 1, 31): datetime(2015, 4, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearBegin(-1, month=4),
|
||||
{
|
||||
datetime(2007, 4, 1): datetime(2006, 4, 1),
|
||||
datetime(2007, 3, 1): datetime(2006, 4, 1),
|
||||
datetime(2007, 12, 15): datetime(2007, 4, 1),
|
||||
datetime(2012, 1, 31): datetime(2011, 4, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearBegin(-3, month=4),
|
||||
{
|
||||
datetime(2007, 4, 1): datetime(2004, 4, 1),
|
||||
datetime(2007, 3, 1): datetime(2004, 4, 1),
|
||||
datetime(2007, 12, 15): datetime(2005, 4, 1),
|
||||
datetime(2012, 1, 31): datetime(2009, 4, 1),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
on_offset_cases = [
|
||||
(YearBegin(), datetime(2007, 1, 3), False),
|
||||
(YearBegin(), datetime(2008, 1, 1), True),
|
||||
(YearBegin(), datetime(2006, 12, 31), False),
|
||||
(YearBegin(), datetime(2006, 1, 2), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
|
||||
class TestYearEnd:
|
||||
def test_misspecified(self):
|
||||
with pytest.raises(ValueError, match="Month must go from 1 to 12"):
|
||||
YearEnd(month=13)
|
||||
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
YearEnd(),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 12, 31),
|
||||
datetime(2008, 6, 30): datetime(2008, 12, 31),
|
||||
datetime(2008, 12, 31): datetime(2009, 12, 31),
|
||||
datetime(2005, 12, 30): datetime(2005, 12, 31),
|
||||
datetime(2005, 12, 31): datetime(2006, 12, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearEnd(0),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 12, 31),
|
||||
datetime(2008, 6, 30): datetime(2008, 12, 31),
|
||||
datetime(2008, 12, 31): datetime(2008, 12, 31),
|
||||
datetime(2005, 12, 30): datetime(2005, 12, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearEnd(-1),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 31),
|
||||
datetime(2008, 6, 30): datetime(2007, 12, 31),
|
||||
datetime(2008, 12, 31): datetime(2007, 12, 31),
|
||||
datetime(2006, 12, 29): datetime(2005, 12, 31),
|
||||
datetime(2006, 12, 30): datetime(2005, 12, 31),
|
||||
datetime(2007, 1, 1): datetime(2006, 12, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearEnd(-2),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2005, 12, 31),
|
||||
datetime(2008, 6, 30): datetime(2006, 12, 31),
|
||||
datetime(2008, 12, 31): datetime(2006, 12, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
on_offset_cases = [
|
||||
(YearEnd(), datetime(2007, 12, 31), True),
|
||||
(YearEnd(), datetime(2008, 1, 1), False),
|
||||
(YearEnd(), datetime(2006, 12, 31), True),
|
||||
(YearEnd(), datetime(2006, 12, 29), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
|
||||
class TestYearEndDiffMonth:
|
||||
offset_cases = []
|
||||
offset_cases.append(
|
||||
(
|
||||
YearEnd(month=3),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 3, 31),
|
||||
datetime(2008, 2, 15): datetime(2008, 3, 31),
|
||||
datetime(2008, 3, 31): datetime(2009, 3, 31),
|
||||
datetime(2008, 3, 30): datetime(2008, 3, 31),
|
||||
datetime(2005, 3, 31): datetime(2006, 3, 31),
|
||||
datetime(2006, 7, 30): datetime(2007, 3, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearEnd(0, month=3),
|
||||
{
|
||||
datetime(2008, 1, 1): datetime(2008, 3, 31),
|
||||
datetime(2008, 2, 28): datetime(2008, 3, 31),
|
||||
datetime(2008, 3, 31): datetime(2008, 3, 31),
|
||||
datetime(2005, 3, 30): datetime(2005, 3, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearEnd(-1, month=3),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2006, 3, 31),
|
||||
datetime(2008, 2, 28): datetime(2007, 3, 31),
|
||||
datetime(2008, 3, 31): datetime(2007, 3, 31),
|
||||
datetime(2006, 3, 29): datetime(2005, 3, 31),
|
||||
datetime(2006, 3, 30): datetime(2005, 3, 31),
|
||||
datetime(2007, 3, 1): datetime(2006, 3, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
offset_cases.append(
|
||||
(
|
||||
YearEnd(-2, month=3),
|
||||
{
|
||||
datetime(2007, 1, 1): datetime(2005, 3, 31),
|
||||
datetime(2008, 6, 30): datetime(2007, 3, 31),
|
||||
datetime(2008, 3, 31): datetime(2006, 3, 31),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("case", offset_cases)
|
||||
def test_offset(self, case):
|
||||
offset, cases = case
|
||||
for base, expected in cases.items():
|
||||
assert_offset_equal(offset, base, expected)
|
||||
|
||||
on_offset_cases = [
|
||||
(YearEnd(month=3), datetime(2007, 3, 31), True),
|
||||
(YearEnd(month=3), datetime(2008, 1, 1), False),
|
||||
(YearEnd(month=3), datetime(2006, 3, 31), True),
|
||||
(YearEnd(month=3), datetime(2006, 3, 29), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_is_on_offset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_is_on_offset(offset, dt, expected)
|
||||
|
||||
|
||||
def test_add_out_of_pydatetime_range():
|
||||
# GH#50348 don't raise in Timestamp.replace
|
||||
ts = Timestamp(np.datetime64("-20000-12-31"))
|
||||
off = YearEnd()
|
||||
|
||||
result = ts + off
|
||||
# TODO(cython3): "arg: datetime" annotation will impose
|
||||
# datetime limitations on Timestamp. The fused type below works in cy3
|
||||
# ctypedef fused datetimelike:
|
||||
# _Timestamp
|
||||
# datetime
|
||||
# expected = Timestamp(np.datetime64("-19999-12-31"))
|
||||
# assert result == expected
|
||||
assert result.year in (-19999, 1973)
|
||||
assert result.month == 12
|
||||
assert result.day == 31
|
Reference in New Issue
Block a user