first commit
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,80 @@
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
Period,
|
||||
Resolution,
|
||||
to_offset,
|
||||
)
|
||||
from pandas._libs.tslibs.dtypes import _attrname_to_abbrevs
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,exp_freqstr",
|
||||
[("D", "D"), ("W", "D"), ("M", "D"), ("S", "S"), ("T", "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._get_to_timestamp_base()
|
||||
assert result_code == exp_code
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected",
|
||||
[
|
||||
("A", "year"),
|
||||
("Q", "quarter"),
|
||||
("M", "month"),
|
||||
("D", "day"),
|
||||
("H", "hour"),
|
||||
("T", "minute"),
|
||||
("S", "second"),
|
||||
("L", "millisecond"),
|
||||
("U", "microsecond"),
|
||||
("N", "nanosecond"),
|
||||
],
|
||||
)
|
||||
def test_get_attrname_from_abbrev(freqstr, expected):
|
||||
assert Resolution.get_reso_from_freq(freqstr).attrname == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", ["D", "H", "T", "S", "L", "U", "N"])
|
||||
def test_get_freq_roundtrip2(freq):
|
||||
obj = Resolution.get_reso_from_freq(freq)
|
||||
result = _attrname_to_abbrevs[obj.attrname]
|
||||
assert freq == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"args,expected",
|
||||
[
|
||||
((1.5, "T"), (90, "S")),
|
||||
((62.4, "T"), (3744, "S")),
|
||||
((1.04, "H"), (3744, "S")),
|
||||
((1, "D"), (1, "D")),
|
||||
((0.342931, "H"), (1234551600, "U")),
|
||||
((1.2345, "D"), (106660800, "L")),
|
||||
],
|
||||
)
|
||||
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, "N"),
|
||||
# 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])
|
||||
@@ -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,504 @@
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.ccalendar import (
|
||||
DAYS,
|
||||
MONTHS,
|
||||
)
|
||||
from pandas._libs.tslibs.period import INVALID_FREQ_ERR_MSG
|
||||
from pandas.compat import is_platform_windows
|
||||
|
||||
from pandas import (
|
||||
DatetimeIndex,
|
||||
Index,
|
||||
Series,
|
||||
Timestamp,
|
||||
date_range,
|
||||
period_range,
|
||||
)
|
||||
import pandas._testing as tm
|
||||
from pandas.core.tools.datetimes import to_datetime
|
||||
|
||||
import pandas.tseries.frequencies as frequencies
|
||||
import pandas.tseries.offsets as offsets
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
params=[
|
||||
(timedelta(1), "D"),
|
||||
(timedelta(hours=1), "H"),
|
||||
(timedelta(minutes=1), "T"),
|
||||
(timedelta(seconds=1), "S"),
|
||||
(np.timedelta64(1, "ns"), "N"),
|
||||
(timedelta(microseconds=1), "U"),
|
||||
(timedelta(microseconds=1000), "L"),
|
||||
]
|
||||
)
|
||||
def base_delta_code_pair(request):
|
||||
return request.param
|
||||
|
||||
|
||||
freqs = (
|
||||
[f"Q-{month}" for month in MONTHS]
|
||||
+ [f"{annual}-{month}" for annual in ["A", "BA"] for month in MONTHS]
|
||||
+ ["M", "BM", "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("Q-"):
|
||||
assert frequencies.infer_freq(index) == gen.freqstr
|
||||
else:
|
||||
inf_freq = frequencies.infer_freq(index)
|
||||
is_dec_range = inf_freq == "Q-DEC" and gen.freqstr in (
|
||||
"Q",
|
||||
"Q-DEC",
|
||||
"Q-SEP",
|
||||
"Q-JUN",
|
||||
"Q-MAR",
|
||||
)
|
||||
is_nov_range = inf_freq == "Q-NOV" and gen.freqstr in (
|
||||
"Q-NOV",
|
||||
"Q-AUG",
|
||||
"Q-MAY",
|
||||
"Q-FEB",
|
||||
)
|
||||
is_oct_range = inf_freq == "Q-OCT" and gen.freqstr in (
|
||||
"Q-OCT",
|
||||
"Q-JUL",
|
||||
"Q-APR",
|
||||
"Q-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 == "M"
|
||||
|
||||
|
||||
def test_annual_ambiguous():
|
||||
rng = DatetimeIndex(["1/31/2000", "1/31/2001", "1/31/2002"])
|
||||
assert rng.inferred_freq == "A-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", "Q-DEC"), ("Q-NOV", "Q-NOV"), ("Q-OCT", "Q-OCT")]
|
||||
)
|
||||
def test_infer_freq_index(freq, expected):
|
||||
rng = period_range("1959Q2", "2009Q3", freq=freq)
|
||||
rng = Index(rng.to_timestamp("D", how="e").astype(object))
|
||||
|
||||
assert rng.inferred_freq == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected,dates",
|
||||
list(
|
||||
{
|
||||
"AS-JAN": ["2009-01-01", "2010-01-01", "2011-01-01", "2012-01-01"],
|
||||
"Q-OCT": ["2009-01-31", "2009-04-30", "2009-07-31", "2009-10-31"],
|
||||
"M": ["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()
|
||||
),
|
||||
)
|
||||
def test_infer_freq_tz(tz_naive_fixture, expected, dates):
|
||||
# see gh-7310
|
||||
tz = tz_naive_fixture
|
||||
idx = DatetimeIndex(dates, tz=tz)
|
||||
assert idx.inferred_freq == expected
|
||||
|
||||
|
||||
@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", "10T", "3601S", "3600001L", "3600000001U", "3600000000001N"]
|
||||
)
|
||||
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 == "-1A-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", [tm.makeIntIndex(10), tm.makeFloatIndex(10), tm.makePeriodIndex(10)]
|
||||
)
|
||||
def test_invalid_index_types(idx):
|
||||
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")
|
||||
@pytest.mark.parametrize("idx", [tm.makeStringIndex(10), tm.makeUnicodeIndex(10)])
|
||||
def test_invalid_index_types_unicode(idx):
|
||||
# see gh-10822
|
||||
#
|
||||
# Odd error message on conversions to datetime for unicode.
|
||||
msg = "Unknown string format"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
frequencies.infer_freq(idx)
|
||||
|
||||
|
||||
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():
|
||||
# see gh-6407
|
||||
msg = "Unknown string format"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
frequencies.infer_freq(Series(["foo", "bar"]))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", [None, "L"])
|
||||
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", ["M", "L", "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",
|
||||
[
|
||||
frequencies._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",
|
||||
"Q@JAN",
|
||||
"Q@FEB",
|
||||
"Q@MAR",
|
||||
"A@JAN",
|
||||
"A@FEB",
|
||||
"A@MAR",
|
||||
"A@APR",
|
||||
"A@MAY",
|
||||
"A@JUN",
|
||||
"A@JUL",
|
||||
"A@AUG",
|
||||
"A@SEP",
|
||||
"A@OCT",
|
||||
"A@NOV",
|
||||
"A@DEC",
|
||||
"Y@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 = frequencies._get_offset("ms")
|
||||
right = frequencies._get_offset("MS")
|
||||
|
||||
assert left == offsets.Milli()
|
||||
assert right == offsets.MonthBegin()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,116 @@
|
||||
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):
|
||||
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.
|
||||
tm.assert_index_equal(jan1.holidays(), DatetimeIndex(["01-Jan-2015"]))
|
||||
tm.assert_index_equal(jan2.holidays(), DatetimeIndex(["02-Jan-2015"]))
|
||||
|
||||
|
||||
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,38 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pandas.tseries.holiday import (
|
||||
AbstractHolidayCalendar,
|
||||
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),
|
||||
]
|
||||
@@ -0,0 +1,266 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from pytz import utc
|
||||
|
||||
import pandas._testing as tm
|
||||
|
||||
from pandas.tseries.holiday import (
|
||||
MO,
|
||||
SA,
|
||||
AbstractHolidayCalendar,
|
||||
DateOffset,
|
||||
EasterMonday,
|
||||
GoodFriday,
|
||||
Holiday,
|
||||
HolidayCalendarFactory,
|
||||
Timestamp,
|
||||
USColumbusDay,
|
||||
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,
|
||||
)
|
||||
@@ -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
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,206 @@
|
||||
"""
|
||||
Assertion helpers and base class for offsets tests
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from dateutil.tz.tz import tzlocal
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
OutOfBoundsDatetime,
|
||||
Timestamp,
|
||||
)
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
FY5253,
|
||||
BusinessHour,
|
||||
CustomBusinessHour,
|
||||
DateOffset,
|
||||
FY5253Quarter,
|
||||
LastWeekOfMonth,
|
||||
Week,
|
||||
WeekOfMonth,
|
||||
)
|
||||
from pandas.compat import IS64
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
class Base:
|
||||
_offset: type[DateOffset] | None = None
|
||||
d = Timestamp(datetime(2008, 1, 2))
|
||||
|
||||
timezones = [
|
||||
None,
|
||||
"UTC",
|
||||
"Asia/Tokyo",
|
||||
"US/Eastern",
|
||||
"dateutil/Asia/Tokyo",
|
||||
"dateutil/US/Pacific",
|
||||
]
|
||||
|
||||
def _get_offset(self, 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
|
||||
|
||||
def test_apply_out_of_range(self, request, tz_naive_fixture):
|
||||
tz = tz_naive_fixture
|
||||
if self._offset is None:
|
||||
return
|
||||
|
||||
# try to create an out-of-bounds result timestamp; if we can't create
|
||||
# the offset skip
|
||||
try:
|
||||
if self._offset in (BusinessHour, CustomBusinessHour):
|
||||
# Using 10000 in BusinessHour fails in tz check because of DST
|
||||
# difference
|
||||
offset = self._get_offset(self._offset, value=100000)
|
||||
else:
|
||||
offset = self._get_offset(self._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 isinstance(tz, tzlocal) and not IS64:
|
||||
# If we hit OutOfBoundsDatetime on non-64 bit machines
|
||||
# we'll drop out of the try clause before the next test
|
||||
request.node.add_marker(
|
||||
pytest.mark.xfail(reason="OverflowError inside tzlocal past 2038")
|
||||
)
|
||||
assert t.tzinfo == result.tzinfo
|
||||
|
||||
except OutOfBoundsDatetime:
|
||||
pass
|
||||
except (ValueError, KeyError):
|
||||
# we are creating an invalid offset
|
||||
# so ignore
|
||||
pass
|
||||
|
||||
def test_offsets_compare_equal(self):
|
||||
# root cause of GH#456: __ne__ was not implemented
|
||||
if self._offset is None:
|
||||
return
|
||||
offset1 = self._offset()
|
||||
offset2 = self._offset()
|
||||
assert not offset1 != offset2
|
||||
assert offset1 == offset2
|
||||
|
||||
def test_rsub(self):
|
||||
if self._offset is None or not hasattr(self, "offset2"):
|
||||
# i.e. skip for TestCommon and YQM subclasses that do not have
|
||||
# offset2 attr
|
||||
return
|
||||
assert self.d - self.offset2 == (-self.offset2)._apply(self.d)
|
||||
|
||||
def test_radd(self):
|
||||
if self._offset is None or not hasattr(self, "offset2"):
|
||||
# i.e. skip for TestCommon and YQM subclasses that do not have
|
||||
# offset2 attr
|
||||
return
|
||||
assert self.d + self.offset2 == self.offset2 + self.d
|
||||
|
||||
def test_sub(self):
|
||||
if self._offset is None or not hasattr(self, "offset2"):
|
||||
# i.e. skip for TestCommon and YQM subclasses that do not have
|
||||
# offset2 attr
|
||||
return
|
||||
off = self.offset2
|
||||
msg = "Cannot subtract datetime from offset"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
off - self.d
|
||||
|
||||
assert 2 * off - off == off
|
||||
assert self.d - self.offset2 == self.d + self._offset(-2)
|
||||
assert self.d - self.offset2 == self.d - (2 * off - off)
|
||||
|
||||
def testMult1(self):
|
||||
if self._offset is None or not hasattr(self, "offset1"):
|
||||
# i.e. skip for TestCommon and YQM subclasses that do not have
|
||||
# offset1 attr
|
||||
return
|
||||
assert self.d + 10 * self.offset1 == self.d + self._offset(10)
|
||||
assert self.d + 5 * self.offset1 == self.d + self._offset(5)
|
||||
|
||||
def testMult2(self):
|
||||
if self._offset is None:
|
||||
return
|
||||
assert self.d + (-5 * self._offset(-10)) == self.d + self._offset(50)
|
||||
assert self.d + (-3 * self._offset(-2)) == self.d + self._offset(6)
|
||||
|
||||
def test_compare_str(self):
|
||||
# GH#23524
|
||||
# comparing to strings that cannot be cast to DateOffsets should
|
||||
# not raise for __eq__ or __ne__
|
||||
if self._offset is None:
|
||||
return
|
||||
off = self._get_offset(self._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,27 @@
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.offsets import MonthOffset
|
||||
|
||||
import pandas.tseries.offsets as offsets
|
||||
|
||||
|
||||
@pytest.fixture(params=[getattr(offsets, o) for o in offsets.__all__])
|
||||
def offset_types(request):
|
||||
"""
|
||||
Fixture for all the datetime offsets available for a time series.
|
||||
"""
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
params=[
|
||||
getattr(offsets, o)
|
||||
for o in offsets.__all__
|
||||
if issubclass(getattr(offsets, o), MonthOffset) and o != "MonthOffset"
|
||||
]
|
||||
)
|
||||
def month_classes(request):
|
||||
"""
|
||||
Fixture for month based datetime offsets available for a time series.
|
||||
"""
|
||||
return request.param
|
||||
@@ -0,0 +1,235 @@
|
||||
"""
|
||||
Tests for offsets.BDay
|
||||
"""
|
||||
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 (
|
||||
Base,
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
from pandas.tests.tseries.offsets.test_offsets import _ApplyCases
|
||||
|
||||
from pandas.tseries import offsets as offsets
|
||||
|
||||
|
||||
class TestBusinessDay(Base):
|
||||
_offset = BDay
|
||||
|
||||
def setup_method(self, method):
|
||||
self.d = datetime(2008, 1, 1)
|
||||
self.nd = np.datetime64("2008-01-01 00:00:00")
|
||||
|
||||
self.offset = self._offset()
|
||||
self.offset1 = self.offset
|
||||
self.offset2 = self._offset(2)
|
||||
|
||||
def test_different_normalize_equals(self):
|
||||
# GH#21404 changed __eq__ to return False when `normalize` does not match
|
||||
offset = self._offset()
|
||||
offset2 = self._offset(normalize=True)
|
||||
assert offset != offset2
|
||||
|
||||
def test_repr(self):
|
||||
assert repr(self.offset) == "<BusinessDay>"
|
||||
assert repr(self.offset2) == "<2 * BusinessDays>"
|
||||
|
||||
expected = "<BusinessDay: offset=datetime.timedelta(days=1)>"
|
||||
assert repr(self.offset + timedelta(1)) == expected
|
||||
|
||||
def test_with_offset(self):
|
||||
offset = self.offset + timedelta(hours=2)
|
||||
|
||||
assert (self.d + 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):
|
||||
|
||||
dti = DatetimeIndex([self.d])
|
||||
expected = DatetimeIndex([datetime(2008, 1, 2, 2)])
|
||||
|
||||
result = dti + (td + self.offset)
|
||||
tm.assert_index_equal(result, expected)
|
||||
|
||||
result = dti + (self.offset + td)
|
||||
tm.assert_index_equal(result, expected)
|
||||
|
||||
def test_eq(self):
|
||||
assert self.offset2 == self.offset2
|
||||
|
||||
def test_mul(self):
|
||||
pass
|
||||
|
||||
def test_hash(self):
|
||||
assert hash(self.offset2) == hash(self.offset2)
|
||||
|
||||
def test_call(self):
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
# GH#34171 DateOffset.__call__ is deprecated
|
||||
assert self.offset2(self.d) == datetime(2008, 1, 3)
|
||||
assert self.offset2(self.nd) == datetime(2008, 1, 3)
|
||||
|
||||
def testRollback1(self):
|
||||
assert self._offset(10).rollback(self.d) == self.d
|
||||
|
||||
def testRollback2(self):
|
||||
assert self._offset(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4)
|
||||
|
||||
def testRollforward1(self):
|
||||
assert self._offset(10).rollforward(self.d) == self.d
|
||||
|
||||
def testRollforward2(self):
|
||||
assert self._offset(10).rollforward(datetime(2008, 1, 5)) == datetime(
|
||||
2008, 1, 7
|
||||
)
|
||||
|
||||
def test_roll_date_object(self):
|
||||
offset = 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)
|
||||
|
||||
def test_is_on_offset(self):
|
||||
tests = [
|
||||
(self._offset(), datetime(2008, 1, 1), True),
|
||||
(self._offset(), datetime(2008, 1, 5), False),
|
||||
]
|
||||
|
||||
for offset, d, expected in tests:
|
||||
assert_is_on_offset(offset, d, expected)
|
||||
|
||||
apply_cases: _ApplyCases = [
|
||||
(
|
||||
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):
|
||||
n, cases = case
|
||||
offset = self._offset(n)
|
||||
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 + self._offset(10)
|
||||
assert result == datetime(2012, 11, 6)
|
||||
|
||||
result = dt + self._offset(100) - self._offset(100)
|
||||
assert result == dt
|
||||
|
||||
off = self._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 = self._offset() * 10
|
||||
rs = datetime(2014, 1, 5) + off # see #5890
|
||||
xp = datetime(2014, 1, 17)
|
||||
assert rs == xp
|
||||
|
||||
def test_apply_corner(self):
|
||||
if self._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):
|
||||
self._offset()._apply(BMonthEnd())
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,220 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- BMonthBegin
|
||||
- BMonthEnd
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
import pandas as pd
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
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="T")
|
||||
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(Base):
|
||||
_offset = BMonthBegin
|
||||
|
||||
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(Base):
|
||||
_offset = BMonthEnd
|
||||
|
||||
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,311 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- BQuarterBegin
|
||||
- BQuarterEnd
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
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(Base):
|
||||
_offset = BQuarterBegin
|
||||
|
||||
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):
|
||||
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(Base):
|
||||
_offset = BQuarterEnd
|
||||
|
||||
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):
|
||||
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,220 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- BYearBegin
|
||||
- BYearEnd
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
BYearBegin,
|
||||
BYearEnd,
|
||||
)
|
||||
|
||||
|
||||
class TestBYearBegin(Base):
|
||||
_offset = BYearBegin
|
||||
|
||||
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(Base):
|
||||
_offset = BYearEnd
|
||||
|
||||
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(Base):
|
||||
_offset = BYearEnd
|
||||
|
||||
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,91 @@
|
||||
"""
|
||||
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.tests.tseries.offsets.test_business_day import TestBusinessDay
|
||||
|
||||
from pandas.tseries.holiday import USFederalHolidayCalendar
|
||||
|
||||
|
||||
class TestCustomBusinessDay(TestBusinessDay):
|
||||
_offset = CDay
|
||||
|
||||
def test_repr(self):
|
||||
assert repr(self.offset) == "<CustomBusinessDay>"
|
||||
assert repr(self.offset2) == "<2 * CustomBusinessDays>"
|
||||
|
||||
expected = "<BusinessDay: offset=datetime.timedelta(days=1)>"
|
||||
assert repr(self.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):
|
||||
def _check_roundtrip(obj):
|
||||
unpickled = tm.round_trip_pickle(obj)
|
||||
assert unpickled == obj
|
||||
|
||||
_check_roundtrip(self.offset)
|
||||
_check_roundtrip(self.offset2)
|
||||
_check_roundtrip(self.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,328 @@
|
||||
"""
|
||||
Tests for offsets.CustomBusinessHour
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import Timestamp
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
BusinessHour,
|
||||
CustomBusinessHour,
|
||||
Nano,
|
||||
)
|
||||
|
||||
import pandas._testing as tm
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.holiday import USFederalHolidayCalendar
|
||||
|
||||
|
||||
class TestCustomBusinessHour(Base):
|
||||
_offset = CustomBusinessHour
|
||||
holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")]
|
||||
|
||||
def setup_method(self, method):
|
||||
# 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
|
||||
self.d = datetime(2014, 7, 1, 10, 00)
|
||||
self.offset1 = CustomBusinessHour(weekmask="Tue Wed Thu Fri")
|
||||
|
||||
self.offset2 = CustomBusinessHour(holidays=self.holidays)
|
||||
|
||||
def test_constructor_errors(self):
|
||||
from datetime import time as dt_time
|
||||
|
||||
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):
|
||||
# GH#21404 changed __eq__ to return False when `normalize` does not match
|
||||
offset = self._offset()
|
||||
offset2 = self._offset(normalize=True)
|
||||
assert offset != offset2
|
||||
|
||||
def test_repr(self):
|
||||
assert repr(self.offset1) == "<CustomBusinessHour: CBH=09:00-17:00>"
|
||||
assert repr(self.offset2) == "<CustomBusinessHour: CBH=09:00-17:00>"
|
||||
|
||||
def test_with_offset(self):
|
||||
expected = Timestamp("2014-07-01 13:00")
|
||||
|
||||
assert self.d + CustomBusinessHour() * 3 == expected
|
||||
assert self.d + CustomBusinessHour(n=3) == expected
|
||||
|
||||
def test_eq(self):
|
||||
for offset in [self.offset1, self.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_sub(self):
|
||||
# override the Base.test_sub implementation because self.offset2 is
|
||||
# defined differently in this class than the test expects
|
||||
pass
|
||||
|
||||
def test_hash(self):
|
||||
assert hash(self.offset1) == hash(self.offset1)
|
||||
assert hash(self.offset2) == hash(self.offset2)
|
||||
|
||||
def test_call(self):
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
# GH#34171 DateOffset.__call__ is deprecated
|
||||
assert self.offset1(self.d) == datetime(2014, 7, 1, 11)
|
||||
assert self.offset2(self.d) == datetime(2014, 7, 1, 11)
|
||||
|
||||
def testRollback1(self):
|
||||
assert self.offset1.rollback(self.d) == self.d
|
||||
assert self.offset2.rollback(self.d) == self.d
|
||||
|
||||
d = datetime(2014, 7, 1, 0)
|
||||
|
||||
# 2014/07/01 is Tuesday, 06/30 is Monday(holiday)
|
||||
assert self.offset1.rollback(d) == datetime(2014, 6, 27, 17)
|
||||
|
||||
# 2014/6/30 and 2014/6/27 are holidays
|
||||
assert self.offset2.rollback(d) == datetime(2014, 6, 26, 17)
|
||||
|
||||
def testRollback2(self):
|
||||
assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime(
|
||||
2014, 7, 4, 17, 0
|
||||
)
|
||||
|
||||
def testRollforward1(self):
|
||||
assert self.offset1.rollforward(self.d) == self.d
|
||||
assert self.offset2.rollforward(self.d) == self.d
|
||||
|
||||
d = datetime(2014, 7, 1, 0)
|
||||
assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9)
|
||||
assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9)
|
||||
|
||||
def testRollforward2(self):
|
||||
assert self._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
|
||||
|
||||
def test_is_on_offset(self):
|
||||
tests = [
|
||||
(
|
||||
CustomBusinessHour(start="10:00", end="15:00", holidays=self.holidays),
|
||||
{
|
||||
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,
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
for offset, cases in tests:
|
||||
for dt, expected in cases.items():
|
||||
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,444 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- CustomBusinessMonthBase
|
||||
- CustomBusinessMonthBegin
|
||||
- CustomBusinessMonthEnd
|
||||
"""
|
||||
from datetime import (
|
||||
date,
|
||||
datetime,
|
||||
timedelta,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
CBMonthBegin,
|
||||
CBMonthEnd,
|
||||
CDay,
|
||||
)
|
||||
|
||||
from pandas import (
|
||||
_testing as tm,
|
||||
date_range,
|
||||
)
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
from pandas.tests.tseries.offsets.test_offsets import _ApplyCases
|
||||
|
||||
from pandas.tseries import offsets as offsets
|
||||
from pandas.tseries.holiday import USFederalHolidayCalendar
|
||||
|
||||
|
||||
class CustomBusinessMonthBase:
|
||||
def setup_method(self, method):
|
||||
self.d = datetime(2008, 1, 1)
|
||||
self.offset = self._offset()
|
||||
self.offset1 = self.offset
|
||||
self.offset2 = self._offset(2)
|
||||
|
||||
def test_eq(self):
|
||||
assert self.offset2 == self.offset2
|
||||
|
||||
def test_mul(self):
|
||||
pass
|
||||
|
||||
def test_hash(self):
|
||||
assert hash(self.offset2) == hash(self.offset2)
|
||||
|
||||
def test_roundtrip_pickle(self):
|
||||
def _check_roundtrip(obj):
|
||||
unpickled = tm.round_trip_pickle(obj)
|
||||
assert unpickled == obj
|
||||
|
||||
_check_roundtrip(self._offset())
|
||||
_check_roundtrip(self._offset(2))
|
||||
_check_roundtrip(self._offset() * 2)
|
||||
|
||||
def test_copy(self):
|
||||
# GH 17452
|
||||
off = self._offset(weekmask="Mon Wed Fri")
|
||||
assert off == off.copy()
|
||||
|
||||
|
||||
class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base):
|
||||
_offset = CBMonthBegin
|
||||
|
||||
def test_different_normalize_equals(self):
|
||||
# GH#21404 changed __eq__ to return False when `normalize` does not match
|
||||
offset = self._offset()
|
||||
offset2 = self._offset(normalize=True)
|
||||
assert offset != offset2
|
||||
|
||||
def test_repr(self):
|
||||
assert repr(self.offset) == "<CustomBusinessMonthBegin>"
|
||||
assert repr(self.offset2) == "<2 * CustomBusinessMonthBegins>"
|
||||
|
||||
def test_call(self):
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
# GH#34171 DateOffset.__call__ is deprecated
|
||||
assert self.offset2(self.d) == datetime(2008, 3, 3)
|
||||
|
||||
def testRollback1(self):
|
||||
assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31)
|
||||
|
||||
def testRollback2(self):
|
||||
assert CBMonthBegin(10).rollback(self.d) == datetime(2008, 1, 1)
|
||||
|
||||
def testRollforward1(self):
|
||||
assert CBMonthBegin(10).rollforward(self.d) == 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: _ApplyCases = [
|
||||
(
|
||||
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.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning")
|
||||
def test_datetimeindex(self):
|
||||
hcal = USFederalHolidayCalendar()
|
||||
cbmb = CBMonthBegin(calendar=hcal)
|
||||
assert date_range(start="20120101", end="20130101", freq=cbmb).tolist()[
|
||||
0
|
||||
] == datetime(2012, 1, 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(CustomBusinessMonthBase, Base):
|
||||
_offset = CBMonthEnd
|
||||
|
||||
def test_different_normalize_equals(self):
|
||||
# GH#21404 changed __eq__ to return False when `normalize` does not match
|
||||
offset = self._offset()
|
||||
offset2 = self._offset(normalize=True)
|
||||
assert offset != offset2
|
||||
|
||||
def test_repr(self):
|
||||
assert repr(self.offset) == "<CustomBusinessMonthEnd>"
|
||||
assert repr(self.offset2) == "<2 * CustomBusinessMonthEnds>"
|
||||
|
||||
def test_call(self):
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
# GH#34171 DateOffset.__call__ is deprecated
|
||||
assert self.offset2(self.d) == datetime(2008, 2, 29)
|
||||
|
||||
def testRollback1(self):
|
||||
assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31)
|
||||
|
||||
def testRollback2(self):
|
||||
assert CBMonthEnd(10).rollback(self.d) == datetime(2007, 12, 31)
|
||||
|
||||
def testRollforward1(self):
|
||||
assert CBMonthEnd(10).rollforward(self.d) == 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, d, expected = case
|
||||
assert_is_on_offset(offset, d, expected)
|
||||
|
||||
apply_cases: _ApplyCases = [
|
||||
(
|
||||
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.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning")
|
||||
def test_datetimeindex(self):
|
||||
from pandas.tseries.holiday import USFederalHolidayCalendar
|
||||
|
||||
hcal = USFederalHolidayCalendar()
|
||||
freq = CBMonthEnd(calendar=hcal)
|
||||
|
||||
assert date_range(start="20120101", end="20130101", freq=freq).tolist()[
|
||||
0
|
||||
] == datetime(2012, 1, 31)
|
||||
|
||||
@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,227 @@
|
||||
"""
|
||||
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.tests.tseries.offsets.test_offsets import get_utc_offset_hours
|
||||
|
||||
|
||||
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})
|
||||
|
||||
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/Kinshasa",
|
||||
marks=pytest.mark.xfail(
|
||||
# error: Module has no attribute "__version__"
|
||||
float(pytz.__version__) <= 2020.1, # type: ignore[attr-defined]
|
||||
reason="GH#41906",
|
||||
),
|
||||
),
|
||||
(
|
||||
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,36 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- Easter
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import Easter
|
||||
|
||||
|
||||
class TestEaster(Base):
|
||||
@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,698 @@
|
||||
"""
|
||||
Tests for Fiscal Year and Fiscal Quarter offset classes
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.period import INVALID_FREQ_ERR_MSG
|
||||
|
||||
from pandas import Timestamp
|
||||
import pandas._testing as tm
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
WeekDay,
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.frequencies import get_offset
|
||||
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"
|
||||
)
|
||||
|
||||
|
||||
def test_get_offset():
|
||||
with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG):
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
get_offset("gibberish")
|
||||
with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG):
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
get_offset("QS-JAN-B")
|
||||
|
||||
pairs = [
|
||||
("RE-N-DEC-MON", makeFY5253NearestEndMonth(weekday=0, startingMonth=12)),
|
||||
("RE-L-DEC-TUE", makeFY5253LastOfMonth(weekday=1, startingMonth=12)),
|
||||
(
|
||||
"REQ-L-MAR-TUE-4",
|
||||
makeFY5253LastOfMonthQuarter(
|
||||
weekday=1, startingMonth=3, qtr_with_extra_week=4
|
||||
),
|
||||
),
|
||||
(
|
||||
"REQ-L-DEC-MON-3",
|
||||
makeFY5253LastOfMonthQuarter(
|
||||
weekday=0, startingMonth=12, qtr_with_extra_week=3
|
||||
),
|
||||
),
|
||||
(
|
||||
"REQ-N-DEC-MON-3",
|
||||
makeFY5253NearestEndMonthQuarter(
|
||||
weekday=0, startingMonth=12, qtr_with_extra_week=3
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
for name, expected in pairs:
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
offset = get_offset(name)
|
||||
assert offset == expected, (
|
||||
f"Expected {repr(name)} to yield {repr(expected)} "
|
||||
f"(actual: {repr(offset)})"
|
||||
)
|
||||
|
||||
|
||||
class TestFY5253LastOfMonth(Base):
|
||||
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(Base):
|
||||
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(Base):
|
||||
def test_is_anchored(self):
|
||||
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(Base):
|
||||
|
||||
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="T")
|
||||
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,692 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- SemiMonthBegin
|
||||
- SemiMonthEnd
|
||||
- MonthBegin
|
||||
- MonthEnd
|
||||
"""
|
||||
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,
|
||||
date_range,
|
||||
)
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
|
||||
class TestSemiMonthEnd(Base):
|
||||
_offset = SemiMonthEnd
|
||||
offset1 = _offset()
|
||||
offset2 = _offset(2)
|
||||
|
||||
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)
|
||||
|
||||
# ensure generating a range with DatetimeIndex gives same result
|
||||
result = date_range(start=dates[0], end=dates[-1], freq="SM")
|
||||
exp = DatetimeIndex(dates, freq="SM")
|
||||
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)
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
result = offset.apply_index(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(Base):
|
||||
_offset = SemiMonthBegin
|
||||
offset1 = _offset()
|
||||
offset2 = _offset(2)
|
||||
|
||||
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)
|
||||
|
||||
# ensure generating a range with DatetimeIndex gives same result
|
||||
result = date_range(start=dates[0], end=dates[-1], freq="SMS")
|
||||
exp = DatetimeIndex(dates, freq="SMS")
|
||||
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(Base):
|
||||
_offset = MonthBegin
|
||||
|
||||
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(Base):
|
||||
_offset = MonthEnd
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,866 @@
|
||||
"""
|
||||
Tests of pandas.tseries.offsets
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
)
|
||||
from typing import (
|
||||
Dict,
|
||||
List,
|
||||
Tuple,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
NaT,
|
||||
Timestamp,
|
||||
conversion,
|
||||
timezones,
|
||||
)
|
||||
import pandas._libs.tslibs.offsets as liboffsets
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
_get_offset,
|
||||
_offset_map,
|
||||
)
|
||||
from pandas._libs.tslibs.period import INVALID_FREQ_ERR_MSG
|
||||
from pandas.errors import PerformanceWarning
|
||||
|
||||
from pandas import DatetimeIndex
|
||||
import pandas._testing as tm
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
WeekDay,
|
||||
)
|
||||
|
||||
import pandas.tseries.offsets as offsets
|
||||
from pandas.tseries.offsets import (
|
||||
FY5253,
|
||||
BaseOffset,
|
||||
BDay,
|
||||
BMonthEnd,
|
||||
BusinessHour,
|
||||
CustomBusinessDay,
|
||||
CustomBusinessHour,
|
||||
CustomBusinessMonthBegin,
|
||||
CustomBusinessMonthEnd,
|
||||
DateOffset,
|
||||
Easter,
|
||||
FY5253Quarter,
|
||||
LastWeekOfMonth,
|
||||
MonthBegin,
|
||||
Nano,
|
||||
Tick,
|
||||
Week,
|
||||
WeekOfMonth,
|
||||
)
|
||||
|
||||
_ApplyCases = List[Tuple[BaseOffset, Dict[datetime, datetime]]]
|
||||
|
||||
|
||||
class TestCommon(Base):
|
||||
# executed value created by Base._get_offset
|
||||
# are applied to 2011/01/01 09:00 (Saturday)
|
||||
# used for .apply and .rollforward
|
||||
expecteds = {
|
||||
"Day": Timestamp("2011-01-02 09:00:00"),
|
||||
"DateOffset": Timestamp("2011-01-02 09:00:00"),
|
||||
"BusinessDay": Timestamp("2011-01-03 09:00:00"),
|
||||
"CustomBusinessDay": Timestamp("2011-01-03 09:00:00"),
|
||||
"CustomBusinessMonthEnd": Timestamp("2011-01-31 09:00:00"),
|
||||
"CustomBusinessMonthBegin": Timestamp("2011-01-03 09:00:00"),
|
||||
"MonthBegin": Timestamp("2011-02-01 09:00:00"),
|
||||
"BusinessMonthBegin": Timestamp("2011-01-03 09:00:00"),
|
||||
"MonthEnd": Timestamp("2011-01-31 09:00:00"),
|
||||
"SemiMonthEnd": Timestamp("2011-01-15 09:00:00"),
|
||||
"SemiMonthBegin": Timestamp("2011-01-15 09:00:00"),
|
||||
"BusinessMonthEnd": Timestamp("2011-01-31 09:00:00"),
|
||||
"YearBegin": Timestamp("2012-01-01 09:00:00"),
|
||||
"BYearBegin": Timestamp("2011-01-03 09:00:00"),
|
||||
"YearEnd": Timestamp("2011-12-31 09:00:00"),
|
||||
"BYearEnd": Timestamp("2011-12-30 09:00:00"),
|
||||
"QuarterBegin": Timestamp("2011-03-01 09:00:00"),
|
||||
"BQuarterBegin": Timestamp("2011-03-01 09:00:00"),
|
||||
"QuarterEnd": Timestamp("2011-03-31 09:00:00"),
|
||||
"BQuarterEnd": Timestamp("2011-03-31 09:00:00"),
|
||||
"BusinessHour": Timestamp("2011-01-03 10:00:00"),
|
||||
"CustomBusinessHour": Timestamp("2011-01-03 10:00:00"),
|
||||
"WeekOfMonth": Timestamp("2011-01-08 09:00:00"),
|
||||
"LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"),
|
||||
"FY5253Quarter": Timestamp("2011-01-25 09:00:00"),
|
||||
"FY5253": Timestamp("2011-01-25 09:00:00"),
|
||||
"Week": Timestamp("2011-01-08 09:00:00"),
|
||||
"Easter": Timestamp("2011-04-24 09:00:00"),
|
||||
"Hour": Timestamp("2011-01-01 10:00:00"),
|
||||
"Minute": Timestamp("2011-01-01 09:01:00"),
|
||||
"Second": Timestamp("2011-01-01 09:00:01"),
|
||||
"Milli": Timestamp("2011-01-01 09:00:00.001000"),
|
||||
"Micro": Timestamp("2011-01-01 09:00:00.000001"),
|
||||
"Nano": Timestamp("2011-01-01T09:00:00.000000001"),
|
||||
}
|
||||
|
||||
def test_immutable(self, offset_types):
|
||||
# GH#21341 check that __setattr__ raises
|
||||
offset = self._get_offset(offset_types)
|
||||
msg = "objects is not writable|DateOffset objects are immutable"
|
||||
with pytest.raises(AttributeError, match=msg):
|
||||
offset.normalize = True
|
||||
with pytest.raises(AttributeError, match=msg):
|
||||
offset.n = 91
|
||||
|
||||
def test_return_type(self, offset_types):
|
||||
offset = self._get_offset(offset_types)
|
||||
|
||||
# make sure that we are returning a Timestamp
|
||||
result = Timestamp("20080101") + offset
|
||||
assert isinstance(result, Timestamp)
|
||||
|
||||
# make sure that we are returning NaT
|
||||
assert NaT + offset is NaT
|
||||
assert offset + NaT is NaT
|
||||
|
||||
assert NaT - offset is NaT
|
||||
assert (-offset)._apply(NaT) is NaT
|
||||
|
||||
def test_offset_n(self, offset_types):
|
||||
offset = self._get_offset(offset_types)
|
||||
assert offset.n == 1
|
||||
|
||||
neg_offset = offset * -1
|
||||
assert neg_offset.n == -1
|
||||
|
||||
mul_offset = offset * 3
|
||||
assert mul_offset.n == 3
|
||||
|
||||
def test_offset_timedelta64_arg(self, offset_types):
|
||||
# check that offset._validate_n raises TypeError on a timedelt64
|
||||
# object
|
||||
off = self._get_offset(offset_types)
|
||||
|
||||
td64 = np.timedelta64(4567, "s")
|
||||
with pytest.raises(TypeError, match="argument must be an integer"):
|
||||
type(off)(n=td64, **off.kwds)
|
||||
|
||||
def test_offset_mul_ndarray(self, offset_types):
|
||||
off = self._get_offset(offset_types)
|
||||
|
||||
expected = np.array([[off, off * 2], [off * 3, off * 4]])
|
||||
|
||||
result = np.array([[1, 2], [3, 4]]) * off
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
result = off * np.array([[1, 2], [3, 4]])
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
def test_offset_freqstr(self, offset_types):
|
||||
offset = self._get_offset(offset_types)
|
||||
|
||||
freqstr = offset.freqstr
|
||||
if freqstr not in ("<Easter>", "<DateOffset: days=1>", "LWOM-SAT"):
|
||||
code = _get_offset(freqstr)
|
||||
assert offset.rule_code == code
|
||||
|
||||
def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=False):
|
||||
|
||||
if normalize and issubclass(offset, Tick):
|
||||
# normalize=True disallowed for Tick subclasses GH#21427
|
||||
return
|
||||
|
||||
offset_s = self._get_offset(offset, normalize=normalize)
|
||||
func = getattr(offset_s, funcname)
|
||||
|
||||
result = func(dt)
|
||||
assert isinstance(result, Timestamp)
|
||||
assert result == expected
|
||||
|
||||
result = func(Timestamp(dt))
|
||||
assert isinstance(result, Timestamp)
|
||||
assert result == expected
|
||||
|
||||
# see gh-14101
|
||||
exp_warning = None
|
||||
ts = Timestamp(dt) + Nano(5)
|
||||
|
||||
if (
|
||||
type(offset_s).__name__ == "DateOffset"
|
||||
and (funcname in ["apply", "_apply"] or normalize)
|
||||
and ts.nanosecond > 0
|
||||
):
|
||||
exp_warning = UserWarning
|
||||
|
||||
# test nanosecond is preserved
|
||||
with tm.assert_produces_warning(exp_warning):
|
||||
result = func(ts)
|
||||
|
||||
if exp_warning is None and funcname == "_apply":
|
||||
# GH#44522
|
||||
# Check in this particular case to avoid headaches with
|
||||
# testing for multiple warnings produced by the same call.
|
||||
with tm.assert_produces_warning(FutureWarning, match="apply is deprecated"):
|
||||
res2 = offset_s.apply(ts)
|
||||
|
||||
assert type(res2) is type(result)
|
||||
assert res2 == result
|
||||
|
||||
assert isinstance(result, Timestamp)
|
||||
if normalize is False:
|
||||
assert result == expected + Nano(5)
|
||||
else:
|
||||
assert result == expected
|
||||
|
||||
if isinstance(dt, np.datetime64):
|
||||
# test tz when input is datetime or Timestamp
|
||||
return
|
||||
|
||||
for tz in self.timezones:
|
||||
expected_localize = expected.tz_localize(tz)
|
||||
tz_obj = timezones.maybe_get_tz(tz)
|
||||
dt_tz = conversion.localize_pydatetime(dt, tz_obj)
|
||||
|
||||
result = func(dt_tz)
|
||||
assert isinstance(result, Timestamp)
|
||||
assert result == expected_localize
|
||||
|
||||
result = func(Timestamp(dt, tz=tz))
|
||||
assert isinstance(result, Timestamp)
|
||||
assert result == expected_localize
|
||||
|
||||
# see gh-14101
|
||||
exp_warning = None
|
||||
ts = Timestamp(dt, tz=tz) + Nano(5)
|
||||
|
||||
if (
|
||||
type(offset_s).__name__ == "DateOffset"
|
||||
and (funcname in ["apply", "_apply"] or normalize)
|
||||
and ts.nanosecond > 0
|
||||
):
|
||||
exp_warning = UserWarning
|
||||
|
||||
# test nanosecond is preserved
|
||||
with tm.assert_produces_warning(exp_warning):
|
||||
result = func(ts)
|
||||
assert isinstance(result, Timestamp)
|
||||
if normalize is False:
|
||||
assert result == expected_localize + Nano(5)
|
||||
else:
|
||||
assert result == expected_localize
|
||||
|
||||
def test_apply(self, offset_types):
|
||||
sdt = datetime(2011, 1, 1, 9, 0)
|
||||
ndt = np.datetime64("2011-01-01 09:00")
|
||||
|
||||
expected = self.expecteds[offset_types.__name__]
|
||||
expected_norm = Timestamp(expected.date())
|
||||
|
||||
for dt in [sdt, ndt]:
|
||||
self._check_offsetfunc_works(offset_types, "_apply", dt, expected)
|
||||
|
||||
self._check_offsetfunc_works(
|
||||
offset_types, "_apply", dt, expected_norm, normalize=True
|
||||
)
|
||||
|
||||
def test_rollforward(self, offset_types):
|
||||
expecteds = self.expecteds.copy()
|
||||
|
||||
# result will not be changed if the target is on the offset
|
||||
no_changes = [
|
||||
"Day",
|
||||
"MonthBegin",
|
||||
"SemiMonthBegin",
|
||||
"YearBegin",
|
||||
"Week",
|
||||
"Hour",
|
||||
"Minute",
|
||||
"Second",
|
||||
"Milli",
|
||||
"Micro",
|
||||
"Nano",
|
||||
"DateOffset",
|
||||
]
|
||||
for n in no_changes:
|
||||
expecteds[n] = Timestamp("2011/01/01 09:00")
|
||||
|
||||
expecteds["BusinessHour"] = Timestamp("2011-01-03 09:00:00")
|
||||
expecteds["CustomBusinessHour"] = Timestamp("2011-01-03 09:00:00")
|
||||
|
||||
# but be changed when normalize=True
|
||||
norm_expected = expecteds.copy()
|
||||
for k in norm_expected:
|
||||
norm_expected[k] = Timestamp(norm_expected[k].date())
|
||||
|
||||
normalized = {
|
||||
"Day": Timestamp("2011-01-02 00:00:00"),
|
||||
"DateOffset": Timestamp("2011-01-02 00:00:00"),
|
||||
"MonthBegin": Timestamp("2011-02-01 00:00:00"),
|
||||
"SemiMonthBegin": Timestamp("2011-01-15 00:00:00"),
|
||||
"YearBegin": Timestamp("2012-01-01 00:00:00"),
|
||||
"Week": Timestamp("2011-01-08 00:00:00"),
|
||||
"Hour": Timestamp("2011-01-01 00:00:00"),
|
||||
"Minute": Timestamp("2011-01-01 00:00:00"),
|
||||
"Second": Timestamp("2011-01-01 00:00:00"),
|
||||
"Milli": Timestamp("2011-01-01 00:00:00"),
|
||||
"Micro": Timestamp("2011-01-01 00:00:00"),
|
||||
}
|
||||
norm_expected.update(normalized)
|
||||
|
||||
sdt = datetime(2011, 1, 1, 9, 0)
|
||||
ndt = np.datetime64("2011-01-01 09:00")
|
||||
|
||||
for dt in [sdt, ndt]:
|
||||
expected = expecteds[offset_types.__name__]
|
||||
self._check_offsetfunc_works(offset_types, "rollforward", dt, expected)
|
||||
expected = norm_expected[offset_types.__name__]
|
||||
self._check_offsetfunc_works(
|
||||
offset_types, "rollforward", dt, expected, normalize=True
|
||||
)
|
||||
|
||||
def test_rollback(self, offset_types):
|
||||
expecteds = {
|
||||
"BusinessDay": Timestamp("2010-12-31 09:00:00"),
|
||||
"CustomBusinessDay": Timestamp("2010-12-31 09:00:00"),
|
||||
"CustomBusinessMonthEnd": Timestamp("2010-12-31 09:00:00"),
|
||||
"CustomBusinessMonthBegin": Timestamp("2010-12-01 09:00:00"),
|
||||
"BusinessMonthBegin": Timestamp("2010-12-01 09:00:00"),
|
||||
"MonthEnd": Timestamp("2010-12-31 09:00:00"),
|
||||
"SemiMonthEnd": Timestamp("2010-12-31 09:00:00"),
|
||||
"BusinessMonthEnd": Timestamp("2010-12-31 09:00:00"),
|
||||
"BYearBegin": Timestamp("2010-01-01 09:00:00"),
|
||||
"YearEnd": Timestamp("2010-12-31 09:00:00"),
|
||||
"BYearEnd": Timestamp("2010-12-31 09:00:00"),
|
||||
"QuarterBegin": Timestamp("2010-12-01 09:00:00"),
|
||||
"BQuarterBegin": Timestamp("2010-12-01 09:00:00"),
|
||||
"QuarterEnd": Timestamp("2010-12-31 09:00:00"),
|
||||
"BQuarterEnd": Timestamp("2010-12-31 09:00:00"),
|
||||
"BusinessHour": Timestamp("2010-12-31 17:00:00"),
|
||||
"CustomBusinessHour": Timestamp("2010-12-31 17:00:00"),
|
||||
"WeekOfMonth": Timestamp("2010-12-11 09:00:00"),
|
||||
"LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"),
|
||||
"FY5253Quarter": Timestamp("2010-10-26 09:00:00"),
|
||||
"FY5253": Timestamp("2010-01-26 09:00:00"),
|
||||
"Easter": Timestamp("2010-04-04 09:00:00"),
|
||||
}
|
||||
|
||||
# result will not be changed if the target is on the offset
|
||||
for n in [
|
||||
"Day",
|
||||
"MonthBegin",
|
||||
"SemiMonthBegin",
|
||||
"YearBegin",
|
||||
"Week",
|
||||
"Hour",
|
||||
"Minute",
|
||||
"Second",
|
||||
"Milli",
|
||||
"Micro",
|
||||
"Nano",
|
||||
"DateOffset",
|
||||
]:
|
||||
expecteds[n] = Timestamp("2011/01/01 09:00")
|
||||
|
||||
# but be changed when normalize=True
|
||||
norm_expected = expecteds.copy()
|
||||
for k in norm_expected:
|
||||
norm_expected[k] = Timestamp(norm_expected[k].date())
|
||||
|
||||
normalized = {
|
||||
"Day": Timestamp("2010-12-31 00:00:00"),
|
||||
"DateOffset": Timestamp("2010-12-31 00:00:00"),
|
||||
"MonthBegin": Timestamp("2010-12-01 00:00:00"),
|
||||
"SemiMonthBegin": Timestamp("2010-12-15 00:00:00"),
|
||||
"YearBegin": Timestamp("2010-01-01 00:00:00"),
|
||||
"Week": Timestamp("2010-12-25 00:00:00"),
|
||||
"Hour": Timestamp("2011-01-01 00:00:00"),
|
||||
"Minute": Timestamp("2011-01-01 00:00:00"),
|
||||
"Second": Timestamp("2011-01-01 00:00:00"),
|
||||
"Milli": Timestamp("2011-01-01 00:00:00"),
|
||||
"Micro": Timestamp("2011-01-01 00:00:00"),
|
||||
}
|
||||
norm_expected.update(normalized)
|
||||
|
||||
sdt = datetime(2011, 1, 1, 9, 0)
|
||||
ndt = np.datetime64("2011-01-01 09:00")
|
||||
|
||||
for dt in [sdt, ndt]:
|
||||
expected = expecteds[offset_types.__name__]
|
||||
self._check_offsetfunc_works(offset_types, "rollback", dt, expected)
|
||||
|
||||
expected = norm_expected[offset_types.__name__]
|
||||
self._check_offsetfunc_works(
|
||||
offset_types, "rollback", dt, expected, normalize=True
|
||||
)
|
||||
|
||||
def test_is_on_offset(self, offset_types):
|
||||
dt = self.expecteds[offset_types.__name__]
|
||||
offset_s = self._get_offset(offset_types)
|
||||
assert offset_s.is_on_offset(dt)
|
||||
|
||||
# when normalize=True, is_on_offset checks time is 00:00:00
|
||||
if issubclass(offset_types, Tick):
|
||||
# normalize=True disallowed for Tick subclasses GH#21427
|
||||
return
|
||||
offset_n = self._get_offset(offset_types, normalize=True)
|
||||
assert not offset_n.is_on_offset(dt)
|
||||
|
||||
if offset_types in (BusinessHour, CustomBusinessHour):
|
||||
# In default BusinessHour (9:00-17:00), normalized time
|
||||
# cannot be in business hour range
|
||||
return
|
||||
date = datetime(dt.year, dt.month, dt.day)
|
||||
assert offset_n.is_on_offset(date)
|
||||
|
||||
def test_add(self, offset_types, tz_naive_fixture):
|
||||
tz = tz_naive_fixture
|
||||
dt = datetime(2011, 1, 1, 9, 0)
|
||||
|
||||
offset_s = self._get_offset(offset_types)
|
||||
expected = self.expecteds[offset_types.__name__]
|
||||
|
||||
result_dt = dt + offset_s
|
||||
result_ts = Timestamp(dt) + offset_s
|
||||
for result in [result_dt, result_ts]:
|
||||
assert isinstance(result, Timestamp)
|
||||
assert result == expected
|
||||
|
||||
expected_localize = expected.tz_localize(tz)
|
||||
result = Timestamp(dt, tz=tz) + offset_s
|
||||
assert isinstance(result, Timestamp)
|
||||
assert result == expected_localize
|
||||
|
||||
# normalize=True, disallowed for Tick subclasses GH#21427
|
||||
if issubclass(offset_types, Tick):
|
||||
return
|
||||
offset_s = self._get_offset(offset_types, normalize=True)
|
||||
expected = Timestamp(expected.date())
|
||||
|
||||
result_dt = dt + offset_s
|
||||
result_ts = Timestamp(dt) + offset_s
|
||||
for result in [result_dt, result_ts]:
|
||||
assert isinstance(result, Timestamp)
|
||||
assert result == expected
|
||||
|
||||
expected_localize = expected.tz_localize(tz)
|
||||
result = Timestamp(dt, tz=tz) + offset_s
|
||||
assert isinstance(result, Timestamp)
|
||||
assert result == expected_localize
|
||||
|
||||
def test_add_empty_datetimeindex(self, offset_types, tz_naive_fixture):
|
||||
# GH#12724, GH#30336
|
||||
offset_s = self._get_offset(offset_types)
|
||||
|
||||
dti = DatetimeIndex([], tz=tz_naive_fixture)
|
||||
|
||||
warn = None
|
||||
if isinstance(
|
||||
offset_s,
|
||||
(
|
||||
Easter,
|
||||
WeekOfMonth,
|
||||
LastWeekOfMonth,
|
||||
CustomBusinessDay,
|
||||
BusinessHour,
|
||||
CustomBusinessHour,
|
||||
CustomBusinessMonthBegin,
|
||||
CustomBusinessMonthEnd,
|
||||
FY5253,
|
||||
FY5253Quarter,
|
||||
),
|
||||
):
|
||||
# We don't have an optimized apply_index
|
||||
warn = PerformanceWarning
|
||||
|
||||
with tm.assert_produces_warning(warn):
|
||||
result = dti + offset_s
|
||||
tm.assert_index_equal(result, dti)
|
||||
with tm.assert_produces_warning(warn):
|
||||
result = offset_s + dti
|
||||
tm.assert_index_equal(result, dti)
|
||||
|
||||
dta = dti._data
|
||||
with tm.assert_produces_warning(warn):
|
||||
result = dta + offset_s
|
||||
tm.assert_equal(result, dta)
|
||||
with tm.assert_produces_warning(warn):
|
||||
result = offset_s + dta
|
||||
tm.assert_equal(result, dta)
|
||||
|
||||
def test_pickle_roundtrip(self, offset_types):
|
||||
off = self._get_offset(offset_types)
|
||||
res = tm.round_trip_pickle(off)
|
||||
assert off == res
|
||||
if type(off) is not DateOffset:
|
||||
for attr in off._attributes:
|
||||
if attr == "calendar":
|
||||
# np.busdaycalendar __eq__ will return False;
|
||||
# we check holidays and weekmask attrs so are OK
|
||||
continue
|
||||
# Make sure nothings got lost from _params (which __eq__) is based on
|
||||
assert getattr(off, attr) == getattr(res, attr)
|
||||
|
||||
def test_pickle_dateoffset_odd_inputs(self):
|
||||
# GH#34511
|
||||
off = DateOffset(months=12)
|
||||
res = tm.round_trip_pickle(off)
|
||||
assert off == res
|
||||
|
||||
base_dt = datetime(2020, 1, 1)
|
||||
assert base_dt + off == base_dt + res
|
||||
|
||||
def test_onOffset_deprecated(self, offset_types, fixed_now_ts):
|
||||
# GH#30340 use idiomatic naming
|
||||
off = self._get_offset(offset_types)
|
||||
|
||||
ts = fixed_now_ts
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
result = off.onOffset(ts)
|
||||
|
||||
expected = off.is_on_offset(ts)
|
||||
assert result == expected
|
||||
|
||||
def test_isAnchored_deprecated(self, offset_types):
|
||||
# GH#30340 use idiomatic naming
|
||||
off = self._get_offset(offset_types)
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
result = off.isAnchored()
|
||||
|
||||
expected = off.is_anchored()
|
||||
assert result == expected
|
||||
|
||||
def test_offsets_hashable(self, offset_types):
|
||||
# GH: 37267
|
||||
off = self._get_offset(offset_types)
|
||||
assert hash(off) is not None
|
||||
|
||||
|
||||
class TestDateOffset(Base):
|
||||
def setup_method(self, method):
|
||||
self.d = Timestamp(datetime(2008, 1, 2))
|
||||
_offset_map.clear()
|
||||
|
||||
def test_repr(self):
|
||||
repr(DateOffset())
|
||||
repr(DateOffset(2))
|
||||
repr(2 * DateOffset())
|
||||
repr(2 * DateOffset(months=2))
|
||||
|
||||
def test_mul(self):
|
||||
assert DateOffset(2) == 2 * DateOffset(1)
|
||||
assert DateOffset(2) == DateOffset(1) * 2
|
||||
|
||||
def test_constructor(self):
|
||||
|
||||
assert (self.d + DateOffset(months=2)) == datetime(2008, 3, 2)
|
||||
assert (self.d - DateOffset(months=2)) == datetime(2007, 11, 2)
|
||||
|
||||
assert (self.d + DateOffset(2)) == datetime(2008, 1, 4)
|
||||
|
||||
assert not DateOffset(2).is_anchored()
|
||||
assert DateOffset(1).is_anchored()
|
||||
|
||||
d = datetime(2008, 1, 31)
|
||||
assert (d + DateOffset(months=1)) == datetime(2008, 2, 29)
|
||||
|
||||
def test_copy(self):
|
||||
assert DateOffset(months=2).copy() == DateOffset(months=2)
|
||||
|
||||
def test_eq(self):
|
||||
offset1 = DateOffset(days=1)
|
||||
offset2 = DateOffset(days=365)
|
||||
|
||||
assert offset1 != offset2
|
||||
|
||||
|
||||
class TestOffsetNames:
|
||||
def test_get_offset_name(self):
|
||||
assert BDay().freqstr == "B"
|
||||
assert BDay(2).freqstr == "2B"
|
||||
assert BMonthEnd().freqstr == "BM"
|
||||
assert Week(weekday=0).freqstr == "W-MON"
|
||||
assert Week(weekday=1).freqstr == "W-TUE"
|
||||
assert Week(weekday=2).freqstr == "W-WED"
|
||||
assert Week(weekday=3).freqstr == "W-THU"
|
||||
assert Week(weekday=4).freqstr == "W-FRI"
|
||||
|
||||
assert LastWeekOfMonth(weekday=WeekDay.SUN).freqstr == "LWOM-SUN"
|
||||
|
||||
|
||||
def test_get_offset():
|
||||
with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG):
|
||||
_get_offset("gibberish")
|
||||
with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG):
|
||||
_get_offset("QS-JAN-B")
|
||||
|
||||
pairs = [
|
||||
("B", BDay()),
|
||||
("b", BDay()),
|
||||
("bm", BMonthEnd()),
|
||||
("Bm", BMonthEnd()),
|
||||
("W-MON", Week(weekday=0)),
|
||||
("W-TUE", Week(weekday=1)),
|
||||
("W-WED", Week(weekday=2)),
|
||||
("W-THU", Week(weekday=3)),
|
||||
("W-FRI", Week(weekday=4)),
|
||||
]
|
||||
|
||||
for name, expected in pairs:
|
||||
offset = _get_offset(name)
|
||||
assert offset == expected, (
|
||||
f"Expected {repr(name)} to yield {repr(expected)} "
|
||||
f"(actual: {repr(offset)})"
|
||||
)
|
||||
|
||||
|
||||
def test_get_offset_legacy():
|
||||
pairs = [("w@Sat", Week(weekday=5))]
|
||||
for name, expected in pairs:
|
||||
with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG):
|
||||
_get_offset(name)
|
||||
|
||||
|
||||
class TestOffsetAliases:
|
||||
def setup_method(self, method):
|
||||
_offset_map.clear()
|
||||
|
||||
def test_alias_equality(self):
|
||||
for k, v in _offset_map.items():
|
||||
if v is None:
|
||||
continue
|
||||
assert k == v.copy()
|
||||
|
||||
def test_rule_code(self):
|
||||
lst = ["M", "MS", "BM", "BMS", "D", "B", "H", "T", "S", "L", "U"]
|
||||
for k in lst:
|
||||
assert k == _get_offset(k).rule_code
|
||||
# should be cached - this is kind of an internals test...
|
||||
assert k in _offset_map
|
||||
assert k == (_get_offset(k) * 3).rule_code
|
||||
|
||||
suffix_lst = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]
|
||||
base = "W"
|
||||
for v in suffix_lst:
|
||||
alias = "-".join([base, v])
|
||||
assert alias == _get_offset(alias).rule_code
|
||||
assert alias == (_get_offset(alias) * 5).rule_code
|
||||
|
||||
suffix_lst = [
|
||||
"JAN",
|
||||
"FEB",
|
||||
"MAR",
|
||||
"APR",
|
||||
"MAY",
|
||||
"JUN",
|
||||
"JUL",
|
||||
"AUG",
|
||||
"SEP",
|
||||
"OCT",
|
||||
"NOV",
|
||||
"DEC",
|
||||
]
|
||||
base_lst = ["A", "AS", "BA", "BAS", "Q", "QS", "BQ", "BQS"]
|
||||
for base in base_lst:
|
||||
for v in suffix_lst:
|
||||
alias = "-".join([base, v])
|
||||
assert alias == _get_offset(alias).rule_code
|
||||
assert alias == (_get_offset(alias) * 5).rule_code
|
||||
|
||||
|
||||
def test_freq_offsets():
|
||||
off = BDay(1, offset=timedelta(0, 1800))
|
||||
assert off.freqstr == "B+30Min"
|
||||
|
||||
off = BDay(1, offset=timedelta(0, -1800))
|
||||
assert off.freqstr == "B-30Min"
|
||||
|
||||
|
||||
class TestReprNames:
|
||||
def test_str_for_named_is_name(self):
|
||||
# look at all the amazing combinations!
|
||||
month_prefixes = ["A", "AS", "BA", "BAS", "Q", "BQ", "BQS", "QS"]
|
||||
names = [
|
||||
prefix + "-" + month
|
||||
for prefix in month_prefixes
|
||||
for month in [
|
||||
"JAN",
|
||||
"FEB",
|
||||
"MAR",
|
||||
"APR",
|
||||
"MAY",
|
||||
"JUN",
|
||||
"JUL",
|
||||
"AUG",
|
||||
"SEP",
|
||||
"OCT",
|
||||
"NOV",
|
||||
"DEC",
|
||||
]
|
||||
]
|
||||
days = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]
|
||||
names += ["W-" + day for day in days]
|
||||
names += ["WOM-" + week + day for week in ("1", "2", "3", "4") for day in days]
|
||||
_offset_map.clear()
|
||||
for name in names:
|
||||
offset = _get_offset(name)
|
||||
assert offset.freqstr == name
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_valid_default_arguments(offset_types):
|
||||
# GH#19142 check that the calling the constructors without passing
|
||||
# any keyword arguments produce valid offsets
|
||||
cls = offset_types
|
||||
cls()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kwd", sorted(liboffsets._relativedelta_kwds))
|
||||
def test_valid_month_attributes(kwd, month_classes):
|
||||
# GH#18226
|
||||
cls = month_classes
|
||||
# check that we cannot create e.g. MonthEnd(weeks=3)
|
||||
msg = rf"__init__\(\) got an unexpected keyword argument '{kwd}'"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
cls(**{kwd: 3})
|
||||
|
||||
|
||||
def test_month_offset_name(month_classes):
|
||||
# GH#33757 off.name with n != 1 should not raise AttributeError
|
||||
obj = month_classes(1)
|
||||
obj2 = month_classes(2)
|
||||
assert obj2.name == obj.name
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kwd", sorted(liboffsets._relativedelta_kwds))
|
||||
def test_valid_relativedelta_kwargs(kwd):
|
||||
# Check that all the arguments specified in liboffsets._relativedelta_kwds
|
||||
# are in fact valid relativedelta keyword args
|
||||
DateOffset(**{kwd: 1})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kwd", sorted(liboffsets._relativedelta_kwds))
|
||||
def test_valid_tick_attributes(kwd, tick_classes):
|
||||
# GH#18226
|
||||
cls = tick_classes
|
||||
# check that we cannot create e.g. Hour(weeks=3)
|
||||
msg = rf"__init__\(\) got an unexpected keyword argument '{kwd}'"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
cls(**{kwd: 3})
|
||||
|
||||
|
||||
def test_validate_n_error():
|
||||
with pytest.raises(TypeError, match="argument must be an integer"):
|
||||
DateOffset(n="Doh!")
|
||||
|
||||
with pytest.raises(TypeError, match="argument must be an integer"):
|
||||
MonthBegin(n=timedelta(1))
|
||||
|
||||
with pytest.raises(TypeError, match="argument must be an integer"):
|
||||
BDay(n=np.array([1, 2], dtype=np.int64))
|
||||
|
||||
|
||||
def test_require_integers(offset_types):
|
||||
cls = offset_types
|
||||
with pytest.raises(ValueError, match="argument must be an integer"):
|
||||
cls(n=1.5)
|
||||
|
||||
|
||||
def test_tick_normalize_raises(tick_classes):
|
||||
# check that trying to create a Tick object with normalize=True raises
|
||||
# GH#21427
|
||||
cls = tick_classes
|
||||
msg = "Tick offset with `normalize=True` are not allowed."
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
cls(n=3, normalize=True)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"offset_kwargs, expected_arg",
|
||||
[
|
||||
({"nanoseconds": 1}, "1970-01-01 00:00:00.000000001"),
|
||||
({"nanoseconds": 5}, "1970-01-01 00:00:00.000000005"),
|
||||
({"nanoseconds": -1}, "1969-12-31 23:59:59.999999999"),
|
||||
({"microseconds": 1}, "1970-01-01 00:00:00.000001"),
|
||||
({"microseconds": -1}, "1969-12-31 23:59:59.999999"),
|
||||
({"seconds": 1}, "1970-01-01 00:00:01"),
|
||||
({"seconds": -1}, "1969-12-31 23:59:59"),
|
||||
({"minutes": 1}, "1970-01-01 00:01:00"),
|
||||
({"minutes": -1}, "1969-12-31 23:59:00"),
|
||||
({"hours": 1}, "1970-01-01 01:00:00"),
|
||||
({"hours": -1}, "1969-12-31 23:00:00"),
|
||||
({"days": 1}, "1970-01-02 00:00:00"),
|
||||
({"days": -1}, "1969-12-31 00:00:00"),
|
||||
({"weeks": 1}, "1970-01-08 00:00:00"),
|
||||
({"weeks": -1}, "1969-12-25 00:00:00"),
|
||||
({"months": 1}, "1970-02-01 00:00:00"),
|
||||
({"months": -1}, "1969-12-01 00:00:00"),
|
||||
({"years": 1}, "1971-01-01 00:00:00"),
|
||||
({"years": -1}, "1969-01-01 00:00:00"),
|
||||
],
|
||||
)
|
||||
def test_dateoffset_add_sub(offset_kwargs, expected_arg):
|
||||
offset = DateOffset(**offset_kwargs)
|
||||
ts = Timestamp(0)
|
||||
result = ts + offset
|
||||
expected = Timestamp(expected_arg)
|
||||
assert result == expected
|
||||
result -= offset
|
||||
assert result == ts
|
||||
result = offset + ts
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_dataoffset_add_sub_timestamp_with_nano():
|
||||
offset = DateOffset(minutes=2, nanoseconds=9)
|
||||
ts = Timestamp(4)
|
||||
result = ts + offset
|
||||
expected = Timestamp("1970-01-01 00:02:00.000000013")
|
||||
assert result == expected
|
||||
result -= offset
|
||||
assert result == ts
|
||||
result = offset + ts
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"attribute",
|
||||
[
|
||||
"hours",
|
||||
"days",
|
||||
"weeks",
|
||||
"months",
|
||||
"years",
|
||||
],
|
||||
)
|
||||
def test_dateoffset_immutable(attribute):
|
||||
offset = DateOffset(**{attribute: 0})
|
||||
msg = "DateOffset objects are immutable"
|
||||
with pytest.raises(AttributeError, match=msg):
|
||||
setattr(offset, attribute, 5)
|
||||
|
||||
|
||||
def test_dateoffset_misc():
|
||||
oset = offsets.DateOffset(months=2, days=4)
|
||||
# it works
|
||||
oset.freqstr
|
||||
|
||||
assert not offsets.DateOffset(months=2) == 2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("n", [-1, 1, 3])
|
||||
def test_construct_int_arg_no_kwargs_assumed_days(n):
|
||||
# GH 45890, 45643
|
||||
offset = DateOffset(n)
|
||||
assert offset._offset == timedelta(1)
|
||||
result = Timestamp(2022, 1, 2) + offset
|
||||
expected = Timestamp(2022, 1, 2 + n)
|
||||
assert result == expected
|
||||
@@ -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,298 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- QuarterBegin
|
||||
- QuarterEnd
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
QuarterBegin,
|
||||
QuarterEnd,
|
||||
)
|
||||
|
||||
|
||||
def test_quarterly_dont_normalize():
|
||||
date = datetime(2012, 3, 31, 5, 30)
|
||||
|
||||
offsets = (QuarterBegin, QuarterEnd)
|
||||
|
||||
for klass in offsets:
|
||||
result = date + klass()
|
||||
assert result.time() == date.time()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("offset", [QuarterBegin(), QuarterEnd()])
|
||||
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 TestQuarterBegin(Base):
|
||||
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):
|
||||
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(Base):
|
||||
_offset = QuarterEnd
|
||||
|
||||
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):
|
||||
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,393 @@
|
||||
"""
|
||||
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 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)._apply(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
|
||||
assert left._apply(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
|
||||
assert not (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
|
||||
|
||||
|
||||
@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.delta == 1
|
||||
assert off / off.delta.to_timedelta64() == 1
|
||||
|
||||
assert off / Nano(1) == off.delta / Nano(1).delta
|
||||
|
||||
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.delta == off.delta / 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.delta == off.delta / 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.delta
|
||||
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):
|
||||
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.delta
|
||||
|
||||
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,363 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- Week
|
||||
- WeekOfMonth
|
||||
- LastWeekOfMonth
|
||||
"""
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
)
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import Timestamp
|
||||
from pandas._libs.tslibs.offsets import (
|
||||
Day,
|
||||
LastWeekOfMonth,
|
||||
Week,
|
||||
WeekOfMonth,
|
||||
)
|
||||
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
WeekDay,
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
|
||||
class TestWeek(Base):
|
||||
_offset = Week
|
||||
d = Timestamp(datetime(2008, 1, 2))
|
||||
offset1 = _offset()
|
||||
offset2 = _offset(2)
|
||||
|
||||
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):
|
||||
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)
|
||||
|
||||
if day % 7 == weekday:
|
||||
expected = True
|
||||
else:
|
||||
expected = False
|
||||
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(Base):
|
||||
_offset = WeekOfMonth
|
||||
offset1 = _offset()
|
||||
offset2 = _offset(2)
|
||||
|
||||
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(Base):
|
||||
_offset = LastWeekOfMonth
|
||||
offset1 = _offset()
|
||||
offset2 = _offset(2)
|
||||
|
||||
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,322 @@
|
||||
"""
|
||||
Tests for the following offsets:
|
||||
- YearBegin
|
||||
- YearEnd
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas.tests.tseries.offsets.common import (
|
||||
Base,
|
||||
assert_is_on_offset,
|
||||
assert_offset_equal,
|
||||
)
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
YearBegin,
|
||||
YearEnd,
|
||||
)
|
||||
|
||||
|
||||
class TestYearBegin(Base):
|
||||
_offset = YearBegin
|
||||
|
||||
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(Base):
|
||||
_offset = YearEnd
|
||||
|
||||
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(Base):
|
||||
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)
|
||||
Reference in New Issue
Block a user