Updated script that can be controled by Nodejs web app

This commit is contained in:
mac OS
2024-11-25 12:24:18 +07:00
parent c440eda1f4
commit 8b0ab2bd3a
8662 changed files with 1803808 additions and 34 deletions

View File

@ -0,0 +1,69 @@
import numpy as np
import pytest
from pandas._libs.tslibs import (
Period,
to_offset,
)
@pytest.mark.parametrize(
"freqstr,exp_freqstr",
[("D", "D"), ("W", "D"), ("ME", "D"), ("s", "s"), ("min", "s"), ("h", "s")],
)
def test_get_to_timestamp_base(freqstr, exp_freqstr):
off = to_offset(freqstr)
per = Period._from_ordinal(1, off)
exp_code = to_offset(exp_freqstr)._period_dtype_code
result_code = per._dtype._get_to_timestamp_base()
assert result_code == exp_code
@pytest.mark.parametrize(
"args,expected",
[
((1.5, "min"), (90, "s")),
((62.4, "min"), (3744, "s")),
((1.04, "h"), (3744, "s")),
((1, "D"), (1, "D")),
((0.342931, "h"), (1234551600, "us")),
((1.2345, "D"), (106660800, "ms")),
],
)
def test_resolution_bumping(args, expected):
# see gh-14378
off = to_offset(str(args[0]) + args[1])
assert off.n == expected[0]
assert off._prefix == expected[1]
@pytest.mark.parametrize(
"args",
[
(0.5, "ns"),
# Too much precision in the input can prevent.
(0.3429324798798269273987982, "h"),
],
)
def test_cat(args):
msg = "Invalid frequency"
with pytest.raises(ValueError, match=msg):
to_offset(str(args[0]) + args[1])
@pytest.mark.parametrize(
"freqstr,expected",
[
("1h", "2021-01-01T09:00:00"),
("1D", "2021-01-02T08:00:00"),
("1W", "2021-01-03T08:00:00"),
("1ME", "2021-01-31T08:00:00"),
("1YE", "2021-12-31T08:00:00"),
],
)
def test_compatibility(freqstr, expected):
ts_np = np.datetime64("2021-01-01T08:00:00.00")
do = to_offset(freqstr)
assert ts_np + do == np.datetime64(expected)

View File

@ -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

View File

@ -0,0 +1,558 @@
from datetime import (
datetime,
timedelta,
)
import numpy as np
import pytest
from pandas._libs.tslibs.ccalendar import (
DAYS,
MONTHS,
)
from pandas._libs.tslibs.offsets import _get_offset
from pandas._libs.tslibs.period import INVALID_FREQ_ERR_MSG
from pandas.compat import is_platform_windows
from pandas import (
DatetimeIndex,
Index,
RangeIndex,
Series,
Timestamp,
date_range,
period_range,
)
import pandas._testing as tm
from pandas.core.arrays import (
DatetimeArray,
TimedeltaArray,
)
from pandas.core.tools.datetimes import to_datetime
from pandas.tseries import (
frequencies,
offsets,
)
@pytest.fixture(
params=[
(timedelta(1), "D"),
(timedelta(hours=1), "h"),
(timedelta(minutes=1), "min"),
(timedelta(seconds=1), "s"),
(np.timedelta64(1, "ns"), "ns"),
(timedelta(microseconds=1), "us"),
(timedelta(microseconds=1000), "ms"),
]
)
def base_delta_code_pair(request):
return request.param
freqs = (
[f"QE-{month}" for month in MONTHS]
+ [f"{annual}-{month}" for annual in ["YE", "BYE"] for month in MONTHS]
+ ["ME", "BME", "BMS"]
+ [f"WOM-{count}{day}" for count in range(1, 5) for day in DAYS]
+ [f"W-{day}" for day in DAYS]
)
@pytest.mark.parametrize("freq", freqs)
@pytest.mark.parametrize("periods", [5, 7])
def test_infer_freq_range(periods, freq):
freq = freq.upper()
gen = date_range("1/1/2000", periods=periods, freq=freq)
index = DatetimeIndex(gen.values)
if not freq.startswith("QE-"):
assert frequencies.infer_freq(index) == gen.freqstr
else:
inf_freq = frequencies.infer_freq(index)
is_dec_range = inf_freq == "QE-DEC" and gen.freqstr in (
"QE",
"QE-DEC",
"QE-SEP",
"QE-JUN",
"QE-MAR",
)
is_nov_range = inf_freq == "QE-NOV" and gen.freqstr in (
"QE-NOV",
"QE-AUG",
"QE-MAY",
"QE-FEB",
)
is_oct_range = inf_freq == "QE-OCT" and gen.freqstr in (
"QE-OCT",
"QE-JUL",
"QE-APR",
"QE-JAN",
)
assert is_dec_range or is_nov_range or is_oct_range
def test_raise_if_period_index():
index = period_range(start="1/1/1990", periods=20, freq="M")
msg = "Check the `freq` attribute instead of using infer_freq"
with pytest.raises(TypeError, match=msg):
frequencies.infer_freq(index)
def test_raise_if_too_few():
index = DatetimeIndex(["12/31/1998", "1/3/1999"])
msg = "Need at least 3 dates to infer frequency"
with pytest.raises(ValueError, match=msg):
frequencies.infer_freq(index)
def test_business_daily():
index = DatetimeIndex(["01/01/1999", "1/4/1999", "1/5/1999"])
assert frequencies.infer_freq(index) == "B"
def test_business_daily_look_alike():
# see gh-16624
#
# Do not infer "B when "weekend" (2-day gap) in wrong place.
index = DatetimeIndex(["12/31/1998", "1/3/1999", "1/4/1999"])
assert frequencies.infer_freq(index) is None
def test_day_corner():
index = DatetimeIndex(["1/1/2000", "1/2/2000", "1/3/2000"])
assert frequencies.infer_freq(index) == "D"
def test_non_datetime_index():
dates = to_datetime(["1/1/2000", "1/2/2000", "1/3/2000"])
assert frequencies.infer_freq(dates) == "D"
def test_fifth_week_of_month_infer():
# see gh-9425
#
# Only attempt to infer up to WOM-4.
index = DatetimeIndex(["2014-03-31", "2014-06-30", "2015-03-30"])
assert frequencies.infer_freq(index) is None
def test_week_of_month_fake():
# All of these dates are on same day
# of week and are 4 or 5 weeks apart.
index = DatetimeIndex(["2013-08-27", "2013-10-01", "2013-10-29", "2013-11-26"])
assert frequencies.infer_freq(index) != "WOM-4TUE"
def test_fifth_week_of_month():
# see gh-9425
#
# Only supports freq up to WOM-4.
msg = (
"Of the four parameters: start, end, periods, "
"and freq, exactly three must be specified"
)
with pytest.raises(ValueError, match=msg):
date_range("2014-01-01", freq="WOM-5MON")
def test_monthly_ambiguous():
rng = DatetimeIndex(["1/31/2000", "2/29/2000", "3/31/2000"])
assert rng.inferred_freq == "ME"
def test_annual_ambiguous():
rng = DatetimeIndex(["1/31/2000", "1/31/2001", "1/31/2002"])
assert rng.inferred_freq == "YE-JAN"
@pytest.mark.parametrize("count", range(1, 5))
def test_infer_freq_delta(base_delta_code_pair, count):
b = Timestamp(datetime.now())
base_delta, code = base_delta_code_pair
inc = base_delta * count
index = DatetimeIndex([b + inc * j for j in range(3)])
exp_freq = f"{count:d}{code}" if count > 1 else code
assert frequencies.infer_freq(index) == exp_freq
@pytest.mark.parametrize(
"constructor",
[
lambda now, delta: DatetimeIndex(
[now + delta * 7] + [now + delta * j for j in range(3)]
),
lambda now, delta: DatetimeIndex(
[now + delta * j for j in range(3)] + [now + delta * 7]
),
],
)
def test_infer_freq_custom(base_delta_code_pair, constructor):
b = Timestamp(datetime.now())
base_delta, _ = base_delta_code_pair
index = constructor(b, base_delta)
assert frequencies.infer_freq(index) is None
@pytest.mark.parametrize(
"freq,expected", [("Q", "QE-DEC"), ("Q-NOV", "QE-NOV"), ("Q-OCT", "QE-OCT")]
)
def test_infer_freq_index(freq, expected):
rng = period_range("1959Q2", "2009Q3", freq=freq)
with tm.assert_produces_warning(FutureWarning, match="Dtype inference"):
rng = Index(rng.to_timestamp("D", how="e").astype(object))
assert rng.inferred_freq == expected
@pytest.mark.parametrize(
"expected,dates",
list(
{
"YS-JAN": ["2009-01-01", "2010-01-01", "2011-01-01", "2012-01-01"],
"QE-OCT": ["2009-01-31", "2009-04-30", "2009-07-31", "2009-10-31"],
"ME": ["2010-11-30", "2010-12-31", "2011-01-31", "2011-02-28"],
"W-SAT": ["2010-12-25", "2011-01-01", "2011-01-08", "2011-01-15"],
"D": ["2011-01-01", "2011-01-02", "2011-01-03", "2011-01-04"],
"h": [
"2011-12-31 22:00",
"2011-12-31 23:00",
"2012-01-01 00:00",
"2012-01-01 01:00",
],
}.items()
),
)
@pytest.mark.parametrize("unit", ["s", "ms", "us", "ns"])
def test_infer_freq_tz(tz_naive_fixture, expected, dates, unit):
# see gh-7310, GH#55609
tz = tz_naive_fixture
idx = DatetimeIndex(dates, tz=tz).as_unit(unit)
assert idx.inferred_freq == expected
def test_infer_freq_tz_series(tz_naive_fixture):
# infer_freq should work with both tz-naive and tz-aware series. See gh-52456
tz = tz_naive_fixture
idx = date_range("2021-01-01", "2021-01-04", tz=tz)
series = idx.to_series().reset_index(drop=True)
inferred_freq = frequencies.infer_freq(series)
assert inferred_freq == "D"
@pytest.mark.parametrize(
"date_pair",
[
["2013-11-02", "2013-11-5"], # Fall DST
["2014-03-08", "2014-03-11"], # Spring DST
["2014-01-01", "2014-01-03"], # Regular Time
],
)
@pytest.mark.parametrize(
"freq",
["h", "3h", "10min", "3601s", "3600001ms", "3600000001us", "3600000000001ns"],
)
def test_infer_freq_tz_transition(tz_naive_fixture, date_pair, freq):
# see gh-8772
tz = tz_naive_fixture
idx = date_range(date_pair[0], date_pair[1], freq=freq, tz=tz)
assert idx.inferred_freq == freq
def test_infer_freq_tz_transition_custom():
index = date_range("2013-11-03", periods=5, freq="3h").tz_localize(
"America/Chicago"
)
assert index.inferred_freq is None
@pytest.mark.parametrize(
"data,expected",
[
# Hourly freq in a day must result in "h"
(
[
"2014-07-01 09:00",
"2014-07-01 10:00",
"2014-07-01 11:00",
"2014-07-01 12:00",
"2014-07-01 13:00",
"2014-07-01 14:00",
],
"h",
),
(
[
"2014-07-01 09:00",
"2014-07-01 10:00",
"2014-07-01 11:00",
"2014-07-01 12:00",
"2014-07-01 13:00",
"2014-07-01 14:00",
"2014-07-01 15:00",
"2014-07-01 16:00",
"2014-07-02 09:00",
"2014-07-02 10:00",
"2014-07-02 11:00",
],
"bh",
),
(
[
"2014-07-04 09:00",
"2014-07-04 10:00",
"2014-07-04 11:00",
"2014-07-04 12:00",
"2014-07-04 13:00",
"2014-07-04 14:00",
"2014-07-04 15:00",
"2014-07-04 16:00",
"2014-07-07 09:00",
"2014-07-07 10:00",
"2014-07-07 11:00",
],
"bh",
),
(
[
"2014-07-04 09:00",
"2014-07-04 10:00",
"2014-07-04 11:00",
"2014-07-04 12:00",
"2014-07-04 13:00",
"2014-07-04 14:00",
"2014-07-04 15:00",
"2014-07-04 16:00",
"2014-07-07 09:00",
"2014-07-07 10:00",
"2014-07-07 11:00",
"2014-07-07 12:00",
"2014-07-07 13:00",
"2014-07-07 14:00",
"2014-07-07 15:00",
"2014-07-07 16:00",
"2014-07-08 09:00",
"2014-07-08 10:00",
"2014-07-08 11:00",
"2014-07-08 12:00",
"2014-07-08 13:00",
"2014-07-08 14:00",
"2014-07-08 15:00",
"2014-07-08 16:00",
],
"bh",
),
],
)
def test_infer_freq_business_hour(data, expected):
# see gh-7905
idx = DatetimeIndex(data)
assert idx.inferred_freq == expected
def test_not_monotonic():
rng = DatetimeIndex(["1/31/2000", "1/31/2001", "1/31/2002"])
rng = rng[::-1]
assert rng.inferred_freq == "-1YE-JAN"
def test_non_datetime_index2():
rng = DatetimeIndex(["1/31/2000", "1/31/2001", "1/31/2002"])
vals = rng.to_pydatetime()
result = frequencies.infer_freq(vals)
assert result == rng.inferred_freq
@pytest.mark.parametrize(
"idx",
[
Index(np.arange(5), dtype=np.int64),
Index(np.arange(5), dtype=np.float64),
period_range("2020-01-01", periods=5),
RangeIndex(5),
],
)
def test_invalid_index_types(idx):
# see gh-48439
msg = "|".join(
[
"cannot infer freq from a non-convertible",
"Check the `freq` attribute instead of using infer_freq",
]
)
with pytest.raises(TypeError, match=msg):
frequencies.infer_freq(idx)
@pytest.mark.skipif(is_platform_windows(), reason="see gh-10822: Windows issue")
def test_invalid_index_types_unicode():
# see gh-10822
#
# Odd error message on conversions to datetime for unicode.
msg = "Unknown datetime string format"
with pytest.raises(ValueError, match=msg):
frequencies.infer_freq(Index(["ZqgszYBfuL"]))
def test_string_datetime_like_compat():
# see gh-6463
data = ["2004-01", "2004-02", "2004-03", "2004-04"]
expected = frequencies.infer_freq(data)
result = frequencies.infer_freq(Index(data))
assert result == expected
def test_series():
# see gh-6407
s = Series(date_range("20130101", "20130110"))
inferred = frequencies.infer_freq(s)
assert inferred == "D"
@pytest.mark.parametrize("end", [10, 10.0])
def test_series_invalid_type(end):
# see gh-6407
msg = "cannot infer freq from a non-convertible dtype on a Series"
s = Series(np.arange(end))
with pytest.raises(TypeError, match=msg):
frequencies.infer_freq(s)
def test_series_inconvertible_string(using_infer_string):
# see gh-6407
if using_infer_string:
msg = "cannot infer freq from"
with pytest.raises(TypeError, match=msg):
frequencies.infer_freq(Series(["foo", "bar"]))
else:
msg = "Unknown datetime string format"
with pytest.raises(ValueError, match=msg):
frequencies.infer_freq(Series(["foo", "bar"]))
@pytest.mark.parametrize("freq", [None, "ms"])
def test_series_period_index(freq):
# see gh-6407
#
# Cannot infer on PeriodIndex
msg = "cannot infer freq from a non-convertible dtype on a Series"
s = Series(period_range("2013", periods=10, freq=freq))
with pytest.raises(TypeError, match=msg):
frequencies.infer_freq(s)
@pytest.mark.parametrize("freq", ["ME", "ms", "s"])
def test_series_datetime_index(freq):
s = Series(date_range("20130101", periods=10, freq=freq))
inferred = frequencies.infer_freq(s)
assert inferred == freq
@pytest.mark.parametrize(
"offset_func",
[
_get_offset,
lambda freq: date_range("2011-01-01", periods=5, freq=freq),
],
)
@pytest.mark.parametrize(
"freq",
[
"WEEKDAY",
"EOM",
"W@MON",
"W@TUE",
"W@WED",
"W@THU",
"W@FRI",
"W@SAT",
"W@SUN",
"QE@JAN",
"QE@FEB",
"QE@MAR",
"YE@JAN",
"YE@FEB",
"YE@MAR",
"YE@APR",
"YE@MAY",
"YE@JUN",
"YE@JUL",
"YE@AUG",
"YE@SEP",
"YE@OCT",
"YE@NOV",
"YE@DEC",
"YE@JAN",
"WOM@1MON",
"WOM@2MON",
"WOM@3MON",
"WOM@4MON",
"WOM@1TUE",
"WOM@2TUE",
"WOM@3TUE",
"WOM@4TUE",
"WOM@1WED",
"WOM@2WED",
"WOM@3WED",
"WOM@4WED",
"WOM@1THU",
"WOM@2THU",
"WOM@3THU",
"WOM@4THU",
"WOM@1FRI",
"WOM@2FRI",
"WOM@3FRI",
"WOM@4FRI",
],
)
def test_legacy_offset_warnings(offset_func, freq):
with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG):
offset_func(freq)
def test_ms_vs_capital_ms():
left = _get_offset("ms")
right = _get_offset("MS")
assert left == offsets.Milli()
assert right == offsets.MonthBegin()
def test_infer_freq_non_nano():
arr = np.arange(10).astype(np.int64).view("M8[s]")
dta = DatetimeArray._simple_new(arr, dtype=arr.dtype)
res = frequencies.infer_freq(dta)
assert res == "s"
arr2 = arr.view("m8[ms]")
tda = TimedeltaArray._simple_new(arr2, dtype=arr2.dtype)
res2 = frequencies.infer_freq(tda)
assert res2 == "ms"
def test_infer_freq_non_nano_tzaware(tz_aware_fixture):
tz = tz_aware_fixture
dti = date_range("2016-01-01", periods=365, freq="B", tz=tz)
dta = dti._data.as_unit("s")
res = frequencies.infer_freq(dta)
assert res == "B"

View File

@ -0,0 +1,119 @@
from datetime import datetime
import pytest
from pandas import (
DatetimeIndex,
offsets,
to_datetime,
)
import pandas._testing as tm
from pandas.tseries.holiday import (
AbstractHolidayCalendar,
Holiday,
Timestamp,
USFederalHolidayCalendar,
USLaborDay,
USThanksgivingDay,
get_calendar,
)
@pytest.mark.parametrize(
"transform", [lambda x: x, lambda x: x.strftime("%Y-%m-%d"), lambda x: Timestamp(x)]
)
def test_calendar(transform):
start_date = datetime(2012, 1, 1)
end_date = datetime(2012, 12, 31)
calendar = USFederalHolidayCalendar()
holidays = calendar.holidays(transform(start_date), transform(end_date))
expected = [
datetime(2012, 1, 2),
datetime(2012, 1, 16),
datetime(2012, 2, 20),
datetime(2012, 5, 28),
datetime(2012, 7, 4),
datetime(2012, 9, 3),
datetime(2012, 10, 8),
datetime(2012, 11, 12),
datetime(2012, 11, 22),
datetime(2012, 12, 25),
]
assert list(holidays.to_pydatetime()) == expected
def test_calendar_caching():
# see gh-9552.
class TestCalendar(AbstractHolidayCalendar):
def __init__(self, name=None, rules=None) -> None:
super().__init__(name=name, rules=rules)
jan1 = TestCalendar(rules=[Holiday("jan1", year=2015, month=1, day=1)])
jan2 = TestCalendar(rules=[Holiday("jan2", year=2015, month=1, day=2)])
# Getting holidays for Jan 1 should not alter results for Jan 2.
expected = DatetimeIndex(["01-Jan-2015"]).as_unit("ns")
tm.assert_index_equal(jan1.holidays(), expected)
expected2 = DatetimeIndex(["02-Jan-2015"]).as_unit("ns")
tm.assert_index_equal(jan2.holidays(), expected2)
def test_calendar_observance_dates():
# see gh-11477
us_fed_cal = get_calendar("USFederalHolidayCalendar")
holidays0 = us_fed_cal.holidays(
datetime(2015, 7, 3), datetime(2015, 7, 3)
) # <-- same start and end dates
holidays1 = us_fed_cal.holidays(
datetime(2015, 7, 3), datetime(2015, 7, 6)
) # <-- different start and end dates
holidays2 = us_fed_cal.holidays(
datetime(2015, 7, 3), datetime(2015, 7, 3)
) # <-- same start and end dates
# These should all produce the same result.
#
# In addition, calling with different start and end
# dates should not alter the output if we call the
# function again with the same start and end date.
tm.assert_index_equal(holidays0, holidays1)
tm.assert_index_equal(holidays0, holidays2)
def test_rule_from_name():
us_fed_cal = get_calendar("USFederalHolidayCalendar")
assert us_fed_cal.rule_from_name("Thanksgiving Day") == USThanksgivingDay
def test_calendar_2031():
# See gh-27790
#
# Labor Day 2031 is on September 1. Saturday before is August 30.
# Next working day after August 30 ought to be Tuesday, September 2.
class testCalendar(AbstractHolidayCalendar):
rules = [USLaborDay]
cal = testCalendar()
workDay = offsets.CustomBusinessDay(calendar=cal)
Sat_before_Labor_Day_2031 = to_datetime("2031-08-30")
next_working_day = Sat_before_Labor_Day_2031 + 0 * workDay
assert next_working_day == to_datetime("2031-09-02")
def test_no_holidays_calendar():
# Test for issue #31415
class NoHolidaysCalendar(AbstractHolidayCalendar):
pass
cal = NoHolidaysCalendar()
holidays = cal.holidays(Timestamp("01-Jan-2020"), Timestamp("01-Jan-2021"))
empty_index = DatetimeIndex([]) # Type is DatetimeIndex since return_name=False
tm.assert_index_equal(holidays, empty_index)

View File

@ -0,0 +1,58 @@
from datetime import datetime
from pandas import DatetimeIndex
import pandas._testing as tm
from pandas.tseries.holiday import (
AbstractHolidayCalendar,
USFederalHolidayCalendar,
USMartinLutherKingJr,
USMemorialDay,
)
def test_no_mlk_before_1986():
# see gh-10278
class MLKCalendar(AbstractHolidayCalendar):
rules = [USMartinLutherKingJr]
holidays = MLKCalendar().holidays(start="1984", end="1988").to_pydatetime().tolist()
# Testing to make sure holiday is not incorrectly observed before 1986.
assert holidays == [datetime(1986, 1, 20, 0, 0), datetime(1987, 1, 19, 0, 0)]
def test_memorial_day():
class MemorialDay(AbstractHolidayCalendar):
rules = [USMemorialDay]
holidays = MemorialDay().holidays(start="1971", end="1980").to_pydatetime().tolist()
# Fixes 5/31 error and checked manually against Wikipedia.
assert holidays == [
datetime(1971, 5, 31, 0, 0),
datetime(1972, 5, 29, 0, 0),
datetime(1973, 5, 28, 0, 0),
datetime(1974, 5, 27, 0, 0),
datetime(1975, 5, 26, 0, 0),
datetime(1976, 5, 31, 0, 0),
datetime(1977, 5, 30, 0, 0),
datetime(1978, 5, 29, 0, 0),
datetime(1979, 5, 28, 0, 0),
]
def test_federal_holiday_inconsistent_returntype():
# GH 49075 test case
# Instantiate two calendars to rule out _cache
cal1 = USFederalHolidayCalendar()
cal2 = USFederalHolidayCalendar()
results_2018 = cal1.holidays(start=datetime(2018, 8, 1), end=datetime(2018, 8, 31))
results_2019 = cal2.holidays(start=datetime(2019, 8, 1), end=datetime(2019, 8, 31))
expected_results = DatetimeIndex([], dtype="datetime64[ns]", freq=None)
# Check against expected results to ensure both date
# ranges generate expected results as per GH49075 submission
tm.assert_index_equal(results_2018, expected_results)
tm.assert_index_equal(results_2019, expected_results)

View File

@ -0,0 +1,332 @@
from datetime import datetime
import pytest
from pytz import utc
from pandas import (
DatetimeIndex,
Series,
)
import pandas._testing as tm
from pandas.tseries.holiday import (
MO,
SA,
AbstractHolidayCalendar,
DateOffset,
EasterMonday,
GoodFriday,
Holiday,
HolidayCalendarFactory,
Timestamp,
USColumbusDay,
USFederalHolidayCalendar,
USLaborDay,
USMartinLutherKingJr,
USMemorialDay,
USPresidentsDay,
USThanksgivingDay,
get_calendar,
next_monday,
)
@pytest.mark.parametrize(
"holiday,start_date,end_date,expected",
[
(
USMemorialDay,
datetime(2011, 1, 1),
datetime(2020, 12, 31),
[
datetime(2011, 5, 30),
datetime(2012, 5, 28),
datetime(2013, 5, 27),
datetime(2014, 5, 26),
datetime(2015, 5, 25),
datetime(2016, 5, 30),
datetime(2017, 5, 29),
datetime(2018, 5, 28),
datetime(2019, 5, 27),
datetime(2020, 5, 25),
],
),
(
Holiday("July 4th Eve", month=7, day=3),
"2001-01-01",
"2003-03-03",
[Timestamp("2001-07-03 00:00:00"), Timestamp("2002-07-03 00:00:00")],
),
(
Holiday("July 4th Eve", month=7, day=3, days_of_week=(0, 1, 2, 3)),
"2001-01-01",
"2008-03-03",
[
Timestamp("2001-07-03 00:00:00"),
Timestamp("2002-07-03 00:00:00"),
Timestamp("2003-07-03 00:00:00"),
Timestamp("2006-07-03 00:00:00"),
Timestamp("2007-07-03 00:00:00"),
],
),
(
EasterMonday,
datetime(2011, 1, 1),
datetime(2020, 12, 31),
[
Timestamp("2011-04-25 00:00:00"),
Timestamp("2012-04-09 00:00:00"),
Timestamp("2013-04-01 00:00:00"),
Timestamp("2014-04-21 00:00:00"),
Timestamp("2015-04-06 00:00:00"),
Timestamp("2016-03-28 00:00:00"),
Timestamp("2017-04-17 00:00:00"),
Timestamp("2018-04-02 00:00:00"),
Timestamp("2019-04-22 00:00:00"),
Timestamp("2020-04-13 00:00:00"),
],
),
(
GoodFriday,
datetime(2011, 1, 1),
datetime(2020, 12, 31),
[
Timestamp("2011-04-22 00:00:00"),
Timestamp("2012-04-06 00:00:00"),
Timestamp("2013-03-29 00:00:00"),
Timestamp("2014-04-18 00:00:00"),
Timestamp("2015-04-03 00:00:00"),
Timestamp("2016-03-25 00:00:00"),
Timestamp("2017-04-14 00:00:00"),
Timestamp("2018-03-30 00:00:00"),
Timestamp("2019-04-19 00:00:00"),
Timestamp("2020-04-10 00:00:00"),
],
),
(
USThanksgivingDay,
datetime(2011, 1, 1),
datetime(2020, 12, 31),
[
datetime(2011, 11, 24),
datetime(2012, 11, 22),
datetime(2013, 11, 28),
datetime(2014, 11, 27),
datetime(2015, 11, 26),
datetime(2016, 11, 24),
datetime(2017, 11, 23),
datetime(2018, 11, 22),
datetime(2019, 11, 28),
datetime(2020, 11, 26),
],
),
],
)
def test_holiday_dates(holiday, start_date, end_date, expected):
assert list(holiday.dates(start_date, end_date)) == expected
# Verify that timezone info is preserved.
assert list(
holiday.dates(
utc.localize(Timestamp(start_date)), utc.localize(Timestamp(end_date))
)
) == [utc.localize(dt) for dt in expected]
@pytest.mark.parametrize(
"holiday,start,expected",
[
(USMemorialDay, datetime(2015, 7, 1), []),
(USMemorialDay, "2015-05-25", [Timestamp("2015-05-25")]),
(USLaborDay, datetime(2015, 7, 1), []),
(USLaborDay, "2015-09-07", [Timestamp("2015-09-07")]),
(USColumbusDay, datetime(2015, 7, 1), []),
(USColumbusDay, "2015-10-12", [Timestamp("2015-10-12")]),
(USThanksgivingDay, datetime(2015, 7, 1), []),
(USThanksgivingDay, "2015-11-26", [Timestamp("2015-11-26")]),
(USMartinLutherKingJr, datetime(2015, 7, 1), []),
(USMartinLutherKingJr, "2015-01-19", [Timestamp("2015-01-19")]),
(USPresidentsDay, datetime(2015, 7, 1), []),
(USPresidentsDay, "2015-02-16", [Timestamp("2015-02-16")]),
(GoodFriday, datetime(2015, 7, 1), []),
(GoodFriday, "2015-04-03", [Timestamp("2015-04-03")]),
(EasterMonday, "2015-04-06", [Timestamp("2015-04-06")]),
(EasterMonday, datetime(2015, 7, 1), []),
(EasterMonday, "2015-04-05", []),
("New Year's Day", "2015-01-01", [Timestamp("2015-01-01")]),
("New Year's Day", "2010-12-31", [Timestamp("2010-12-31")]),
("New Year's Day", datetime(2015, 7, 1), []),
("New Year's Day", "2011-01-01", []),
("Independence Day", "2015-07-03", [Timestamp("2015-07-03")]),
("Independence Day", datetime(2015, 7, 1), []),
("Independence Day", "2015-07-04", []),
("Veterans Day", "2012-11-12", [Timestamp("2012-11-12")]),
("Veterans Day", datetime(2015, 7, 1), []),
("Veterans Day", "2012-11-11", []),
("Christmas Day", "2011-12-26", [Timestamp("2011-12-26")]),
("Christmas Day", datetime(2015, 7, 1), []),
("Christmas Day", "2011-12-25", []),
("Juneteenth National Independence Day", "2020-06-19", []),
(
"Juneteenth National Independence Day",
"2021-06-18",
[Timestamp("2021-06-18")],
),
("Juneteenth National Independence Day", "2022-06-19", []),
(
"Juneteenth National Independence Day",
"2022-06-20",
[Timestamp("2022-06-20")],
),
],
)
def test_holidays_within_dates(holiday, start, expected):
# see gh-11477
#
# Fix holiday behavior where holiday.dates returned dates outside
# start/end date, or observed rules could not be applied because the
# holiday was not in the original date range (e.g., 7/4/2015 -> 7/3/2015).
if isinstance(holiday, str):
calendar = get_calendar("USFederalHolidayCalendar")
holiday = calendar.rule_from_name(holiday)
assert list(holiday.dates(start, start)) == expected
# Verify that timezone info is preserved.
assert list(
holiday.dates(utc.localize(Timestamp(start)), utc.localize(Timestamp(start)))
) == [utc.localize(dt) for dt in expected]
@pytest.mark.parametrize(
"transform", [lambda x: x.strftime("%Y-%m-%d"), lambda x: Timestamp(x)]
)
def test_argument_types(transform):
start_date = datetime(2011, 1, 1)
end_date = datetime(2020, 12, 31)
holidays = USThanksgivingDay.dates(start_date, end_date)
holidays2 = USThanksgivingDay.dates(transform(start_date), transform(end_date))
tm.assert_index_equal(holidays, holidays2)
@pytest.mark.parametrize(
"name,kwargs",
[
("One-Time", {"year": 2012, "month": 5, "day": 28}),
(
"Range",
{
"month": 5,
"day": 28,
"start_date": datetime(2012, 1, 1),
"end_date": datetime(2012, 12, 31),
"offset": DateOffset(weekday=MO(1)),
},
),
],
)
def test_special_holidays(name, kwargs):
base_date = [datetime(2012, 5, 28)]
holiday = Holiday(name, **kwargs)
start_date = datetime(2011, 1, 1)
end_date = datetime(2020, 12, 31)
assert base_date == holiday.dates(start_date, end_date)
def test_get_calendar():
class TestCalendar(AbstractHolidayCalendar):
rules = []
calendar = get_calendar("TestCalendar")
assert TestCalendar == type(calendar)
def test_factory():
class_1 = HolidayCalendarFactory(
"MemorialDay", AbstractHolidayCalendar, USMemorialDay
)
class_2 = HolidayCalendarFactory(
"Thanksgiving", AbstractHolidayCalendar, USThanksgivingDay
)
class_3 = HolidayCalendarFactory("Combined", class_1, class_2)
assert len(class_1.rules) == 1
assert len(class_2.rules) == 1
assert len(class_3.rules) == 2
def test_both_offset_observance_raises():
# see gh-10217
msg = "Cannot use both offset and observance"
with pytest.raises(NotImplementedError, match=msg):
Holiday(
"Cyber Monday",
month=11,
day=1,
offset=[DateOffset(weekday=SA(4))],
observance=next_monday,
)
def test_half_open_interval_with_observance():
# Prompted by GH 49075
# Check for holidays that have a half-open date interval where
# they have either a start_date or end_date defined along
# with a defined observance pattern to make sure that the return type
# for Holiday.dates() remains consistent before & after the year that
# marks the 'edge' of the half-open date interval.
holiday_1 = Holiday(
"Arbitrary Holiday - start 2022-03-14",
start_date=datetime(2022, 3, 14),
month=3,
day=14,
observance=next_monday,
)
holiday_2 = Holiday(
"Arbitrary Holiday 2 - end 2022-03-20",
end_date=datetime(2022, 3, 20),
month=3,
day=20,
observance=next_monday,
)
class TestHolidayCalendar(AbstractHolidayCalendar):
rules = [
USMartinLutherKingJr,
holiday_1,
holiday_2,
USLaborDay,
]
start = Timestamp("2022-08-01")
end = Timestamp("2022-08-31")
year_offset = DateOffset(years=5)
expected_results = DatetimeIndex([], dtype="datetime64[ns]", freq=None)
test_cal = TestHolidayCalendar()
date_interval_low = test_cal.holidays(start - year_offset, end - year_offset)
date_window_edge = test_cal.holidays(start, end)
date_interval_high = test_cal.holidays(start + year_offset, end + year_offset)
tm.assert_index_equal(date_interval_low, expected_results)
tm.assert_index_equal(date_window_edge, expected_results)
tm.assert_index_equal(date_interval_high, expected_results)
def test_holidays_with_timezone_specified_but_no_occurences():
# GH 54580
# _apply_rule() in holiday.py was silently dropping timezones if you passed it
# an empty list of holiday dates that had timezone information
start_date = Timestamp("2018-01-01", tz="America/Chicago")
end_date = Timestamp("2018-01-11", tz="America/Chicago")
test_case = USFederalHolidayCalendar().holidays(
start_date, end_date, return_name=True
)
expected_results = Series("New Year's Day", index=[start_date])
expected_results.index = expected_results.index.as_unit("ns")
tm.assert_equal(test_case, expected_results)

View File

@ -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

View File

@ -0,0 +1,37 @@
"""
Assertion helpers and base class for offsets tests
"""
from __future__ import annotations
def assert_offset_equal(offset, base, expected):
actual = offset + base
actual_swapped = base + offset
actual_apply = offset._apply(base)
try:
assert actual == expected
assert actual_swapped == expected
assert actual_apply == expected
except AssertionError as err:
raise AssertionError(
f"\nExpected: {expected}\nActual: {actual}\nFor Offset: {offset})"
f"\nAt Date: {base}"
) from err
def assert_is_on_offset(offset, date, expected):
actual = offset.is_on_offset(date)
assert actual == expected, (
f"\nExpected: {expected}\nActual: {actual}\nFor Offset: {offset})"
f"\nAt Date: {date}"
)
class WeekDay:
MON = 0
TUE = 1
WED = 2
THU = 3
FRI = 4
SAT = 5
SUN = 6

View File

@ -0,0 +1,236 @@
"""
Tests for offsets.BDay
"""
from __future__ import annotations
from datetime import (
date,
datetime,
timedelta,
)
import numpy as np
import pytest
from pandas._libs.tslibs.offsets import (
ApplyTypeError,
BDay,
BMonthEnd,
)
from pandas import (
DatetimeIndex,
Timedelta,
_testing as tm,
)
from pandas.tests.tseries.offsets.common import (
assert_is_on_offset,
assert_offset_equal,
)
from pandas.tseries import offsets
@pytest.fixture
def dt():
return datetime(2008, 1, 1)
@pytest.fixture
def _offset():
return BDay
@pytest.fixture
def offset(_offset):
return _offset()
@pytest.fixture
def offset2(_offset):
return _offset(2)
class TestBusinessDay:
def test_different_normalize_equals(self, _offset, offset2):
# GH#21404 changed __eq__ to return False when `normalize` does not match
offset = _offset()
offset2 = _offset(normalize=True)
assert offset != offset2
def test_repr(self, offset, offset2):
assert repr(offset) == "<BusinessDay>"
assert repr(offset2) == "<2 * BusinessDays>"
expected = "<BusinessDay: offset=datetime.timedelta(days=1)>"
assert repr(offset + timedelta(1)) == expected
def test_with_offset(self, dt, offset):
offset = offset + timedelta(hours=2)
assert (dt + offset) == datetime(2008, 1, 2, 2)
@pytest.mark.parametrize(
"td",
[
Timedelta(hours=2),
Timedelta(hours=2).to_pytimedelta(),
Timedelta(hours=2).to_timedelta64(),
],
ids=lambda x: type(x),
)
def test_with_offset_index(self, td, dt, offset):
dti = DatetimeIndex([dt])
expected = DatetimeIndex([datetime(2008, 1, 2, 2)])
result = dti + (td + offset)
tm.assert_index_equal(result, expected)
result = dti + (offset + td)
tm.assert_index_equal(result, expected)
def test_eq(self, offset2):
assert offset2 == offset2
def test_hash(self, offset2):
assert hash(offset2) == hash(offset2)
def test_add_datetime(self, dt, offset2):
assert offset2 + dt == datetime(2008, 1, 3)
assert offset2 + np.datetime64("2008-01-01 00:00:00") == datetime(2008, 1, 3)
def testRollback1(self, dt, _offset):
assert _offset(10).rollback(dt) == dt
def testRollback2(self, _offset):
assert _offset(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4)
def testRollforward1(self, dt, _offset):
assert _offset(10).rollforward(dt) == dt
def testRollforward2(self, _offset):
assert _offset(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7)
def test_roll_date_object(self, offset):
dt = date(2012, 9, 15)
result = offset.rollback(dt)
assert result == datetime(2012, 9, 14)
result = offset.rollforward(dt)
assert result == datetime(2012, 9, 17)
offset = offsets.Day()
result = offset.rollback(dt)
assert result == datetime(2012, 9, 15)
result = offset.rollforward(dt)
assert result == datetime(2012, 9, 15)
@pytest.mark.parametrize(
"dt, expected",
[
(datetime(2008, 1, 1), True),
(datetime(2008, 1, 5), False),
],
)
def test_is_on_offset(self, offset, dt, expected):
assert_is_on_offset(offset, dt, expected)
apply_cases: list[tuple[int, dict[datetime, datetime]]] = [
(
1,
{
datetime(2008, 1, 1): datetime(2008, 1, 2),
datetime(2008, 1, 4): datetime(2008, 1, 7),
datetime(2008, 1, 5): datetime(2008, 1, 7),
datetime(2008, 1, 6): datetime(2008, 1, 7),
datetime(2008, 1, 7): datetime(2008, 1, 8),
},
),
(
2,
{
datetime(2008, 1, 1): datetime(2008, 1, 3),
datetime(2008, 1, 4): datetime(2008, 1, 8),
datetime(2008, 1, 5): datetime(2008, 1, 8),
datetime(2008, 1, 6): datetime(2008, 1, 8),
datetime(2008, 1, 7): datetime(2008, 1, 9),
},
),
(
-1,
{
datetime(2008, 1, 1): datetime(2007, 12, 31),
datetime(2008, 1, 4): datetime(2008, 1, 3),
datetime(2008, 1, 5): datetime(2008, 1, 4),
datetime(2008, 1, 6): datetime(2008, 1, 4),
datetime(2008, 1, 7): datetime(2008, 1, 4),
datetime(2008, 1, 8): datetime(2008, 1, 7),
},
),
(
-2,
{
datetime(2008, 1, 1): datetime(2007, 12, 28),
datetime(2008, 1, 4): datetime(2008, 1, 2),
datetime(2008, 1, 5): datetime(2008, 1, 3),
datetime(2008, 1, 6): datetime(2008, 1, 3),
datetime(2008, 1, 7): datetime(2008, 1, 3),
datetime(2008, 1, 8): datetime(2008, 1, 4),
datetime(2008, 1, 9): datetime(2008, 1, 7),
},
),
(
0,
{
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2008, 1, 4): datetime(2008, 1, 4),
datetime(2008, 1, 5): datetime(2008, 1, 7),
datetime(2008, 1, 6): datetime(2008, 1, 7),
datetime(2008, 1, 7): datetime(2008, 1, 7),
},
),
]
@pytest.mark.parametrize("case", apply_cases)
def test_apply(self, case, _offset):
n, cases = case
offset = _offset(n)
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
def test_apply_large_n(self, _offset):
dt = datetime(2012, 10, 23)
result = dt + _offset(10)
assert result == datetime(2012, 11, 6)
result = dt + _offset(100) - _offset(100)
assert result == dt
off = _offset() * 6
rs = datetime(2012, 1, 1) - off
xp = datetime(2011, 12, 23)
assert rs == xp
st = datetime(2011, 12, 18)
rs = st + off
xp = datetime(2011, 12, 26)
assert rs == xp
off = _offset() * 10
rs = datetime(2014, 1, 5) + off # see #5890
xp = datetime(2014, 1, 17)
assert rs == xp
def test_apply_corner(self, _offset):
if _offset is BDay:
msg = "Only know how to combine business day with datetime or timedelta"
else:
msg = (
"Only know how to combine trading day "
"with datetime, datetime64 or timedelta"
)
with pytest.raises(ApplyTypeError, match=msg):
_offset()._apply(BMonthEnd())

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,217 @@
"""
Tests for the following offsets:
- BMonthBegin
- BMonthEnd
"""
from __future__ import annotations
from datetime import datetime
import pytest
import pandas as pd
from pandas.tests.tseries.offsets.common import (
assert_is_on_offset,
assert_offset_equal,
)
from pandas.tseries.offsets import (
BMonthBegin,
BMonthEnd,
)
@pytest.mark.parametrize("n", [-2, 1])
@pytest.mark.parametrize(
"cls",
[
BMonthBegin,
BMonthEnd,
],
)
def test_apply_index(cls, n):
offset = cls(n=n)
rng = pd.date_range(start="1/1/2000", periods=100000, freq="min")
ser = pd.Series(rng)
res = rng + offset
assert res.freq is None # not retained
assert res[0] == rng[0] + offset
assert res[-1] == rng[-1] + offset
res2 = ser + offset
# apply_index is only for indexes, not series, so no res2_v2
assert res2.iloc[0] == ser.iloc[0] + offset
assert res2.iloc[-1] == ser.iloc[-1] + offset
class TestBMonthBegin:
def test_offsets_compare_equal(self):
# root cause of #456
offset1 = BMonthBegin()
offset2 = BMonthBegin()
assert not offset1 != offset2
offset_cases = []
offset_cases.append(
(
BMonthBegin(),
{
datetime(2008, 1, 1): datetime(2008, 2, 1),
datetime(2008, 1, 31): datetime(2008, 2, 1),
datetime(2006, 12, 29): datetime(2007, 1, 1),
datetime(2006, 12, 31): datetime(2007, 1, 1),
datetime(2006, 9, 1): datetime(2006, 10, 2),
datetime(2007, 1, 1): datetime(2007, 2, 1),
datetime(2006, 12, 1): datetime(2007, 1, 1),
},
)
)
offset_cases.append(
(
BMonthBegin(0),
{
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2006, 10, 2): datetime(2006, 10, 2),
datetime(2008, 1, 31): datetime(2008, 2, 1),
datetime(2006, 12, 29): datetime(2007, 1, 1),
datetime(2006, 12, 31): datetime(2007, 1, 1),
datetime(2006, 9, 15): datetime(2006, 10, 2),
},
)
)
offset_cases.append(
(
BMonthBegin(2),
{
datetime(2008, 1, 1): datetime(2008, 3, 3),
datetime(2008, 1, 15): datetime(2008, 3, 3),
datetime(2006, 12, 29): datetime(2007, 2, 1),
datetime(2006, 12, 31): datetime(2007, 2, 1),
datetime(2007, 1, 1): datetime(2007, 3, 1),
datetime(2006, 11, 1): datetime(2007, 1, 1),
},
)
)
offset_cases.append(
(
BMonthBegin(-1),
{
datetime(2007, 1, 1): datetime(2006, 12, 1),
datetime(2008, 6, 30): datetime(2008, 6, 2),
datetime(2008, 6, 1): datetime(2008, 5, 1),
datetime(2008, 3, 10): datetime(2008, 3, 3),
datetime(2008, 12, 31): datetime(2008, 12, 1),
datetime(2006, 12, 29): datetime(2006, 12, 1),
datetime(2006, 12, 30): datetime(2006, 12, 1),
datetime(2007, 1, 1): datetime(2006, 12, 1),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
on_offset_cases = [
(BMonthBegin(), datetime(2007, 12, 31), False),
(BMonthBegin(), datetime(2008, 1, 1), True),
(BMonthBegin(), datetime(2001, 4, 2), True),
(BMonthBegin(), datetime(2008, 3, 3), True),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
class TestBMonthEnd:
def test_normalize(self):
dt = datetime(2007, 1, 1, 3)
result = dt + BMonthEnd(normalize=True)
expected = dt.replace(hour=0) + BMonthEnd()
assert result == expected
def test_offsets_compare_equal(self):
# root cause of #456
offset1 = BMonthEnd()
offset2 = BMonthEnd()
assert not offset1 != offset2
offset_cases = []
offset_cases.append(
(
BMonthEnd(),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 2, 29),
datetime(2006, 12, 29): datetime(2007, 1, 31),
datetime(2006, 12, 31): datetime(2007, 1, 31),
datetime(2007, 1, 1): datetime(2007, 1, 31),
datetime(2006, 12, 1): datetime(2006, 12, 29),
},
)
)
offset_cases.append(
(
BMonthEnd(0),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 1, 31),
datetime(2006, 12, 29): datetime(2006, 12, 29),
datetime(2006, 12, 31): datetime(2007, 1, 31),
datetime(2007, 1, 1): datetime(2007, 1, 31),
},
)
)
offset_cases.append(
(
BMonthEnd(2),
{
datetime(2008, 1, 1): datetime(2008, 2, 29),
datetime(2008, 1, 31): datetime(2008, 3, 31),
datetime(2006, 12, 29): datetime(2007, 2, 28),
datetime(2006, 12, 31): datetime(2007, 2, 28),
datetime(2007, 1, 1): datetime(2007, 2, 28),
datetime(2006, 11, 1): datetime(2006, 12, 29),
},
)
)
offset_cases.append(
(
BMonthEnd(-1),
{
datetime(2007, 1, 1): datetime(2006, 12, 29),
datetime(2008, 6, 30): datetime(2008, 5, 30),
datetime(2008, 12, 31): datetime(2008, 11, 28),
datetime(2006, 12, 29): datetime(2006, 11, 30),
datetime(2006, 12, 30): datetime(2006, 12, 29),
datetime(2007, 1, 1): datetime(2006, 12, 29),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
on_offset_cases = [
(BMonthEnd(), datetime(2007, 12, 31), True),
(BMonthEnd(), datetime(2008, 1, 1), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)

View File

@ -0,0 +1,315 @@
"""
Tests for the following offsets:
- BQuarterBegin
- BQuarterEnd
"""
from __future__ import annotations
from datetime import datetime
import pytest
import pandas._testing as tm
from pandas.tests.tseries.offsets.common import (
assert_is_on_offset,
assert_offset_equal,
)
from pandas.tseries.offsets import (
BQuarterBegin,
BQuarterEnd,
)
def test_quarterly_dont_normalize():
date = datetime(2012, 3, 31, 5, 30)
offsets = (BQuarterEnd, BQuarterBegin)
for klass in offsets:
result = date + klass()
assert result.time() == date.time()
@pytest.mark.parametrize("offset", [BQuarterBegin(), BQuarterEnd()])
def test_on_offset(offset):
dates = [
datetime(2016, m, d)
for m in [10, 11, 12]
for d in [1, 2, 3, 28, 29, 30, 31]
if not (m == 11 and d == 31)
]
for date in dates:
res = offset.is_on_offset(date)
slow_version = date == (date + offset) - offset
assert res == slow_version
class TestBQuarterBegin:
def test_repr(self):
expected = "<BusinessQuarterBegin: startingMonth=3>"
assert repr(BQuarterBegin()) == expected
expected = "<BusinessQuarterBegin: startingMonth=3>"
assert repr(BQuarterBegin(startingMonth=3)) == expected
expected = "<BusinessQuarterBegin: startingMonth=1>"
assert repr(BQuarterBegin(startingMonth=1)) == expected
def test_is_anchored(self):
msg = "BQuarterBegin.is_anchored is deprecated "
with tm.assert_produces_warning(FutureWarning, match=msg):
assert BQuarterBegin(startingMonth=1).is_anchored()
assert BQuarterBegin().is_anchored()
assert not BQuarterBegin(2, startingMonth=1).is_anchored()
def test_offset_corner_case(self):
# corner
offset = BQuarterBegin(n=-1, startingMonth=1)
assert datetime(2007, 4, 3) + offset == datetime(2007, 4, 2)
offset_cases = []
offset_cases.append(
(
BQuarterBegin(startingMonth=1),
{
datetime(2008, 1, 1): datetime(2008, 4, 1),
datetime(2008, 1, 31): datetime(2008, 4, 1),
datetime(2008, 2, 15): datetime(2008, 4, 1),
datetime(2008, 2, 29): datetime(2008, 4, 1),
datetime(2008, 3, 15): datetime(2008, 4, 1),
datetime(2008, 3, 31): datetime(2008, 4, 1),
datetime(2008, 4, 15): datetime(2008, 7, 1),
datetime(2007, 3, 15): datetime(2007, 4, 2),
datetime(2007, 2, 28): datetime(2007, 4, 2),
datetime(2007, 1, 1): datetime(2007, 4, 2),
datetime(2007, 4, 15): datetime(2007, 7, 2),
datetime(2007, 7, 1): datetime(2007, 7, 2),
datetime(2007, 4, 1): datetime(2007, 4, 2),
datetime(2007, 4, 2): datetime(2007, 7, 2),
datetime(2008, 4, 30): datetime(2008, 7, 1),
},
)
)
offset_cases.append(
(
BQuarterBegin(startingMonth=2),
{
datetime(2008, 1, 1): datetime(2008, 2, 1),
datetime(2008, 1, 31): datetime(2008, 2, 1),
datetime(2008, 1, 15): datetime(2008, 2, 1),
datetime(2008, 2, 29): datetime(2008, 5, 1),
datetime(2008, 3, 15): datetime(2008, 5, 1),
datetime(2008, 3, 31): datetime(2008, 5, 1),
datetime(2008, 4, 15): datetime(2008, 5, 1),
datetime(2008, 8, 15): datetime(2008, 11, 3),
datetime(2008, 9, 15): datetime(2008, 11, 3),
datetime(2008, 11, 1): datetime(2008, 11, 3),
datetime(2008, 4, 30): datetime(2008, 5, 1),
},
)
)
offset_cases.append(
(
BQuarterBegin(startingMonth=1, n=0),
{
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2007, 12, 31): datetime(2008, 1, 1),
datetime(2008, 2, 15): datetime(2008, 4, 1),
datetime(2008, 2, 29): datetime(2008, 4, 1),
datetime(2008, 1, 15): datetime(2008, 4, 1),
datetime(2008, 2, 27): datetime(2008, 4, 1),
datetime(2008, 3, 15): datetime(2008, 4, 1),
datetime(2007, 4, 1): datetime(2007, 4, 2),
datetime(2007, 4, 2): datetime(2007, 4, 2),
datetime(2007, 7, 1): datetime(2007, 7, 2),
datetime(2007, 4, 15): datetime(2007, 7, 2),
datetime(2007, 7, 2): datetime(2007, 7, 2),
},
)
)
offset_cases.append(
(
BQuarterBegin(startingMonth=1, n=-1),
{
datetime(2008, 1, 1): datetime(2007, 10, 1),
datetime(2008, 1, 31): datetime(2008, 1, 1),
datetime(2008, 2, 15): datetime(2008, 1, 1),
datetime(2008, 2, 29): datetime(2008, 1, 1),
datetime(2008, 3, 15): datetime(2008, 1, 1),
datetime(2008, 3, 31): datetime(2008, 1, 1),
datetime(2008, 4, 15): datetime(2008, 4, 1),
datetime(2007, 7, 3): datetime(2007, 7, 2),
datetime(2007, 4, 3): datetime(2007, 4, 2),
datetime(2007, 7, 2): datetime(2007, 4, 2),
datetime(2008, 4, 1): datetime(2008, 1, 1),
},
)
)
offset_cases.append(
(
BQuarterBegin(startingMonth=1, n=2),
{
datetime(2008, 1, 1): datetime(2008, 7, 1),
datetime(2008, 1, 15): datetime(2008, 7, 1),
datetime(2008, 2, 29): datetime(2008, 7, 1),
datetime(2008, 3, 15): datetime(2008, 7, 1),
datetime(2007, 3, 31): datetime(2007, 7, 2),
datetime(2007, 4, 15): datetime(2007, 10, 1),
datetime(2008, 4, 30): datetime(2008, 10, 1),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
class TestBQuarterEnd:
def test_repr(self):
expected = "<BusinessQuarterEnd: startingMonth=3>"
assert repr(BQuarterEnd()) == expected
expected = "<BusinessQuarterEnd: startingMonth=3>"
assert repr(BQuarterEnd(startingMonth=3)) == expected
expected = "<BusinessQuarterEnd: startingMonth=1>"
assert repr(BQuarterEnd(startingMonth=1)) == expected
def test_is_anchored(self):
msg = "BQuarterEnd.is_anchored is deprecated "
with tm.assert_produces_warning(FutureWarning, match=msg):
assert BQuarterEnd(startingMonth=1).is_anchored()
assert BQuarterEnd().is_anchored()
assert not BQuarterEnd(2, startingMonth=1).is_anchored()
def test_offset_corner_case(self):
# corner
offset = BQuarterEnd(n=-1, startingMonth=1)
assert datetime(2010, 1, 31) + offset == datetime(2010, 1, 29)
offset_cases = []
offset_cases.append(
(
BQuarterEnd(startingMonth=1),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 4, 30),
datetime(2008, 2, 15): datetime(2008, 4, 30),
datetime(2008, 2, 29): datetime(2008, 4, 30),
datetime(2008, 3, 15): datetime(2008, 4, 30),
datetime(2008, 3, 31): datetime(2008, 4, 30),
datetime(2008, 4, 15): datetime(2008, 4, 30),
datetime(2008, 4, 30): datetime(2008, 7, 31),
},
)
)
offset_cases.append(
(
BQuarterEnd(startingMonth=2),
{
datetime(2008, 1, 1): datetime(2008, 2, 29),
datetime(2008, 1, 31): datetime(2008, 2, 29),
datetime(2008, 2, 15): datetime(2008, 2, 29),
datetime(2008, 2, 29): datetime(2008, 5, 30),
datetime(2008, 3, 15): datetime(2008, 5, 30),
datetime(2008, 3, 31): datetime(2008, 5, 30),
datetime(2008, 4, 15): datetime(2008, 5, 30),
datetime(2008, 4, 30): datetime(2008, 5, 30),
},
)
)
offset_cases.append(
(
BQuarterEnd(startingMonth=1, n=0),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 1, 31),
datetime(2008, 2, 15): datetime(2008, 4, 30),
datetime(2008, 2, 29): datetime(2008, 4, 30),
datetime(2008, 3, 15): datetime(2008, 4, 30),
datetime(2008, 3, 31): datetime(2008, 4, 30),
datetime(2008, 4, 15): datetime(2008, 4, 30),
datetime(2008, 4, 30): datetime(2008, 4, 30),
},
)
)
offset_cases.append(
(
BQuarterEnd(startingMonth=1, n=-1),
{
datetime(2008, 1, 1): datetime(2007, 10, 31),
datetime(2008, 1, 31): datetime(2007, 10, 31),
datetime(2008, 2, 15): datetime(2008, 1, 31),
datetime(2008, 2, 29): datetime(2008, 1, 31),
datetime(2008, 3, 15): datetime(2008, 1, 31),
datetime(2008, 3, 31): datetime(2008, 1, 31),
datetime(2008, 4, 15): datetime(2008, 1, 31),
datetime(2008, 4, 30): datetime(2008, 1, 31),
},
)
)
offset_cases.append(
(
BQuarterEnd(startingMonth=1, n=2),
{
datetime(2008, 1, 31): datetime(2008, 7, 31),
datetime(2008, 2, 15): datetime(2008, 7, 31),
datetime(2008, 2, 29): datetime(2008, 7, 31),
datetime(2008, 3, 15): datetime(2008, 7, 31),
datetime(2008, 3, 31): datetime(2008, 7, 31),
datetime(2008, 4, 15): datetime(2008, 7, 31),
datetime(2008, 4, 30): datetime(2008, 10, 31),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
on_offset_cases = [
(BQuarterEnd(1, startingMonth=1), datetime(2008, 1, 31), True),
(BQuarterEnd(1, startingMonth=1), datetime(2007, 12, 31), False),
(BQuarterEnd(1, startingMonth=1), datetime(2008, 2, 29), False),
(BQuarterEnd(1, startingMonth=1), datetime(2007, 3, 30), False),
(BQuarterEnd(1, startingMonth=1), datetime(2007, 3, 31), False),
(BQuarterEnd(1, startingMonth=1), datetime(2008, 4, 30), True),
(BQuarterEnd(1, startingMonth=1), datetime(2008, 5, 30), False),
(BQuarterEnd(1, startingMonth=1), datetime(2007, 6, 29), False),
(BQuarterEnd(1, startingMonth=1), datetime(2007, 6, 30), False),
(BQuarterEnd(1, startingMonth=2), datetime(2008, 1, 31), False),
(BQuarterEnd(1, startingMonth=2), datetime(2007, 12, 31), False),
(BQuarterEnd(1, startingMonth=2), datetime(2008, 2, 29), True),
(BQuarterEnd(1, startingMonth=2), datetime(2007, 3, 30), False),
(BQuarterEnd(1, startingMonth=2), datetime(2007, 3, 31), False),
(BQuarterEnd(1, startingMonth=2), datetime(2008, 4, 30), False),
(BQuarterEnd(1, startingMonth=2), datetime(2008, 5, 30), True),
(BQuarterEnd(1, startingMonth=2), datetime(2007, 6, 29), False),
(BQuarterEnd(1, startingMonth=2), datetime(2007, 6, 30), False),
(BQuarterEnd(1, startingMonth=3), datetime(2008, 1, 31), False),
(BQuarterEnd(1, startingMonth=3), datetime(2007, 12, 31), True),
(BQuarterEnd(1, startingMonth=3), datetime(2008, 2, 29), False),
(BQuarterEnd(1, startingMonth=3), datetime(2007, 3, 30), True),
(BQuarterEnd(1, startingMonth=3), datetime(2007, 3, 31), False),
(BQuarterEnd(1, startingMonth=3), datetime(2008, 4, 30), False),
(BQuarterEnd(1, startingMonth=3), datetime(2008, 5, 30), False),
(BQuarterEnd(1, startingMonth=3), datetime(2007, 6, 29), True),
(BQuarterEnd(1, startingMonth=3), datetime(2007, 6, 30), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)

View File

@ -0,0 +1,215 @@
"""
Tests for the following offsets:
- BYearBegin
- BYearEnd
"""
from __future__ import annotations
from datetime import datetime
import pytest
from pandas.tests.tseries.offsets.common import (
assert_is_on_offset,
assert_offset_equal,
)
from pandas.tseries.offsets import (
BYearBegin,
BYearEnd,
)
class TestBYearBegin:
def test_misspecified(self):
msg = "Month must go from 1 to 12"
with pytest.raises(ValueError, match=msg):
BYearBegin(month=13)
with pytest.raises(ValueError, match=msg):
BYearEnd(month=13)
offset_cases = []
offset_cases.append(
(
BYearBegin(),
{
datetime(2008, 1, 1): datetime(2009, 1, 1),
datetime(2008, 6, 30): datetime(2009, 1, 1),
datetime(2008, 12, 31): datetime(2009, 1, 1),
datetime(2011, 1, 1): datetime(2011, 1, 3),
datetime(2011, 1, 3): datetime(2012, 1, 2),
datetime(2005, 12, 30): datetime(2006, 1, 2),
datetime(2005, 12, 31): datetime(2006, 1, 2),
},
)
)
offset_cases.append(
(
BYearBegin(0),
{
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2008, 6, 30): datetime(2009, 1, 1),
datetime(2008, 12, 31): datetime(2009, 1, 1),
datetime(2005, 12, 30): datetime(2006, 1, 2),
datetime(2005, 12, 31): datetime(2006, 1, 2),
},
)
)
offset_cases.append(
(
BYearBegin(-1),
{
datetime(2007, 1, 1): datetime(2006, 1, 2),
datetime(2009, 1, 4): datetime(2009, 1, 1),
datetime(2009, 1, 1): datetime(2008, 1, 1),
datetime(2008, 6, 30): datetime(2008, 1, 1),
datetime(2008, 12, 31): datetime(2008, 1, 1),
datetime(2006, 12, 29): datetime(2006, 1, 2),
datetime(2006, 12, 30): datetime(2006, 1, 2),
datetime(2006, 1, 1): datetime(2005, 1, 3),
},
)
)
offset_cases.append(
(
BYearBegin(-2),
{
datetime(2007, 1, 1): datetime(2005, 1, 3),
datetime(2007, 6, 30): datetime(2006, 1, 2),
datetime(2008, 12, 31): datetime(2007, 1, 1),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
class TestBYearEnd:
offset_cases = []
offset_cases.append(
(
BYearEnd(),
{
datetime(2008, 1, 1): datetime(2008, 12, 31),
datetime(2008, 6, 30): datetime(2008, 12, 31),
datetime(2008, 12, 31): datetime(2009, 12, 31),
datetime(2005, 12, 30): datetime(2006, 12, 29),
datetime(2005, 12, 31): datetime(2006, 12, 29),
},
)
)
offset_cases.append(
(
BYearEnd(0),
{
datetime(2008, 1, 1): datetime(2008, 12, 31),
datetime(2008, 6, 30): datetime(2008, 12, 31),
datetime(2008, 12, 31): datetime(2008, 12, 31),
datetime(2005, 12, 31): datetime(2006, 12, 29),
},
)
)
offset_cases.append(
(
BYearEnd(-1),
{
datetime(2007, 1, 1): datetime(2006, 12, 29),
datetime(2008, 6, 30): datetime(2007, 12, 31),
datetime(2008, 12, 31): datetime(2007, 12, 31),
datetime(2006, 12, 29): datetime(2005, 12, 30),
datetime(2006, 12, 30): datetime(2006, 12, 29),
datetime(2007, 1, 1): datetime(2006, 12, 29),
},
)
)
offset_cases.append(
(
BYearEnd(-2),
{
datetime(2007, 1, 1): datetime(2005, 12, 30),
datetime(2008, 6, 30): datetime(2006, 12, 29),
datetime(2008, 12, 31): datetime(2006, 12, 29),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
on_offset_cases = [
(BYearEnd(), datetime(2007, 12, 31), True),
(BYearEnd(), datetime(2008, 1, 1), False),
(BYearEnd(), datetime(2006, 12, 31), False),
(BYearEnd(), datetime(2006, 12, 29), True),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
class TestBYearEndLagged:
def test_bad_month_fail(self):
msg = "Month must go from 1 to 12"
with pytest.raises(ValueError, match=msg):
BYearEnd(month=13)
with pytest.raises(ValueError, match=msg):
BYearEnd(month=0)
offset_cases = []
offset_cases.append(
(
BYearEnd(month=6),
{
datetime(2008, 1, 1): datetime(2008, 6, 30),
datetime(2007, 6, 30): datetime(2008, 6, 30),
},
)
)
offset_cases.append(
(
BYearEnd(n=-1, month=6),
{
datetime(2008, 1, 1): datetime(2007, 6, 29),
datetime(2007, 6, 30): datetime(2007, 6, 29),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
def test_roll(self):
offset = BYearEnd(month=6)
date = datetime(2009, 11, 30)
assert offset.rollforward(date) == datetime(2010, 6, 30)
assert offset.rollback(date) == datetime(2009, 6, 30)
on_offset_cases = [
(BYearEnd(month=2), datetime(2007, 2, 28), True),
(BYearEnd(month=6), datetime(2007, 6, 30), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)

View File

@ -0,0 +1,268 @@
from datetime import datetime
from dateutil.tz.tz import tzlocal
import pytest
from pandas._libs.tslibs import (
OutOfBoundsDatetime,
Timestamp,
)
from pandas.compat import (
IS64,
is_platform_windows,
)
from pandas.tseries.offsets import (
FY5253,
BDay,
BMonthBegin,
BMonthEnd,
BQuarterBegin,
BQuarterEnd,
BusinessHour,
BYearBegin,
BYearEnd,
CBMonthBegin,
CBMonthEnd,
CDay,
CustomBusinessHour,
DateOffset,
FY5253Quarter,
LastWeekOfMonth,
MonthBegin,
MonthEnd,
QuarterEnd,
SemiMonthBegin,
SemiMonthEnd,
Week,
WeekOfMonth,
YearBegin,
YearEnd,
)
def _get_offset(klass, value=1, normalize=False):
# create instance from offset class
if klass is FY5253:
klass = klass(
n=value,
startingMonth=1,
weekday=1,
variation="last",
normalize=normalize,
)
elif klass is FY5253Quarter:
klass = klass(
n=value,
startingMonth=1,
weekday=1,
qtr_with_extra_week=1,
variation="last",
normalize=normalize,
)
elif klass is LastWeekOfMonth:
klass = klass(n=value, weekday=5, normalize=normalize)
elif klass is WeekOfMonth:
klass = klass(n=value, week=1, weekday=5, normalize=normalize)
elif klass is Week:
klass = klass(n=value, weekday=5, normalize=normalize)
elif klass is DateOffset:
klass = klass(days=value, normalize=normalize)
else:
klass = klass(value, normalize=normalize)
return klass
@pytest.fixture(
params=[
BDay,
BusinessHour,
BMonthEnd,
BMonthBegin,
BQuarterEnd,
BQuarterBegin,
BYearEnd,
BYearBegin,
CDay,
CustomBusinessHour,
CBMonthEnd,
CBMonthBegin,
MonthEnd,
MonthBegin,
SemiMonthBegin,
SemiMonthEnd,
QuarterEnd,
LastWeekOfMonth,
WeekOfMonth,
Week,
YearBegin,
YearEnd,
FY5253,
FY5253Quarter,
DateOffset,
]
)
def _offset(request):
return request.param
@pytest.fixture
def dt(_offset):
if _offset in (CBMonthBegin, CBMonthEnd, BDay):
return Timestamp(2008, 1, 1)
elif _offset is (CustomBusinessHour, BusinessHour):
return Timestamp(2014, 7, 1, 10, 00)
return Timestamp(2008, 1, 2)
def test_apply_out_of_range(request, tz_naive_fixture, _offset):
tz = tz_naive_fixture
# try to create an out-of-bounds result timestamp; if we can't create
# the offset skip
try:
if _offset in (BusinessHour, CustomBusinessHour):
# Using 10000 in BusinessHour fails in tz check because of DST
# difference
offset = _get_offset(_offset, value=100000)
else:
offset = _get_offset(_offset, value=10000)
result = Timestamp("20080101") + offset
assert isinstance(result, datetime)
assert result.tzinfo is None
# Check tz is preserved
t = Timestamp("20080101", tz=tz)
result = t + offset
assert isinstance(result, datetime)
if tz is not None:
assert t.tzinfo is not None
if isinstance(tz, tzlocal) and not IS64 and _offset is not DateOffset:
# If we hit OutOfBoundsDatetime on non-64 bit machines
# we'll drop out of the try clause before the next test
request.applymarker(
pytest.mark.xfail(reason="OverflowError inside tzlocal past 2038")
)
elif (
isinstance(tz, tzlocal)
and is_platform_windows()
and _offset in (QuarterEnd, BQuarterBegin, BQuarterEnd)
):
request.applymarker(
pytest.mark.xfail(reason="After GH#49737 t.tzinfo is None on CI")
)
assert str(t.tzinfo) == str(result.tzinfo)
except OutOfBoundsDatetime:
pass
except (ValueError, KeyError):
# we are creating an invalid offset
# so ignore
pass
def test_offsets_compare_equal(_offset):
# root cause of GH#456: __ne__ was not implemented
offset1 = _offset()
offset2 = _offset()
assert not offset1 != offset2
assert offset1 == offset2
@pytest.mark.parametrize(
"date, offset2",
[
[Timestamp(2008, 1, 1), BDay(2)],
[Timestamp(2014, 7, 1, 10, 00), BusinessHour(n=3)],
[
Timestamp(2014, 7, 1, 10),
CustomBusinessHour(
holidays=["2014-06-27", Timestamp(2014, 6, 30), Timestamp("2014-07-02")]
),
],
[Timestamp(2008, 1, 2), SemiMonthEnd(2)],
[Timestamp(2008, 1, 2), SemiMonthBegin(2)],
[Timestamp(2008, 1, 2), Week(2)],
[Timestamp(2008, 1, 2), WeekOfMonth(2)],
[Timestamp(2008, 1, 2), LastWeekOfMonth(2)],
],
)
def test_rsub(date, offset2):
assert date - offset2 == (-offset2)._apply(date)
@pytest.mark.parametrize(
"date, offset2",
[
[Timestamp(2008, 1, 1), BDay(2)],
[Timestamp(2014, 7, 1, 10, 00), BusinessHour(n=3)],
[
Timestamp(2014, 7, 1, 10),
CustomBusinessHour(
holidays=["2014-06-27", Timestamp(2014, 6, 30), Timestamp("2014-07-02")]
),
],
[Timestamp(2008, 1, 2), SemiMonthEnd(2)],
[Timestamp(2008, 1, 2), SemiMonthBegin(2)],
[Timestamp(2008, 1, 2), Week(2)],
[Timestamp(2008, 1, 2), WeekOfMonth(2)],
[Timestamp(2008, 1, 2), LastWeekOfMonth(2)],
],
)
def test_radd(date, offset2):
assert date + offset2 == offset2 + date
@pytest.mark.parametrize(
"date, offset_box, offset2",
[
[Timestamp(2008, 1, 1), BDay, BDay(2)],
[Timestamp(2008, 1, 2), SemiMonthEnd, SemiMonthEnd(2)],
[Timestamp(2008, 1, 2), SemiMonthBegin, SemiMonthBegin(2)],
[Timestamp(2008, 1, 2), Week, Week(2)],
[Timestamp(2008, 1, 2), WeekOfMonth, WeekOfMonth(2)],
[Timestamp(2008, 1, 2), LastWeekOfMonth, LastWeekOfMonth(2)],
],
)
def test_sub(date, offset_box, offset2):
off = offset2
msg = "Cannot subtract datetime from offset"
with pytest.raises(TypeError, match=msg):
off - date
assert 2 * off - off == off
assert date - offset2 == date + offset_box(-2)
assert date - offset2 == date - (2 * off - off)
@pytest.mark.parametrize(
"offset_box, offset1",
[
[BDay, BDay()],
[LastWeekOfMonth, LastWeekOfMonth()],
[WeekOfMonth, WeekOfMonth()],
[Week, Week()],
[SemiMonthBegin, SemiMonthBegin()],
[SemiMonthEnd, SemiMonthEnd()],
[CustomBusinessHour, CustomBusinessHour(weekmask="Tue Wed Thu Fri")],
[BusinessHour, BusinessHour()],
],
)
def test_Mult1(offset_box, offset1):
dt = Timestamp(2008, 1, 2)
assert dt + 10 * offset1 == dt + offset_box(10)
assert dt + 5 * offset1 == dt + offset_box(5)
def test_compare_str(_offset):
# GH#23524
# comparing to strings that cannot be cast to DateOffsets should
# not raise for __eq__ or __ne__
off = _get_offset(_offset)
assert not off == "infer"
assert off != "foo"
# Note: inequalities are only implemented for Tick subclasses;
# tests for this are in test_ticks

View File

@ -0,0 +1,98 @@
"""
Tests for offsets.CustomBusinessDay / CDay
"""
from datetime import (
datetime,
timedelta,
)
import numpy as np
import pytest
from pandas._libs.tslibs.offsets import CDay
from pandas import (
_testing as tm,
read_pickle,
)
from pandas.tests.tseries.offsets.common import assert_offset_equal
from pandas.tseries.holiday import USFederalHolidayCalendar
@pytest.fixture
def offset():
return CDay()
@pytest.fixture
def offset2():
return CDay(2)
class TestCustomBusinessDay:
def test_repr(self, offset, offset2):
assert repr(offset) == "<CustomBusinessDay>"
assert repr(offset2) == "<2 * CustomBusinessDays>"
expected = "<BusinessDay: offset=datetime.timedelta(days=1)>"
assert repr(offset + timedelta(1)) == expected
def test_holidays(self):
# Define a TradingDay offset
holidays = ["2012-05-01", datetime(2013, 5, 1), np.datetime64("2014-05-01")]
tday = CDay(holidays=holidays)
for year in range(2012, 2015):
dt = datetime(year, 4, 30)
xp = datetime(year, 5, 2)
rs = dt + tday
assert rs == xp
def test_weekmask(self):
weekmask_saudi = "Sat Sun Mon Tue Wed" # Thu-Fri Weekend
weekmask_uae = "1111001" # Fri-Sat Weekend
weekmask_egypt = [1, 1, 1, 1, 0, 0, 1] # Fri-Sat Weekend
bday_saudi = CDay(weekmask=weekmask_saudi)
bday_uae = CDay(weekmask=weekmask_uae)
bday_egypt = CDay(weekmask=weekmask_egypt)
dt = datetime(2013, 5, 1)
xp_saudi = datetime(2013, 5, 4)
xp_uae = datetime(2013, 5, 2)
xp_egypt = datetime(2013, 5, 2)
assert xp_saudi == dt + bday_saudi
assert xp_uae == dt + bday_uae
assert xp_egypt == dt + bday_egypt
xp2 = datetime(2013, 5, 5)
assert xp2 == dt + 2 * bday_saudi
assert xp2 == dt + 2 * bday_uae
assert xp2 == dt + 2 * bday_egypt
def test_weekmask_and_holidays(self):
weekmask_egypt = "Sun Mon Tue Wed Thu" # Fri-Sat Weekend
holidays = ["2012-05-01", datetime(2013, 5, 1), np.datetime64("2014-05-01")]
bday_egypt = CDay(holidays=holidays, weekmask=weekmask_egypt)
dt = datetime(2013, 4, 30)
xp_egypt = datetime(2013, 5, 5)
assert xp_egypt == dt + 2 * bday_egypt
@pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning")
def test_calendar(self):
calendar = USFederalHolidayCalendar()
dt = datetime(2014, 1, 17)
assert_offset_equal(CDay(calendar=calendar), dt, datetime(2014, 1, 21))
def test_roundtrip_pickle(self, offset, offset2):
def _check_roundtrip(obj):
unpickled = tm.round_trip_pickle(obj)
assert unpickled == obj
_check_roundtrip(offset)
_check_roundtrip(offset2)
_check_roundtrip(offset * 2)
def test_pickle_compat_0_14_1(self, datapath):
hdays = [datetime(2013, 1, 1) for ele in range(4)]
pth = datapath("tseries", "offsets", "data", "cday-0.14.1.pickle")
cday0_14_1 = read_pickle(pth)
cday = CDay(holidays=hdays)
assert cday == cday0_14_1

View File

@ -0,0 +1,329 @@
"""
Tests for offsets.CustomBusinessHour
"""
from __future__ import annotations
from datetime import (
datetime,
time as dt_time,
)
import numpy as np
import pytest
from pandas._libs.tslibs import Timestamp
from pandas._libs.tslibs.offsets import (
BusinessHour,
CustomBusinessHour,
Nano,
)
from pandas.tests.tseries.offsets.common import assert_offset_equal
from pandas.tseries.holiday import USFederalHolidayCalendar
holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")]
@pytest.fixture
def dt():
return datetime(2014, 7, 1, 10, 00)
@pytest.fixture
def _offset():
return CustomBusinessHour
# 2014 Calendar to check custom holidays
# Sun Mon Tue Wed Thu Fri Sat
# 6/22 23 24 25 26 27 28
# 29 30 7/1 2 3 4 5
# 6 7 8 9 10 11 12
@pytest.fixture
def offset1():
return CustomBusinessHour(weekmask="Tue Wed Thu Fri")
@pytest.fixture
def offset2():
return CustomBusinessHour(holidays=holidays)
class TestCustomBusinessHour:
def test_constructor_errors(self):
msg = "time data must be specified only with hour and minute"
with pytest.raises(ValueError, match=msg):
CustomBusinessHour(start=dt_time(11, 0, 5))
msg = "time data must match '%H:%M' format"
with pytest.raises(ValueError, match=msg):
CustomBusinessHour(start="AAA")
msg = "time data must match '%H:%M' format"
with pytest.raises(ValueError, match=msg):
CustomBusinessHour(start="14:00:05")
def test_different_normalize_equals(self, _offset):
# GH#21404 changed __eq__ to return False when `normalize` does not match
offset = _offset()
offset2 = _offset(normalize=True)
assert offset != offset2
def test_repr(self, offset1, offset2):
assert repr(offset1) == "<CustomBusinessHour: cbh=09:00-17:00>"
assert repr(offset2) == "<CustomBusinessHour: cbh=09:00-17:00>"
def test_with_offset(self, dt):
expected = Timestamp("2014-07-01 13:00")
assert dt + CustomBusinessHour() * 3 == expected
assert dt + CustomBusinessHour(n=3) == expected
def test_eq(self, offset1, offset2):
for offset in [offset1, offset2]:
assert offset == offset
assert CustomBusinessHour() != CustomBusinessHour(-1)
assert CustomBusinessHour(start="09:00") == CustomBusinessHour()
assert CustomBusinessHour(start="09:00") != CustomBusinessHour(start="09:01")
assert CustomBusinessHour(start="09:00", end="17:00") != CustomBusinessHour(
start="17:00", end="09:01"
)
assert CustomBusinessHour(weekmask="Tue Wed Thu Fri") != CustomBusinessHour(
weekmask="Mon Tue Wed Thu Fri"
)
assert CustomBusinessHour(holidays=["2014-06-27"]) != CustomBusinessHour(
holidays=["2014-06-28"]
)
def test_hash(self, offset1, offset2):
assert hash(offset1) == hash(offset1)
assert hash(offset2) == hash(offset2)
def test_add_dateime(self, dt, offset1, offset2):
assert offset1 + dt == datetime(2014, 7, 1, 11)
assert offset2 + dt == datetime(2014, 7, 1, 11)
def testRollback1(self, dt, offset1, offset2):
assert offset1.rollback(dt) == dt
assert offset2.rollback(dt) == dt
d = datetime(2014, 7, 1, 0)
# 2014/07/01 is Tuesday, 06/30 is Monday(holiday)
assert offset1.rollback(d) == datetime(2014, 6, 27, 17)
# 2014/6/30 and 2014/6/27 are holidays
assert offset2.rollback(d) == datetime(2014, 6, 26, 17)
def testRollback2(self, _offset):
assert _offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime(
2014, 7, 4, 17, 0
)
def testRollforward1(self, dt, offset1, offset2):
assert offset1.rollforward(dt) == dt
assert offset2.rollforward(dt) == dt
d = datetime(2014, 7, 1, 0)
assert offset1.rollforward(d) == datetime(2014, 7, 1, 9)
assert offset2.rollforward(d) == datetime(2014, 7, 1, 9)
def testRollforward2(self, _offset):
assert _offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime(
2014, 7, 7, 9
)
def test_roll_date_object(self):
offset = BusinessHour()
dt = datetime(2014, 7, 6, 15, 0)
result = offset.rollback(dt)
assert result == datetime(2014, 7, 4, 17)
result = offset.rollforward(dt)
assert result == datetime(2014, 7, 7, 9)
normalize_cases = [
(
CustomBusinessHour(normalize=True, holidays=holidays),
{
datetime(2014, 7, 1, 8): datetime(2014, 7, 1),
datetime(2014, 7, 1, 17): datetime(2014, 7, 3),
datetime(2014, 7, 1, 16): datetime(2014, 7, 3),
datetime(2014, 7, 1, 23): datetime(2014, 7, 3),
datetime(2014, 7, 1, 0): datetime(2014, 7, 1),
datetime(2014, 7, 4, 15): datetime(2014, 7, 4),
datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4),
datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7),
datetime(2014, 7, 5, 23): datetime(2014, 7, 7),
datetime(2014, 7, 6, 10): datetime(2014, 7, 7),
},
),
(
CustomBusinessHour(-1, normalize=True, holidays=holidays),
{
datetime(2014, 7, 1, 8): datetime(2014, 6, 26),
datetime(2014, 7, 1, 17): datetime(2014, 7, 1),
datetime(2014, 7, 1, 16): datetime(2014, 7, 1),
datetime(2014, 7, 1, 10): datetime(2014, 6, 26),
datetime(2014, 7, 1, 0): datetime(2014, 6, 26),
datetime(2014, 7, 7, 10): datetime(2014, 7, 4),
datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7),
datetime(2014, 7, 5, 23): datetime(2014, 7, 4),
datetime(2014, 7, 6, 10): datetime(2014, 7, 4),
},
),
(
CustomBusinessHour(
1, normalize=True, start="17:00", end="04:00", holidays=holidays
),
{
datetime(2014, 7, 1, 8): datetime(2014, 7, 1),
datetime(2014, 7, 1, 17): datetime(2014, 7, 1),
datetime(2014, 7, 1, 23): datetime(2014, 7, 2),
datetime(2014, 7, 2, 2): datetime(2014, 7, 2),
datetime(2014, 7, 2, 3): datetime(2014, 7, 3),
datetime(2014, 7, 4, 23): datetime(2014, 7, 5),
datetime(2014, 7, 5, 2): datetime(2014, 7, 5),
datetime(2014, 7, 7, 2): datetime(2014, 7, 7),
datetime(2014, 7, 7, 17): datetime(2014, 7, 7),
},
),
]
@pytest.mark.parametrize("norm_cases", normalize_cases)
def test_normalize(self, norm_cases):
offset, cases = norm_cases
for dt, expected in cases.items():
assert offset._apply(dt) == expected
@pytest.mark.parametrize(
"dt, expected",
[
[datetime(2014, 7, 1, 9), False],
[datetime(2014, 7, 1, 10), True],
[datetime(2014, 7, 1, 15), True],
[datetime(2014, 7, 1, 15, 1), False],
[datetime(2014, 7, 5, 12), False],
[datetime(2014, 7, 6, 12), False],
],
)
def test_is_on_offset(self, dt, expected):
offset = CustomBusinessHour(start="10:00", end="15:00", holidays=holidays)
assert offset.is_on_offset(dt) == expected
apply_cases = [
(
CustomBusinessHour(holidays=holidays),
{
datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12),
datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14),
datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16),
datetime(2014, 7, 1, 19): datetime(2014, 7, 3, 10),
datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 9),
datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 3, 9, 30, 15),
datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 10),
datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 10),
# out of business hours
datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 10),
datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10),
datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10),
datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10),
# saturday
datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10),
datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10),
datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30),
datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30),
},
),
(
CustomBusinessHour(4, holidays=holidays),
{
datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15),
datetime(2014, 7, 1, 13): datetime(2014, 7, 3, 9),
datetime(2014, 7, 1, 15): datetime(2014, 7, 3, 11),
datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 12),
datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 13),
datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 13),
datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 13),
datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13),
datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13),
datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13),
datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13),
datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13),
datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30),
datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30),
},
),
]
@pytest.mark.parametrize("apply_case", apply_cases)
def test_apply(self, apply_case):
offset, cases = apply_case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
nano_cases = [
(
CustomBusinessHour(holidays=holidays),
{
Timestamp("2014-07-01 15:00")
+ Nano(5): Timestamp("2014-07-01 16:00")
+ Nano(5),
Timestamp("2014-07-01 16:00")
+ Nano(5): Timestamp("2014-07-03 09:00")
+ Nano(5),
Timestamp("2014-07-01 16:00")
- Nano(5): Timestamp("2014-07-01 17:00")
- Nano(5),
},
),
(
CustomBusinessHour(-1, holidays=holidays),
{
Timestamp("2014-07-01 15:00")
+ Nano(5): Timestamp("2014-07-01 14:00")
+ Nano(5),
Timestamp("2014-07-01 10:00")
+ Nano(5): Timestamp("2014-07-01 09:00")
+ Nano(5),
Timestamp("2014-07-01 10:00")
- Nano(5): Timestamp("2014-06-26 17:00")
- Nano(5),
},
),
]
@pytest.mark.parametrize("nano_case", nano_cases)
def test_apply_nanoseconds(self, nano_case):
offset, cases = nano_case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
def test_us_federal_holiday_with_datetime(self):
# GH 16867
bhour_us = CustomBusinessHour(calendar=USFederalHolidayCalendar())
t0 = datetime(2014, 1, 17, 15)
result = t0 + bhour_us * 8
expected = Timestamp("2014-01-21 15:00:00")
assert result == expected
@pytest.mark.parametrize(
"weekmask, expected_time, mult",
[
["Mon Tue Wed Thu Fri Sat", "2018-11-10 09:00:00", 10],
["Tue Wed Thu Fri Sat", "2018-11-13 08:00:00", 18],
],
)
def test_custom_businesshour_weekmask_and_holidays(weekmask, expected_time, mult):
# GH 23542
holidays = ["2018-11-09"]
bh = CustomBusinessHour(
start="08:00", end="17:00", weekmask=weekmask, holidays=holidays
)
result = Timestamp("2018-11-08 08:00") + mult * bh
expected = Timestamp(expected_time)
assert result == expected

View File

@ -0,0 +1,437 @@
"""
Tests for the following offsets:
- CustomBusinessMonthBase
- CustomBusinessMonthBegin
- CustomBusinessMonthEnd
"""
from __future__ import annotations
from datetime import (
date,
datetime,
timedelta,
)
import numpy as np
import pytest
from pandas._libs.tslibs.offsets import (
CBMonthBegin,
CBMonthEnd,
CDay,
)
import pandas._testing as tm
from pandas.tests.tseries.offsets.common import (
assert_is_on_offset,
assert_offset_equal,
)
from pandas.tseries import offsets
@pytest.fixture
def dt():
return datetime(2008, 1, 1)
class TestCommonCBM:
@pytest.mark.parametrize("offset2", [CBMonthBegin(2), CBMonthEnd(2)])
def test_eq(self, offset2):
assert offset2 == offset2
@pytest.mark.parametrize("offset2", [CBMonthBegin(2), CBMonthEnd(2)])
def test_hash(self, offset2):
assert hash(offset2) == hash(offset2)
@pytest.mark.parametrize("_offset", [CBMonthBegin, CBMonthEnd])
def test_roundtrip_pickle(self, _offset):
def _check_roundtrip(obj):
unpickled = tm.round_trip_pickle(obj)
assert unpickled == obj
_check_roundtrip(_offset())
_check_roundtrip(_offset(2))
_check_roundtrip(_offset() * 2)
@pytest.mark.parametrize("_offset", [CBMonthBegin, CBMonthEnd])
def test_copy(self, _offset):
# GH 17452
off = _offset(weekmask="Mon Wed Fri")
assert off == off.copy()
class TestCustomBusinessMonthBegin:
@pytest.fixture
def _offset(self):
return CBMonthBegin
@pytest.fixture
def offset(self):
return CBMonthBegin()
@pytest.fixture
def offset2(self):
return CBMonthBegin(2)
def test_different_normalize_equals(self, _offset):
# GH#21404 changed __eq__ to return False when `normalize` does not match
offset = _offset()
offset2 = _offset(normalize=True)
assert offset != offset2
def test_repr(self, offset, offset2):
assert repr(offset) == "<CustomBusinessMonthBegin>"
assert repr(offset2) == "<2 * CustomBusinessMonthBegins>"
def test_add_datetime(self, dt, offset2):
assert offset2 + dt == datetime(2008, 3, 3)
def testRollback1(self):
assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31)
def testRollback2(self, dt):
assert CBMonthBegin(10).rollback(dt) == datetime(2008, 1, 1)
def testRollforward1(self, dt):
assert CBMonthBegin(10).rollforward(dt) == datetime(2008, 1, 1)
def test_roll_date_object(self):
offset = CBMonthBegin()
dt = date(2012, 9, 15)
result = offset.rollback(dt)
assert result == datetime(2012, 9, 3)
result = offset.rollforward(dt)
assert result == datetime(2012, 10, 1)
offset = offsets.Day()
result = offset.rollback(dt)
assert result == datetime(2012, 9, 15)
result = offset.rollforward(dt)
assert result == datetime(2012, 9, 15)
on_offset_cases = [
(CBMonthBegin(), datetime(2008, 1, 1), True),
(CBMonthBegin(), datetime(2008, 1, 31), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
apply_cases = [
(
CBMonthBegin(),
{
datetime(2008, 1, 1): datetime(2008, 2, 1),
datetime(2008, 2, 7): datetime(2008, 3, 3),
},
),
(
2 * CBMonthBegin(),
{
datetime(2008, 1, 1): datetime(2008, 3, 3),
datetime(2008, 2, 7): datetime(2008, 4, 1),
},
),
(
-CBMonthBegin(),
{
datetime(2008, 1, 1): datetime(2007, 12, 3),
datetime(2008, 2, 8): datetime(2008, 2, 1),
},
),
(
-2 * CBMonthBegin(),
{
datetime(2008, 1, 1): datetime(2007, 11, 1),
datetime(2008, 2, 9): datetime(2008, 1, 1),
},
),
(
CBMonthBegin(0),
{
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2008, 1, 7): datetime(2008, 2, 1),
},
),
]
@pytest.mark.parametrize("case", apply_cases)
def test_apply(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
def test_apply_large_n(self):
dt = datetime(2012, 10, 23)
result = dt + CBMonthBegin(10)
assert result == datetime(2013, 8, 1)
result = dt + CDay(100) - CDay(100)
assert result == dt
off = CBMonthBegin() * 6
rs = datetime(2012, 1, 1) - off
xp = datetime(2011, 7, 1)
assert rs == xp
st = datetime(2011, 12, 18)
rs = st + off
xp = datetime(2012, 6, 1)
assert rs == xp
def test_holidays(self):
# Define a TradingDay offset
holidays = ["2012-02-01", datetime(2012, 2, 2), np.datetime64("2012-03-01")]
bm_offset = CBMonthBegin(holidays=holidays)
dt = datetime(2012, 1, 1)
assert dt + bm_offset == datetime(2012, 1, 2)
assert dt + 2 * bm_offset == datetime(2012, 2, 3)
@pytest.mark.parametrize(
"case",
[
(
CBMonthBegin(n=1, offset=timedelta(days=5)),
{
datetime(2021, 3, 1): datetime(2021, 4, 1) + timedelta(days=5),
datetime(2021, 4, 17): datetime(2021, 5, 3) + timedelta(days=5),
},
),
(
CBMonthBegin(n=2, offset=timedelta(days=40)),
{
datetime(2021, 3, 10): datetime(2021, 5, 3) + timedelta(days=40),
datetime(2021, 4, 30): datetime(2021, 6, 1) + timedelta(days=40),
},
),
(
CBMonthBegin(n=1, offset=timedelta(days=-5)),
{
datetime(2021, 3, 1): datetime(2021, 4, 1) - timedelta(days=5),
datetime(2021, 4, 11): datetime(2021, 5, 3) - timedelta(days=5),
},
),
(
-2 * CBMonthBegin(n=1, offset=timedelta(days=10)),
{
datetime(2021, 3, 1): datetime(2021, 1, 1) + timedelta(days=10),
datetime(2021, 4, 3): datetime(2021, 3, 1) + timedelta(days=10),
},
),
(
CBMonthBegin(n=0, offset=timedelta(days=1)),
{
datetime(2021, 3, 2): datetime(2021, 4, 1) + timedelta(days=1),
datetime(2021, 4, 1): datetime(2021, 4, 1) + timedelta(days=1),
},
),
(
CBMonthBegin(
n=1, holidays=["2021-04-01", "2021-04-02"], offset=timedelta(days=1)
),
{
datetime(2021, 3, 2): datetime(2021, 4, 5) + timedelta(days=1),
},
),
],
)
def test_apply_with_extra_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
class TestCustomBusinessMonthEnd:
@pytest.fixture
def _offset(self):
return CBMonthEnd
@pytest.fixture
def offset(self):
return CBMonthEnd()
@pytest.fixture
def offset2(self):
return CBMonthEnd(2)
def test_different_normalize_equals(self, _offset):
# GH#21404 changed __eq__ to return False when `normalize` does not match
offset = _offset()
offset2 = _offset(normalize=True)
assert offset != offset2
def test_repr(self, offset, offset2):
assert repr(offset) == "<CustomBusinessMonthEnd>"
assert repr(offset2) == "<2 * CustomBusinessMonthEnds>"
def test_add_datetime(self, dt, offset2):
assert offset2 + dt == datetime(2008, 2, 29)
def testRollback1(self):
assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31)
def testRollback2(self, dt):
assert CBMonthEnd(10).rollback(dt) == datetime(2007, 12, 31)
def testRollforward1(self, dt):
assert CBMonthEnd(10).rollforward(dt) == datetime(2008, 1, 31)
def test_roll_date_object(self):
offset = CBMonthEnd()
dt = date(2012, 9, 15)
result = offset.rollback(dt)
assert result == datetime(2012, 8, 31)
result = offset.rollforward(dt)
assert result == datetime(2012, 9, 28)
offset = offsets.Day()
result = offset.rollback(dt)
assert result == datetime(2012, 9, 15)
result = offset.rollforward(dt)
assert result == datetime(2012, 9, 15)
on_offset_cases = [
(CBMonthEnd(), datetime(2008, 1, 31), True),
(CBMonthEnd(), datetime(2008, 1, 1), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
apply_cases = [
(
CBMonthEnd(),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 2, 7): datetime(2008, 2, 29),
},
),
(
2 * CBMonthEnd(),
{
datetime(2008, 1, 1): datetime(2008, 2, 29),
datetime(2008, 2, 7): datetime(2008, 3, 31),
},
),
(
-CBMonthEnd(),
{
datetime(2008, 1, 1): datetime(2007, 12, 31),
datetime(2008, 2, 8): datetime(2008, 1, 31),
},
),
(
-2 * CBMonthEnd(),
{
datetime(2008, 1, 1): datetime(2007, 11, 30),
datetime(2008, 2, 9): datetime(2007, 12, 31),
},
),
(
CBMonthEnd(0),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 2, 7): datetime(2008, 2, 29),
},
),
]
@pytest.mark.parametrize("case", apply_cases)
def test_apply(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
def test_apply_large_n(self):
dt = datetime(2012, 10, 23)
result = dt + CBMonthEnd(10)
assert result == datetime(2013, 7, 31)
result = dt + CDay(100) - CDay(100)
assert result == dt
off = CBMonthEnd() * 6
rs = datetime(2012, 1, 1) - off
xp = datetime(2011, 7, 29)
assert rs == xp
st = datetime(2011, 12, 18)
rs = st + off
xp = datetime(2012, 5, 31)
assert rs == xp
def test_holidays(self):
# Define a TradingDay offset
holidays = ["2012-01-31", datetime(2012, 2, 28), np.datetime64("2012-02-29")]
bm_offset = CBMonthEnd(holidays=holidays)
dt = datetime(2012, 1, 1)
assert dt + bm_offset == datetime(2012, 1, 30)
assert dt + 2 * bm_offset == datetime(2012, 2, 27)
@pytest.mark.parametrize(
"case",
[
(
CBMonthEnd(n=1, offset=timedelta(days=5)),
{
datetime(2021, 3, 1): datetime(2021, 3, 31) + timedelta(days=5),
datetime(2021, 4, 17): datetime(2021, 4, 30) + timedelta(days=5),
},
),
(
CBMonthEnd(n=2, offset=timedelta(days=40)),
{
datetime(2021, 3, 10): datetime(2021, 4, 30) + timedelta(days=40),
datetime(2021, 4, 30): datetime(2021, 6, 30) + timedelta(days=40),
},
),
(
CBMonthEnd(n=1, offset=timedelta(days=-5)),
{
datetime(2021, 3, 1): datetime(2021, 3, 31) - timedelta(days=5),
datetime(2021, 4, 11): datetime(2021, 4, 30) - timedelta(days=5),
},
),
(
-2 * CBMonthEnd(n=1, offset=timedelta(days=10)),
{
datetime(2021, 3, 1): datetime(2021, 1, 29) + timedelta(days=10),
datetime(2021, 4, 3): datetime(2021, 2, 26) + timedelta(days=10),
},
),
(
CBMonthEnd(n=0, offset=timedelta(days=1)),
{
datetime(2021, 3, 2): datetime(2021, 3, 31) + timedelta(days=1),
datetime(2021, 4, 1): datetime(2021, 4, 30) + timedelta(days=1),
},
),
(
CBMonthEnd(n=1, holidays=["2021-03-31"], offset=timedelta(days=1)),
{
datetime(2021, 3, 2): datetime(2021, 3, 30) + timedelta(days=1),
},
),
],
)
def test_apply_with_extra_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)

View File

@ -0,0 +1,260 @@
"""
Tests for DateOffset additions over Daylight Savings Time
"""
from datetime import timedelta
import pytest
import pytz
from pandas._libs.tslibs import Timestamp
from pandas._libs.tslibs.offsets import (
BMonthBegin,
BMonthEnd,
BQuarterBegin,
BQuarterEnd,
BYearBegin,
BYearEnd,
CBMonthBegin,
CBMonthEnd,
CustomBusinessDay,
DateOffset,
Day,
MonthBegin,
MonthEnd,
QuarterBegin,
QuarterEnd,
SemiMonthBegin,
SemiMonthEnd,
Week,
YearBegin,
YearEnd,
)
from pandas.errors import PerformanceWarning
from pandas import DatetimeIndex
import pandas._testing as tm
from pandas.util.version import Version
# error: Module has no attribute "__version__"
pytz_version = Version(pytz.__version__) # type: ignore[attr-defined]
def get_utc_offset_hours(ts):
# take a Timestamp and compute total hours of utc offset
o = ts.utcoffset()
return (o.days * 24 * 3600 + o.seconds) / 3600.0
class TestDST:
# one microsecond before the DST transition
ts_pre_fallback = "2013-11-03 01:59:59.999999"
ts_pre_springfwd = "2013-03-10 01:59:59.999999"
# test both basic names and dateutil timezones
timezone_utc_offsets = {
"US/Eastern": {"utc_offset_daylight": -4, "utc_offset_standard": -5},
"dateutil/US/Pacific": {"utc_offset_daylight": -7, "utc_offset_standard": -8},
}
valid_date_offsets_singular = [
"weekday",
"day",
"hour",
"minute",
"second",
"microsecond",
]
valid_date_offsets_plural = [
"weeks",
"days",
"hours",
"minutes",
"seconds",
"milliseconds",
"microseconds",
]
def _test_all_offsets(self, n, **kwds):
valid_offsets = (
self.valid_date_offsets_plural
if n > 1
else self.valid_date_offsets_singular
)
for name in valid_offsets:
self._test_offset(offset_name=name, offset_n=n, **kwds)
def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset):
offset = DateOffset(**{offset_name: offset_n})
if (
offset_name in ["hour", "minute", "second", "microsecond"]
and offset_n == 1
and tstart == Timestamp("2013-11-03 01:59:59.999999-0500", tz="US/Eastern")
):
# This addition results in an ambiguous wall time
err_msg = {
"hour": "2013-11-03 01:59:59.999999",
"minute": "2013-11-03 01:01:59.999999",
"second": "2013-11-03 01:59:01.999999",
"microsecond": "2013-11-03 01:59:59.000001",
}[offset_name]
with pytest.raises(pytz.AmbiguousTimeError, match=err_msg):
tstart + offset
# While we're here, let's check that we get the same behavior in a
# vectorized path
dti = DatetimeIndex([tstart])
warn_msg = "Non-vectorized DateOffset"
with pytest.raises(pytz.AmbiguousTimeError, match=err_msg):
with tm.assert_produces_warning(PerformanceWarning, match=warn_msg):
dti + offset
return
t = tstart + offset
if expected_utc_offset is not None:
assert get_utc_offset_hours(t) == expected_utc_offset
if offset_name == "weeks":
# dates should match
assert t.date() == timedelta(days=7 * offset.kwds["weeks"]) + tstart.date()
# expect the same day of week, hour of day, minute, second, ...
assert (
t.dayofweek == tstart.dayofweek
and t.hour == tstart.hour
and t.minute == tstart.minute
and t.second == tstart.second
)
elif offset_name == "days":
# dates should match
assert timedelta(offset.kwds["days"]) + tstart.date() == t.date()
# expect the same hour of day, minute, second, ...
assert (
t.hour == tstart.hour
and t.minute == tstart.minute
and t.second == tstart.second
)
elif offset_name in self.valid_date_offsets_singular:
# expect the singular offset value to match between tstart and t
datepart_offset = getattr(
t, offset_name if offset_name != "weekday" else "dayofweek"
)
assert datepart_offset == offset.kwds[offset_name]
else:
# the offset should be the same as if it was done in UTC
assert t == (tstart.tz_convert("UTC") + offset).tz_convert("US/Pacific")
def _make_timestamp(self, string, hrs_offset, tz):
if hrs_offset >= 0:
offset_string = f"{hrs_offset:02d}00"
else:
offset_string = f"-{(hrs_offset * -1):02}00"
return Timestamp(string + offset_string).tz_convert(tz)
def test_springforward_plural(self):
# test moving from standard to daylight savings
for tz, utc_offsets in self.timezone_utc_offsets.items():
hrs_pre = utc_offsets["utc_offset_standard"]
hrs_post = utc_offsets["utc_offset_daylight"]
self._test_all_offsets(
n=3,
tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz),
expected_utc_offset=hrs_post,
)
def test_fallback_singular(self):
# in the case of singular offsets, we don't necessarily know which utc
# offset the new Timestamp will wind up in (the tz for 1 month may be
# different from 1 second) so we don't specify an expected_utc_offset
for tz, utc_offsets in self.timezone_utc_offsets.items():
hrs_pre = utc_offsets["utc_offset_standard"]
self._test_all_offsets(
n=1,
tstart=self._make_timestamp(self.ts_pre_fallback, hrs_pre, tz),
expected_utc_offset=None,
)
def test_springforward_singular(self):
for tz, utc_offsets in self.timezone_utc_offsets.items():
hrs_pre = utc_offsets["utc_offset_standard"]
self._test_all_offsets(
n=1,
tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz),
expected_utc_offset=None,
)
offset_classes = {
MonthBegin: ["11/2/2012", "12/1/2012"],
MonthEnd: ["11/2/2012", "11/30/2012"],
BMonthBegin: ["11/2/2012", "12/3/2012"],
BMonthEnd: ["11/2/2012", "11/30/2012"],
CBMonthBegin: ["11/2/2012", "12/3/2012"],
CBMonthEnd: ["11/2/2012", "11/30/2012"],
SemiMonthBegin: ["11/2/2012", "11/15/2012"],
SemiMonthEnd: ["11/2/2012", "11/15/2012"],
Week: ["11/2/2012", "11/9/2012"],
YearBegin: ["11/2/2012", "1/1/2013"],
YearEnd: ["11/2/2012", "12/31/2012"],
BYearBegin: ["11/2/2012", "1/1/2013"],
BYearEnd: ["11/2/2012", "12/31/2012"],
QuarterBegin: ["11/2/2012", "12/1/2012"],
QuarterEnd: ["11/2/2012", "12/31/2012"],
BQuarterBegin: ["11/2/2012", "12/3/2012"],
BQuarterEnd: ["11/2/2012", "12/31/2012"],
Day: ["11/4/2012", "11/4/2012 23:00"],
}.items()
@pytest.mark.parametrize("tup", offset_classes)
def test_all_offset_classes(self, tup):
offset, test_values = tup
first = Timestamp(test_values[0], tz="US/Eastern") + offset()
second = Timestamp(test_values[1], tz="US/Eastern")
assert first == second
@pytest.mark.parametrize(
"original_dt, target_dt, offset, tz",
[
pytest.param(
Timestamp("1900-01-01"),
Timestamp("1905-07-01"),
MonthBegin(66),
"Africa/Lagos",
marks=pytest.mark.xfail(
pytz_version < Version("2020.5") or pytz_version == Version("2022.2"),
reason="GH#41906: pytz utc transition dates changed",
),
),
(
Timestamp("2021-10-01 01:15"),
Timestamp("2021-10-31 01:15"),
MonthEnd(1),
"Europe/London",
),
(
Timestamp("2010-12-05 02:59"),
Timestamp("2010-10-31 02:59"),
SemiMonthEnd(-3),
"Europe/Paris",
),
(
Timestamp("2021-10-31 01:20"),
Timestamp("2021-11-07 01:20"),
CustomBusinessDay(2, weekmask="Sun Mon"),
"US/Eastern",
),
(
Timestamp("2020-04-03 01:30"),
Timestamp("2020-11-01 01:30"),
YearBegin(1, month=11),
"America/Chicago",
),
],
)
def test_nontick_offset_with_ambiguous_time_error(original_dt, target_dt, offset, tz):
# .apply for non-Tick offsets throws AmbiguousTimeError when the target dt
# is dst-ambiguous
localized_dt = original_dt.tz_localize(tz)
msg = f"Cannot infer dst time from {target_dt}, try using the 'ambiguous' argument"
with pytest.raises(pytz.AmbiguousTimeError, match=msg):
localized_dt + offset

View File

@ -0,0 +1,33 @@
"""
Tests for the following offsets:
- Easter
"""
from __future__ import annotations
from datetime import datetime
import pytest
from pandas.tests.tseries.offsets.common import assert_offset_equal
from pandas.tseries.offsets import Easter
class TestEaster:
@pytest.mark.parametrize(
"offset,date,expected",
[
(Easter(), datetime(2010, 1, 1), datetime(2010, 4, 4)),
(Easter(), datetime(2010, 4, 5), datetime(2011, 4, 24)),
(Easter(2), datetime(2010, 1, 1), datetime(2011, 4, 24)),
(Easter(), datetime(2010, 4, 4), datetime(2011, 4, 24)),
(Easter(2), datetime(2010, 4, 4), datetime(2012, 4, 8)),
(-Easter(), datetime(2011, 1, 1), datetime(2010, 4, 4)),
(-Easter(), datetime(2010, 4, 5), datetime(2010, 4, 4)),
(-Easter(2), datetime(2011, 1, 1), datetime(2009, 4, 12)),
(-Easter(), datetime(2010, 4, 4), datetime(2009, 4, 12)),
(-Easter(2), datetime(2010, 4, 4), datetime(2008, 3, 23)),
],
)
def test_offset(self, offset, date, expected):
assert_offset_equal(offset, date, expected)

View File

@ -0,0 +1,656 @@
"""
Tests for Fiscal Year and Fiscal Quarter offset classes
"""
from datetime import datetime
from dateutil.relativedelta import relativedelta
import pytest
from pandas import Timestamp
import pandas._testing as tm
from pandas.tests.tseries.offsets.common import (
WeekDay,
assert_is_on_offset,
assert_offset_equal,
)
from pandas.tseries.offsets import (
FY5253,
FY5253Quarter,
)
def makeFY5253LastOfMonthQuarter(*args, **kwds):
return FY5253Quarter(*args, variation="last", **kwds)
def makeFY5253NearestEndMonthQuarter(*args, **kwds):
return FY5253Quarter(*args, variation="nearest", **kwds)
def makeFY5253NearestEndMonth(*args, **kwds):
return FY5253(*args, variation="nearest", **kwds)
def makeFY5253LastOfMonth(*args, **kwds):
return FY5253(*args, variation="last", **kwds)
def test_get_offset_name():
assert (
makeFY5253LastOfMonthQuarter(
weekday=1, startingMonth=3, qtr_with_extra_week=4
).freqstr
== "REQ-L-MAR-TUE-4"
)
assert (
makeFY5253NearestEndMonthQuarter(
weekday=1, startingMonth=3, qtr_with_extra_week=3
).freqstr
== "REQ-N-MAR-TUE-3"
)
class TestFY5253LastOfMonth:
offset_lom_sat_aug = makeFY5253LastOfMonth(1, startingMonth=8, weekday=WeekDay.SAT)
offset_lom_sat_sep = makeFY5253LastOfMonth(1, startingMonth=9, weekday=WeekDay.SAT)
on_offset_cases = [
# From Wikipedia (see:
# https://en.wikipedia.org/wiki/4%E2%80%934%E2%80%935_calendar#Last_Saturday_of_the_month_at_fiscal_year_end)
(offset_lom_sat_aug, datetime(2006, 8, 26), True),
(offset_lom_sat_aug, datetime(2007, 8, 25), True),
(offset_lom_sat_aug, datetime(2008, 8, 30), True),
(offset_lom_sat_aug, datetime(2009, 8, 29), True),
(offset_lom_sat_aug, datetime(2010, 8, 28), True),
(offset_lom_sat_aug, datetime(2011, 8, 27), True),
(offset_lom_sat_aug, datetime(2012, 8, 25), True),
(offset_lom_sat_aug, datetime(2013, 8, 31), True),
(offset_lom_sat_aug, datetime(2014, 8, 30), True),
(offset_lom_sat_aug, datetime(2015, 8, 29), True),
(offset_lom_sat_aug, datetime(2016, 8, 27), True),
(offset_lom_sat_aug, datetime(2017, 8, 26), True),
(offset_lom_sat_aug, datetime(2018, 8, 25), True),
(offset_lom_sat_aug, datetime(2019, 8, 31), True),
(offset_lom_sat_aug, datetime(2006, 8, 27), False),
(offset_lom_sat_aug, datetime(2007, 8, 28), False),
(offset_lom_sat_aug, datetime(2008, 8, 31), False),
(offset_lom_sat_aug, datetime(2009, 8, 30), False),
(offset_lom_sat_aug, datetime(2010, 8, 29), False),
(offset_lom_sat_aug, datetime(2011, 8, 28), False),
(offset_lom_sat_aug, datetime(2006, 8, 25), False),
(offset_lom_sat_aug, datetime(2007, 8, 24), False),
(offset_lom_sat_aug, datetime(2008, 8, 29), False),
(offset_lom_sat_aug, datetime(2009, 8, 28), False),
(offset_lom_sat_aug, datetime(2010, 8, 27), False),
(offset_lom_sat_aug, datetime(2011, 8, 26), False),
(offset_lom_sat_aug, datetime(2019, 8, 30), False),
# From GMCR (see for example:
# http://yahoo.brand.edgar-online.com/Default.aspx?
# companyid=3184&formtypeID=7)
(offset_lom_sat_sep, datetime(2010, 9, 25), True),
(offset_lom_sat_sep, datetime(2011, 9, 24), True),
(offset_lom_sat_sep, datetime(2012, 9, 29), True),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
def test_apply(self):
offset_lom_aug_sat = makeFY5253LastOfMonth(startingMonth=8, weekday=WeekDay.SAT)
offset_lom_aug_sat_1 = makeFY5253LastOfMonth(
n=1, startingMonth=8, weekday=WeekDay.SAT
)
date_seq_lom_aug_sat = [
datetime(2006, 8, 26),
datetime(2007, 8, 25),
datetime(2008, 8, 30),
datetime(2009, 8, 29),
datetime(2010, 8, 28),
datetime(2011, 8, 27),
datetime(2012, 8, 25),
datetime(2013, 8, 31),
datetime(2014, 8, 30),
datetime(2015, 8, 29),
datetime(2016, 8, 27),
]
tests = [
(offset_lom_aug_sat, date_seq_lom_aug_sat),
(offset_lom_aug_sat_1, date_seq_lom_aug_sat),
(offset_lom_aug_sat, [datetime(2006, 8, 25)] + date_seq_lom_aug_sat),
(offset_lom_aug_sat_1, [datetime(2006, 8, 27)] + date_seq_lom_aug_sat[1:]),
(
makeFY5253LastOfMonth(n=-1, startingMonth=8, weekday=WeekDay.SAT),
list(reversed(date_seq_lom_aug_sat)),
),
]
for test in tests:
offset, data = test
current = data[0]
for datum in data[1:]:
current = current + offset
assert current == datum
class TestFY5253NearestEndMonth:
def test_get_year_end(self):
assert makeFY5253NearestEndMonth(
startingMonth=8, weekday=WeekDay.SAT
).get_year_end(datetime(2013, 1, 1)) == datetime(2013, 8, 31)
assert makeFY5253NearestEndMonth(
startingMonth=8, weekday=WeekDay.SUN
).get_year_end(datetime(2013, 1, 1)) == datetime(2013, 9, 1)
assert makeFY5253NearestEndMonth(
startingMonth=8, weekday=WeekDay.FRI
).get_year_end(datetime(2013, 1, 1)) == datetime(2013, 8, 30)
offset_n = FY5253(weekday=WeekDay.TUE, startingMonth=12, variation="nearest")
assert offset_n.get_year_end(datetime(2012, 1, 1)) == datetime(2013, 1, 1)
assert offset_n.get_year_end(datetime(2012, 1, 10)) == datetime(2013, 1, 1)
assert offset_n.get_year_end(datetime(2013, 1, 1)) == datetime(2013, 12, 31)
assert offset_n.get_year_end(datetime(2013, 1, 2)) == datetime(2013, 12, 31)
assert offset_n.get_year_end(datetime(2013, 1, 3)) == datetime(2013, 12, 31)
assert offset_n.get_year_end(datetime(2013, 1, 10)) == datetime(2013, 12, 31)
JNJ = FY5253(n=1, startingMonth=12, weekday=6, variation="nearest")
assert JNJ.get_year_end(datetime(2006, 1, 1)) == datetime(2006, 12, 31)
offset_lom_aug_sat = makeFY5253NearestEndMonth(
1, startingMonth=8, weekday=WeekDay.SAT
)
offset_lom_aug_thu = makeFY5253NearestEndMonth(
1, startingMonth=8, weekday=WeekDay.THU
)
offset_n = FY5253(weekday=WeekDay.TUE, startingMonth=12, variation="nearest")
on_offset_cases = [
# From Wikipedia (see:
# https://en.wikipedia.org/wiki/4%E2%80%934%E2%80%935_calendar
# #Saturday_nearest_the_end_of_month)
# 2006-09-02 2006 September 2
# 2007-09-01 2007 September 1
# 2008-08-30 2008 August 30 (leap year)
# 2009-08-29 2009 August 29
# 2010-08-28 2010 August 28
# 2011-09-03 2011 September 3
# 2012-09-01 2012 September 1 (leap year)
# 2013-08-31 2013 August 31
# 2014-08-30 2014 August 30
# 2015-08-29 2015 August 29
# 2016-09-03 2016 September 3 (leap year)
# 2017-09-02 2017 September 2
# 2018-09-01 2018 September 1
# 2019-08-31 2019 August 31
(offset_lom_aug_sat, datetime(2006, 9, 2), True),
(offset_lom_aug_sat, datetime(2007, 9, 1), True),
(offset_lom_aug_sat, datetime(2008, 8, 30), True),
(offset_lom_aug_sat, datetime(2009, 8, 29), True),
(offset_lom_aug_sat, datetime(2010, 8, 28), True),
(offset_lom_aug_sat, datetime(2011, 9, 3), True),
(offset_lom_aug_sat, datetime(2016, 9, 3), True),
(offset_lom_aug_sat, datetime(2017, 9, 2), True),
(offset_lom_aug_sat, datetime(2018, 9, 1), True),
(offset_lom_aug_sat, datetime(2019, 8, 31), True),
(offset_lom_aug_sat, datetime(2006, 8, 27), False),
(offset_lom_aug_sat, datetime(2007, 8, 28), False),
(offset_lom_aug_sat, datetime(2008, 8, 31), False),
(offset_lom_aug_sat, datetime(2009, 8, 30), False),
(offset_lom_aug_sat, datetime(2010, 8, 29), False),
(offset_lom_aug_sat, datetime(2011, 8, 28), False),
(offset_lom_aug_sat, datetime(2006, 8, 25), False),
(offset_lom_aug_sat, datetime(2007, 8, 24), False),
(offset_lom_aug_sat, datetime(2008, 8, 29), False),
(offset_lom_aug_sat, datetime(2009, 8, 28), False),
(offset_lom_aug_sat, datetime(2010, 8, 27), False),
(offset_lom_aug_sat, datetime(2011, 8, 26), False),
(offset_lom_aug_sat, datetime(2019, 8, 30), False),
# From Micron, see:
# http://google.brand.edgar-online.com/?sym=MU&formtypeID=7
(offset_lom_aug_thu, datetime(2012, 8, 30), True),
(offset_lom_aug_thu, datetime(2011, 9, 1), True),
(offset_n, datetime(2012, 12, 31), False),
(offset_n, datetime(2013, 1, 1), True),
(offset_n, datetime(2013, 1, 2), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
def test_apply(self):
date_seq_nem_8_sat = [
datetime(2006, 9, 2),
datetime(2007, 9, 1),
datetime(2008, 8, 30),
datetime(2009, 8, 29),
datetime(2010, 8, 28),
datetime(2011, 9, 3),
]
JNJ = [
datetime(2005, 1, 2),
datetime(2006, 1, 1),
datetime(2006, 12, 31),
datetime(2007, 12, 30),
datetime(2008, 12, 28),
datetime(2010, 1, 3),
datetime(2011, 1, 2),
datetime(2012, 1, 1),
datetime(2012, 12, 30),
]
DEC_SAT = FY5253(n=-1, startingMonth=12, weekday=5, variation="nearest")
tests = [
(
makeFY5253NearestEndMonth(startingMonth=8, weekday=WeekDay.SAT),
date_seq_nem_8_sat,
),
(
makeFY5253NearestEndMonth(n=1, startingMonth=8, weekday=WeekDay.SAT),
date_seq_nem_8_sat,
),
(
makeFY5253NearestEndMonth(startingMonth=8, weekday=WeekDay.SAT),
[datetime(2006, 9, 1)] + date_seq_nem_8_sat,
),
(
makeFY5253NearestEndMonth(n=1, startingMonth=8, weekday=WeekDay.SAT),
[datetime(2006, 9, 3)] + date_seq_nem_8_sat[1:],
),
(
makeFY5253NearestEndMonth(n=-1, startingMonth=8, weekday=WeekDay.SAT),
list(reversed(date_seq_nem_8_sat)),
),
(
makeFY5253NearestEndMonth(n=1, startingMonth=12, weekday=WeekDay.SUN),
JNJ,
),
(
makeFY5253NearestEndMonth(n=-1, startingMonth=12, weekday=WeekDay.SUN),
list(reversed(JNJ)),
),
(
makeFY5253NearestEndMonth(n=1, startingMonth=12, weekday=WeekDay.SUN),
[datetime(2005, 1, 2), datetime(2006, 1, 1)],
),
(
makeFY5253NearestEndMonth(n=1, startingMonth=12, weekday=WeekDay.SUN),
[datetime(2006, 1, 2), datetime(2006, 12, 31)],
),
(DEC_SAT, [datetime(2013, 1, 15), datetime(2012, 12, 29)]),
]
for test in tests:
offset, data = test
current = data[0]
for datum in data[1:]:
current = current + offset
assert current == datum
class TestFY5253LastOfMonthQuarter:
def test_is_anchored(self):
msg = "FY5253Quarter.is_anchored is deprecated "
with tm.assert_produces_warning(FutureWarning, match=msg):
assert makeFY5253LastOfMonthQuarter(
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
).is_anchored()
assert makeFY5253LastOfMonthQuarter(
weekday=WeekDay.SAT, startingMonth=3, qtr_with_extra_week=4
).is_anchored()
assert not makeFY5253LastOfMonthQuarter(
2, startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
).is_anchored()
def test_equality(self):
assert makeFY5253LastOfMonthQuarter(
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
) == makeFY5253LastOfMonthQuarter(
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
assert makeFY5253LastOfMonthQuarter(
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
) != makeFY5253LastOfMonthQuarter(
startingMonth=1, weekday=WeekDay.SUN, qtr_with_extra_week=4
)
assert makeFY5253LastOfMonthQuarter(
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
) != makeFY5253LastOfMonthQuarter(
startingMonth=2, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
def test_offset(self):
offset = makeFY5253LastOfMonthQuarter(
1, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
offset2 = makeFY5253LastOfMonthQuarter(
2, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
offset4 = makeFY5253LastOfMonthQuarter(
4, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
offset_neg1 = makeFY5253LastOfMonthQuarter(
-1, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
offset_neg2 = makeFY5253LastOfMonthQuarter(
-2, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
GMCR = [
datetime(2010, 3, 27),
datetime(2010, 6, 26),
datetime(2010, 9, 25),
datetime(2010, 12, 25),
datetime(2011, 3, 26),
datetime(2011, 6, 25),
datetime(2011, 9, 24),
datetime(2011, 12, 24),
datetime(2012, 3, 24),
datetime(2012, 6, 23),
datetime(2012, 9, 29),
datetime(2012, 12, 29),
datetime(2013, 3, 30),
datetime(2013, 6, 29),
]
assert_offset_equal(offset, base=GMCR[0], expected=GMCR[1])
assert_offset_equal(
offset, base=GMCR[0] + relativedelta(days=-1), expected=GMCR[0]
)
assert_offset_equal(offset, base=GMCR[1], expected=GMCR[2])
assert_offset_equal(offset2, base=GMCR[0], expected=GMCR[2])
assert_offset_equal(offset4, base=GMCR[0], expected=GMCR[4])
assert_offset_equal(offset_neg1, base=GMCR[-1], expected=GMCR[-2])
assert_offset_equal(
offset_neg1, base=GMCR[-1] + relativedelta(days=+1), expected=GMCR[-1]
)
assert_offset_equal(offset_neg2, base=GMCR[-1], expected=GMCR[-3])
date = GMCR[0] + relativedelta(days=-1)
for expected in GMCR:
assert_offset_equal(offset, date, expected)
date = date + offset
date = GMCR[-1] + relativedelta(days=+1)
for expected in reversed(GMCR):
assert_offset_equal(offset_neg1, date, expected)
date = date + offset_neg1
lomq_aug_sat_4 = makeFY5253LastOfMonthQuarter(
1, startingMonth=8, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
lomq_sep_sat_4 = makeFY5253LastOfMonthQuarter(
1, startingMonth=9, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
on_offset_cases = [
# From Wikipedia
(lomq_aug_sat_4, datetime(2006, 8, 26), True),
(lomq_aug_sat_4, datetime(2007, 8, 25), True),
(lomq_aug_sat_4, datetime(2008, 8, 30), True),
(lomq_aug_sat_4, datetime(2009, 8, 29), True),
(lomq_aug_sat_4, datetime(2010, 8, 28), True),
(lomq_aug_sat_4, datetime(2011, 8, 27), True),
(lomq_aug_sat_4, datetime(2019, 8, 31), True),
(lomq_aug_sat_4, datetime(2006, 8, 27), False),
(lomq_aug_sat_4, datetime(2007, 8, 28), False),
(lomq_aug_sat_4, datetime(2008, 8, 31), False),
(lomq_aug_sat_4, datetime(2009, 8, 30), False),
(lomq_aug_sat_4, datetime(2010, 8, 29), False),
(lomq_aug_sat_4, datetime(2011, 8, 28), False),
(lomq_aug_sat_4, datetime(2006, 8, 25), False),
(lomq_aug_sat_4, datetime(2007, 8, 24), False),
(lomq_aug_sat_4, datetime(2008, 8, 29), False),
(lomq_aug_sat_4, datetime(2009, 8, 28), False),
(lomq_aug_sat_4, datetime(2010, 8, 27), False),
(lomq_aug_sat_4, datetime(2011, 8, 26), False),
(lomq_aug_sat_4, datetime(2019, 8, 30), False),
# From GMCR
(lomq_sep_sat_4, datetime(2010, 9, 25), True),
(lomq_sep_sat_4, datetime(2011, 9, 24), True),
(lomq_sep_sat_4, datetime(2012, 9, 29), True),
(lomq_sep_sat_4, datetime(2013, 6, 29), True),
(lomq_sep_sat_4, datetime(2012, 6, 23), True),
(lomq_sep_sat_4, datetime(2012, 6, 30), False),
(lomq_sep_sat_4, datetime(2013, 3, 30), True),
(lomq_sep_sat_4, datetime(2012, 3, 24), True),
(lomq_sep_sat_4, datetime(2012, 12, 29), True),
(lomq_sep_sat_4, datetime(2011, 12, 24), True),
# INTC (extra week in Q1)
# See: http://www.intc.com/releasedetail.cfm?ReleaseID=542844
(
makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
),
datetime(2011, 4, 2),
True,
),
# see: http://google.brand.edgar-online.com/?sym=INTC&formtypeID=7
(
makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
),
datetime(2012, 12, 29),
True,
),
(
makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
),
datetime(2011, 12, 31),
True,
),
(
makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
),
datetime(2010, 12, 25),
True,
),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
def test_year_has_extra_week(self):
# End of long Q1
assert makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
).year_has_extra_week(datetime(2011, 4, 2))
# Start of long Q1
assert makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
).year_has_extra_week(datetime(2010, 12, 26))
# End of year before year with long Q1
assert not makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
).year_has_extra_week(datetime(2010, 12, 25))
for year in [
x for x in range(1994, 2011 + 1) if x not in [2011, 2005, 2000, 1994]
]:
assert not makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
).year_has_extra_week(datetime(year, 4, 2))
# Other long years
assert makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
).year_has_extra_week(datetime(2005, 4, 2))
assert makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
).year_has_extra_week(datetime(2000, 4, 2))
assert makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
).year_has_extra_week(datetime(1994, 4, 2))
def test_get_weeks(self):
sat_dec_1 = makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
)
sat_dec_4 = makeFY5253LastOfMonthQuarter(
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
assert sat_dec_1.get_weeks(datetime(2011, 4, 2)) == [14, 13, 13, 13]
assert sat_dec_4.get_weeks(datetime(2011, 4, 2)) == [13, 13, 13, 14]
assert sat_dec_1.get_weeks(datetime(2010, 12, 25)) == [13, 13, 13, 13]
class TestFY5253NearestEndMonthQuarter:
offset_nem_sat_aug_4 = makeFY5253NearestEndMonthQuarter(
1, startingMonth=8, weekday=WeekDay.SAT, qtr_with_extra_week=4
)
offset_nem_thu_aug_4 = makeFY5253NearestEndMonthQuarter(
1, startingMonth=8, weekday=WeekDay.THU, qtr_with_extra_week=4
)
offset_n = FY5253(weekday=WeekDay.TUE, startingMonth=12, variation="nearest")
on_offset_cases = [
# From Wikipedia
(offset_nem_sat_aug_4, datetime(2006, 9, 2), True),
(offset_nem_sat_aug_4, datetime(2007, 9, 1), True),
(offset_nem_sat_aug_4, datetime(2008, 8, 30), True),
(offset_nem_sat_aug_4, datetime(2009, 8, 29), True),
(offset_nem_sat_aug_4, datetime(2010, 8, 28), True),
(offset_nem_sat_aug_4, datetime(2011, 9, 3), True),
(offset_nem_sat_aug_4, datetime(2016, 9, 3), True),
(offset_nem_sat_aug_4, datetime(2017, 9, 2), True),
(offset_nem_sat_aug_4, datetime(2018, 9, 1), True),
(offset_nem_sat_aug_4, datetime(2019, 8, 31), True),
(offset_nem_sat_aug_4, datetime(2006, 8, 27), False),
(offset_nem_sat_aug_4, datetime(2007, 8, 28), False),
(offset_nem_sat_aug_4, datetime(2008, 8, 31), False),
(offset_nem_sat_aug_4, datetime(2009, 8, 30), False),
(offset_nem_sat_aug_4, datetime(2010, 8, 29), False),
(offset_nem_sat_aug_4, datetime(2011, 8, 28), False),
(offset_nem_sat_aug_4, datetime(2006, 8, 25), False),
(offset_nem_sat_aug_4, datetime(2007, 8, 24), False),
(offset_nem_sat_aug_4, datetime(2008, 8, 29), False),
(offset_nem_sat_aug_4, datetime(2009, 8, 28), False),
(offset_nem_sat_aug_4, datetime(2010, 8, 27), False),
(offset_nem_sat_aug_4, datetime(2011, 8, 26), False),
(offset_nem_sat_aug_4, datetime(2019, 8, 30), False),
# From Micron, see:
# http://google.brand.edgar-online.com/?sym=MU&formtypeID=7
(offset_nem_thu_aug_4, datetime(2012, 8, 30), True),
(offset_nem_thu_aug_4, datetime(2011, 9, 1), True),
# See: http://google.brand.edgar-online.com/?sym=MU&formtypeID=13
(offset_nem_thu_aug_4, datetime(2013, 5, 30), True),
(offset_nem_thu_aug_4, datetime(2013, 2, 28), True),
(offset_nem_thu_aug_4, datetime(2012, 11, 29), True),
(offset_nem_thu_aug_4, datetime(2012, 5, 31), True),
(offset_nem_thu_aug_4, datetime(2007, 3, 1), True),
(offset_nem_thu_aug_4, datetime(1994, 3, 3), True),
(offset_n, datetime(2012, 12, 31), False),
(offset_n, datetime(2013, 1, 1), True),
(offset_n, datetime(2013, 1, 2), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
def test_offset(self):
offset = makeFY5253NearestEndMonthQuarter(
1, startingMonth=8, weekday=WeekDay.THU, qtr_with_extra_week=4
)
MU = [
datetime(2012, 5, 31),
datetime(2012, 8, 30),
datetime(2012, 11, 29),
datetime(2013, 2, 28),
datetime(2013, 5, 30),
]
date = MU[0] + relativedelta(days=-1)
for expected in MU:
assert_offset_equal(offset, date, expected)
date = date + offset
assert_offset_equal(offset, datetime(2012, 5, 31), datetime(2012, 8, 30))
assert_offset_equal(offset, datetime(2012, 5, 30), datetime(2012, 5, 31))
offset2 = FY5253Quarter(
weekday=5, startingMonth=12, variation="last", qtr_with_extra_week=4
)
assert_offset_equal(offset2, datetime(2013, 1, 15), datetime(2013, 3, 30))
def test_bunched_yearends():
# GH#14774 cases with two fiscal year-ends in the same calendar-year
fy = FY5253(n=1, weekday=5, startingMonth=12, variation="nearest")
dt = Timestamp("2004-01-01")
assert fy.rollback(dt) == Timestamp("2002-12-28")
assert (-fy)._apply(dt) == Timestamp("2002-12-28")
assert dt - fy == Timestamp("2002-12-28")
assert fy.rollforward(dt) == Timestamp("2004-01-03")
assert fy._apply(dt) == Timestamp("2004-01-03")
assert fy + dt == Timestamp("2004-01-03")
assert dt + fy == Timestamp("2004-01-03")
# Same thing, but starting from a Timestamp in the previous year.
dt = Timestamp("2003-12-31")
assert fy.rollback(dt) == Timestamp("2002-12-28")
assert (-fy)._apply(dt) == Timestamp("2002-12-28")
assert dt - fy == Timestamp("2002-12-28")
def test_fy5253_last_onoffset():
# GH#18877 dates on the year-end but not normalized to midnight
offset = FY5253(n=-5, startingMonth=5, variation="last", weekday=0)
ts = Timestamp("1984-05-28 06:29:43.955911354+0200", tz="Europe/San_Marino")
fast = offset.is_on_offset(ts)
slow = (ts + offset) - offset == ts
assert fast == slow
def test_fy5253_nearest_onoffset():
# GH#18877 dates on the year-end but not normalized to midnight
offset = FY5253(n=3, startingMonth=7, variation="nearest", weekday=2)
ts = Timestamp("2032-07-28 00:12:59.035729419+0000", tz="Africa/Dakar")
fast = offset.is_on_offset(ts)
slow = (ts + offset) - offset == ts
assert fast == slow
def test_fy5253qtr_onoffset_nearest():
# GH#19036
ts = Timestamp("1985-09-02 23:57:46.232550356-0300", tz="Atlantic/Bermuda")
offset = FY5253Quarter(
n=3, qtr_with_extra_week=1, startingMonth=2, variation="nearest", weekday=0
)
fast = offset.is_on_offset(ts)
slow = (ts + offset) - offset == ts
assert fast == slow
def test_fy5253qtr_onoffset_last():
# GH#19036
offset = FY5253Quarter(
n=-2, qtr_with_extra_week=1, startingMonth=7, variation="last", weekday=2
)
ts = Timestamp("2011-01-26 19:03:40.331096129+0200", tz="Africa/Windhoek")
slow = (ts + offset) - offset == ts
fast = offset.is_on_offset(ts)
assert fast == slow

View File

@ -0,0 +1,57 @@
"""
Tests for offset behavior with indices.
"""
import pytest
from pandas import (
Series,
date_range,
)
from pandas.tseries.offsets import (
BMonthBegin,
BMonthEnd,
BQuarterBegin,
BQuarterEnd,
BYearBegin,
BYearEnd,
MonthBegin,
MonthEnd,
QuarterBegin,
QuarterEnd,
YearBegin,
YearEnd,
)
@pytest.mark.parametrize("n", [-2, 1])
@pytest.mark.parametrize(
"cls",
[
MonthBegin,
MonthEnd,
BMonthBegin,
BMonthEnd,
QuarterBegin,
QuarterEnd,
BQuarterBegin,
BQuarterEnd,
YearBegin,
YearEnd,
BYearBegin,
BYearEnd,
],
)
def test_apply_index(cls, n):
offset = cls(n=n)
rng = date_range(start="1/1/2000", periods=100000, freq="min")
ser = Series(rng)
res = rng + offset
assert res.freq is None # not retained
assert res[0] == rng[0] + offset
assert res[-1] == rng[-1] + offset
res2 = ser + offset
# apply_index is only for indexes, not series, so no res2_v2
assert res2.iloc[0] == ser.iloc[0] + offset
assert res2.iloc[-1] == ser.iloc[-1] + offset

View File

@ -0,0 +1,666 @@
"""
Tests for the following offsets:
- SemiMonthBegin
- SemiMonthEnd
- MonthBegin
- MonthEnd
"""
from __future__ import annotations
from datetime import datetime
import pytest
from pandas._libs.tslibs import Timestamp
from pandas._libs.tslibs.offsets import (
MonthBegin,
MonthEnd,
SemiMonthBegin,
SemiMonthEnd,
)
from pandas import (
DatetimeIndex,
Series,
_testing as tm,
)
from pandas.tests.tseries.offsets.common import (
assert_is_on_offset,
assert_offset_equal,
)
class TestSemiMonthEnd:
def test_offset_whole_year(self):
dates = (
datetime(2007, 12, 31),
datetime(2008, 1, 15),
datetime(2008, 1, 31),
datetime(2008, 2, 15),
datetime(2008, 2, 29),
datetime(2008, 3, 15),
datetime(2008, 3, 31),
datetime(2008, 4, 15),
datetime(2008, 4, 30),
datetime(2008, 5, 15),
datetime(2008, 5, 31),
datetime(2008, 6, 15),
datetime(2008, 6, 30),
datetime(2008, 7, 15),
datetime(2008, 7, 31),
datetime(2008, 8, 15),
datetime(2008, 8, 31),
datetime(2008, 9, 15),
datetime(2008, 9, 30),
datetime(2008, 10, 15),
datetime(2008, 10, 31),
datetime(2008, 11, 15),
datetime(2008, 11, 30),
datetime(2008, 12, 15),
datetime(2008, 12, 31),
)
for base, exp_date in zip(dates[:-1], dates[1:]):
assert_offset_equal(SemiMonthEnd(), base, exp_date)
# ensure .apply_index works as expected
shift = DatetimeIndex(dates[:-1])
with tm.assert_produces_warning(None):
# GH#22535 check that we don't get a FutureWarning from adding
# an integer array to PeriodIndex
result = SemiMonthEnd() + shift
exp = DatetimeIndex(dates[1:])
tm.assert_index_equal(result, exp)
offset_cases = []
offset_cases.append(
(
SemiMonthEnd(),
{
datetime(2008, 1, 1): datetime(2008, 1, 15),
datetime(2008, 1, 15): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 2, 15),
datetime(2006, 12, 14): datetime(2006, 12, 15),
datetime(2006, 12, 29): datetime(2006, 12, 31),
datetime(2006, 12, 31): datetime(2007, 1, 15),
datetime(2007, 1, 1): datetime(2007, 1, 15),
datetime(2006, 12, 1): datetime(2006, 12, 15),
datetime(2006, 12, 15): datetime(2006, 12, 31),
},
)
)
offset_cases.append(
(
SemiMonthEnd(day_of_month=20),
{
datetime(2008, 1, 1): datetime(2008, 1, 20),
datetime(2008, 1, 15): datetime(2008, 1, 20),
datetime(2008, 1, 21): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 2, 20),
datetime(2006, 12, 14): datetime(2006, 12, 20),
datetime(2006, 12, 29): datetime(2006, 12, 31),
datetime(2006, 12, 31): datetime(2007, 1, 20),
datetime(2007, 1, 1): datetime(2007, 1, 20),
datetime(2006, 12, 1): datetime(2006, 12, 20),
datetime(2006, 12, 15): datetime(2006, 12, 20),
},
)
)
offset_cases.append(
(
SemiMonthEnd(0),
{
datetime(2008, 1, 1): datetime(2008, 1, 15),
datetime(2008, 1, 16): datetime(2008, 1, 31),
datetime(2008, 1, 15): datetime(2008, 1, 15),
datetime(2008, 1, 31): datetime(2008, 1, 31),
datetime(2006, 12, 29): datetime(2006, 12, 31),
datetime(2006, 12, 31): datetime(2006, 12, 31),
datetime(2007, 1, 1): datetime(2007, 1, 15),
},
)
)
offset_cases.append(
(
SemiMonthEnd(0, day_of_month=16),
{
datetime(2008, 1, 1): datetime(2008, 1, 16),
datetime(2008, 1, 16): datetime(2008, 1, 16),
datetime(2008, 1, 15): datetime(2008, 1, 16),
datetime(2008, 1, 31): datetime(2008, 1, 31),
datetime(2006, 12, 29): datetime(2006, 12, 31),
datetime(2006, 12, 31): datetime(2006, 12, 31),
datetime(2007, 1, 1): datetime(2007, 1, 16),
},
)
)
offset_cases.append(
(
SemiMonthEnd(2),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 2, 29),
datetime(2006, 12, 29): datetime(2007, 1, 15),
datetime(2006, 12, 31): datetime(2007, 1, 31),
datetime(2007, 1, 1): datetime(2007, 1, 31),
datetime(2007, 1, 16): datetime(2007, 2, 15),
datetime(2006, 11, 1): datetime(2006, 11, 30),
},
)
)
offset_cases.append(
(
SemiMonthEnd(-1),
{
datetime(2007, 1, 1): datetime(2006, 12, 31),
datetime(2008, 6, 30): datetime(2008, 6, 15),
datetime(2008, 12, 31): datetime(2008, 12, 15),
datetime(2006, 12, 29): datetime(2006, 12, 15),
datetime(2006, 12, 30): datetime(2006, 12, 15),
datetime(2007, 1, 1): datetime(2006, 12, 31),
},
)
)
offset_cases.append(
(
SemiMonthEnd(-1, day_of_month=4),
{
datetime(2007, 1, 1): datetime(2006, 12, 31),
datetime(2007, 1, 4): datetime(2006, 12, 31),
datetime(2008, 6, 30): datetime(2008, 6, 4),
datetime(2008, 12, 31): datetime(2008, 12, 4),
datetime(2006, 12, 5): datetime(2006, 12, 4),
datetime(2006, 12, 30): datetime(2006, 12, 4),
datetime(2007, 1, 1): datetime(2006, 12, 31),
},
)
)
offset_cases.append(
(
SemiMonthEnd(-2),
{
datetime(2007, 1, 1): datetime(2006, 12, 15),
datetime(2008, 6, 30): datetime(2008, 5, 31),
datetime(2008, 3, 15): datetime(2008, 2, 15),
datetime(2008, 12, 31): datetime(2008, 11, 30),
datetime(2006, 12, 29): datetime(2006, 11, 30),
datetime(2006, 12, 14): datetime(2006, 11, 15),
datetime(2007, 1, 1): datetime(2006, 12, 15),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
@pytest.mark.parametrize("case", offset_cases)
def test_apply_index(self, case):
# https://github.com/pandas-dev/pandas/issues/34580
offset, cases = case
shift = DatetimeIndex(cases.keys())
exp = DatetimeIndex(cases.values())
with tm.assert_produces_warning(None):
# GH#22535 check that we don't get a FutureWarning from adding
# an integer array to PeriodIndex
result = offset + shift
tm.assert_index_equal(result, exp)
on_offset_cases = [
(datetime(2007, 12, 31), True),
(datetime(2007, 12, 15), True),
(datetime(2007, 12, 14), False),
(datetime(2007, 12, 1), False),
(datetime(2008, 2, 29), True),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
dt, expected = case
assert_is_on_offset(SemiMonthEnd(), dt, expected)
@pytest.mark.parametrize("klass", [Series, DatetimeIndex])
def test_vectorized_offset_addition(self, klass):
shift = klass(
[
Timestamp("2000-01-15 00:15:00", tz="US/Central"),
Timestamp("2000-02-15", tz="US/Central"),
],
name="a",
)
with tm.assert_produces_warning(None):
# GH#22535 check that we don't get a FutureWarning from adding
# an integer array to PeriodIndex
result = shift + SemiMonthEnd()
result2 = SemiMonthEnd() + shift
exp = klass(
[
Timestamp("2000-01-31 00:15:00", tz="US/Central"),
Timestamp("2000-02-29", tz="US/Central"),
],
name="a",
)
tm.assert_equal(result, exp)
tm.assert_equal(result2, exp)
shift = klass(
[
Timestamp("2000-01-01 00:15:00", tz="US/Central"),
Timestamp("2000-02-01", tz="US/Central"),
],
name="a",
)
with tm.assert_produces_warning(None):
# GH#22535 check that we don't get a FutureWarning from adding
# an integer array to PeriodIndex
result = shift + SemiMonthEnd()
result2 = SemiMonthEnd() + shift
exp = klass(
[
Timestamp("2000-01-15 00:15:00", tz="US/Central"),
Timestamp("2000-02-15", tz="US/Central"),
],
name="a",
)
tm.assert_equal(result, exp)
tm.assert_equal(result2, exp)
class TestSemiMonthBegin:
def test_offset_whole_year(self):
dates = (
datetime(2007, 12, 15),
datetime(2008, 1, 1),
datetime(2008, 1, 15),
datetime(2008, 2, 1),
datetime(2008, 2, 15),
datetime(2008, 3, 1),
datetime(2008, 3, 15),
datetime(2008, 4, 1),
datetime(2008, 4, 15),
datetime(2008, 5, 1),
datetime(2008, 5, 15),
datetime(2008, 6, 1),
datetime(2008, 6, 15),
datetime(2008, 7, 1),
datetime(2008, 7, 15),
datetime(2008, 8, 1),
datetime(2008, 8, 15),
datetime(2008, 9, 1),
datetime(2008, 9, 15),
datetime(2008, 10, 1),
datetime(2008, 10, 15),
datetime(2008, 11, 1),
datetime(2008, 11, 15),
datetime(2008, 12, 1),
datetime(2008, 12, 15),
)
for base, exp_date in zip(dates[:-1], dates[1:]):
assert_offset_equal(SemiMonthBegin(), base, exp_date)
# ensure .apply_index works as expected
shift = DatetimeIndex(dates[:-1])
with tm.assert_produces_warning(None):
# GH#22535 check that we don't get a FutureWarning from adding
# an integer array to PeriodIndex
result = SemiMonthBegin() + shift
exp = DatetimeIndex(dates[1:])
tm.assert_index_equal(result, exp)
offset_cases = [
(
SemiMonthBegin(),
{
datetime(2008, 1, 1): datetime(2008, 1, 15),
datetime(2008, 1, 15): datetime(2008, 2, 1),
datetime(2008, 1, 31): datetime(2008, 2, 1),
datetime(2006, 12, 14): datetime(2006, 12, 15),
datetime(2006, 12, 29): datetime(2007, 1, 1),
datetime(2006, 12, 31): datetime(2007, 1, 1),
datetime(2007, 1, 1): datetime(2007, 1, 15),
datetime(2006, 12, 1): datetime(2006, 12, 15),
datetime(2006, 12, 15): datetime(2007, 1, 1),
},
),
(
SemiMonthBegin(day_of_month=20),
{
datetime(2008, 1, 1): datetime(2008, 1, 20),
datetime(2008, 1, 15): datetime(2008, 1, 20),
datetime(2008, 1, 21): datetime(2008, 2, 1),
datetime(2008, 1, 31): datetime(2008, 2, 1),
datetime(2006, 12, 14): datetime(2006, 12, 20),
datetime(2006, 12, 29): datetime(2007, 1, 1),
datetime(2006, 12, 31): datetime(2007, 1, 1),
datetime(2007, 1, 1): datetime(2007, 1, 20),
datetime(2006, 12, 1): datetime(2006, 12, 20),
datetime(2006, 12, 15): datetime(2006, 12, 20),
},
),
(
SemiMonthBegin(0),
{
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2008, 1, 16): datetime(2008, 2, 1),
datetime(2008, 1, 15): datetime(2008, 1, 15),
datetime(2008, 1, 31): datetime(2008, 2, 1),
datetime(2006, 12, 29): datetime(2007, 1, 1),
datetime(2006, 12, 2): datetime(2006, 12, 15),
datetime(2007, 1, 1): datetime(2007, 1, 1),
},
),
(
SemiMonthBegin(0, day_of_month=16),
{
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2008, 1, 16): datetime(2008, 1, 16),
datetime(2008, 1, 15): datetime(2008, 1, 16),
datetime(2008, 1, 31): datetime(2008, 2, 1),
datetime(2006, 12, 29): datetime(2007, 1, 1),
datetime(2006, 12, 31): datetime(2007, 1, 1),
datetime(2007, 1, 5): datetime(2007, 1, 16),
datetime(2007, 1, 1): datetime(2007, 1, 1),
},
),
(
SemiMonthBegin(2),
{
datetime(2008, 1, 1): datetime(2008, 2, 1),
datetime(2008, 1, 31): datetime(2008, 2, 15),
datetime(2006, 12, 1): datetime(2007, 1, 1),
datetime(2006, 12, 29): datetime(2007, 1, 15),
datetime(2006, 12, 15): datetime(2007, 1, 15),
datetime(2007, 1, 1): datetime(2007, 2, 1),
datetime(2007, 1, 16): datetime(2007, 2, 15),
datetime(2006, 11, 1): datetime(2006, 12, 1),
},
),
(
SemiMonthBegin(-1),
{
datetime(2007, 1, 1): datetime(2006, 12, 15),
datetime(2008, 6, 30): datetime(2008, 6, 15),
datetime(2008, 6, 14): datetime(2008, 6, 1),
datetime(2008, 12, 31): datetime(2008, 12, 15),
datetime(2006, 12, 29): datetime(2006, 12, 15),
datetime(2006, 12, 15): datetime(2006, 12, 1),
datetime(2007, 1, 1): datetime(2006, 12, 15),
},
),
(
SemiMonthBegin(-1, day_of_month=4),
{
datetime(2007, 1, 1): datetime(2006, 12, 4),
datetime(2007, 1, 4): datetime(2007, 1, 1),
datetime(2008, 6, 30): datetime(2008, 6, 4),
datetime(2008, 12, 31): datetime(2008, 12, 4),
datetime(2006, 12, 5): datetime(2006, 12, 4),
datetime(2006, 12, 30): datetime(2006, 12, 4),
datetime(2006, 12, 2): datetime(2006, 12, 1),
datetime(2007, 1, 1): datetime(2006, 12, 4),
},
),
(
SemiMonthBegin(-2),
{
datetime(2007, 1, 1): datetime(2006, 12, 1),
datetime(2008, 6, 30): datetime(2008, 6, 1),
datetime(2008, 6, 14): datetime(2008, 5, 15),
datetime(2008, 12, 31): datetime(2008, 12, 1),
datetime(2006, 12, 29): datetime(2006, 12, 1),
datetime(2006, 12, 15): datetime(2006, 11, 15),
datetime(2007, 1, 1): datetime(2006, 12, 1),
},
),
]
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
@pytest.mark.parametrize("case", offset_cases)
def test_apply_index(self, case):
offset, cases = case
shift = DatetimeIndex(cases.keys())
with tm.assert_produces_warning(None):
# GH#22535 check that we don't get a FutureWarning from adding
# an integer array to PeriodIndex
result = offset + shift
exp = DatetimeIndex(cases.values())
tm.assert_index_equal(result, exp)
on_offset_cases = [
(datetime(2007, 12, 1), True),
(datetime(2007, 12, 15), True),
(datetime(2007, 12, 14), False),
(datetime(2007, 12, 31), False),
(datetime(2008, 2, 15), True),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
dt, expected = case
assert_is_on_offset(SemiMonthBegin(), dt, expected)
@pytest.mark.parametrize("klass", [Series, DatetimeIndex])
def test_vectorized_offset_addition(self, klass):
shift = klass(
[
Timestamp("2000-01-15 00:15:00", tz="US/Central"),
Timestamp("2000-02-15", tz="US/Central"),
],
name="a",
)
with tm.assert_produces_warning(None):
# GH#22535 check that we don't get a FutureWarning from adding
# an integer array to PeriodIndex
result = shift + SemiMonthBegin()
result2 = SemiMonthBegin() + shift
exp = klass(
[
Timestamp("2000-02-01 00:15:00", tz="US/Central"),
Timestamp("2000-03-01", tz="US/Central"),
],
name="a",
)
tm.assert_equal(result, exp)
tm.assert_equal(result2, exp)
shift = klass(
[
Timestamp("2000-01-01 00:15:00", tz="US/Central"),
Timestamp("2000-02-01", tz="US/Central"),
],
name="a",
)
with tm.assert_produces_warning(None):
# GH#22535 check that we don't get a FutureWarning from adding
# an integer array to PeriodIndex
result = shift + SemiMonthBegin()
result2 = SemiMonthBegin() + shift
exp = klass(
[
Timestamp("2000-01-15 00:15:00", tz="US/Central"),
Timestamp("2000-02-15", tz="US/Central"),
],
name="a",
)
tm.assert_equal(result, exp)
tm.assert_equal(result2, exp)
class TestMonthBegin:
offset_cases = []
# NOTE: I'm not entirely happy with the logic here for Begin -ss
# see thread 'offset conventions' on the ML
offset_cases.append(
(
MonthBegin(),
{
datetime(2008, 1, 31): datetime(2008, 2, 1),
datetime(2008, 2, 1): datetime(2008, 3, 1),
datetime(2006, 12, 31): datetime(2007, 1, 1),
datetime(2006, 12, 1): datetime(2007, 1, 1),
datetime(2007, 1, 31): datetime(2007, 2, 1),
},
)
)
offset_cases.append(
(
MonthBegin(0),
{
datetime(2008, 1, 31): datetime(2008, 2, 1),
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2006, 12, 3): datetime(2007, 1, 1),
datetime(2007, 1, 31): datetime(2007, 2, 1),
},
)
)
offset_cases.append(
(
MonthBegin(2),
{
datetime(2008, 2, 29): datetime(2008, 4, 1),
datetime(2008, 1, 31): datetime(2008, 3, 1),
datetime(2006, 12, 31): datetime(2007, 2, 1),
datetime(2007, 12, 28): datetime(2008, 2, 1),
datetime(2007, 1, 1): datetime(2007, 3, 1),
datetime(2006, 11, 1): datetime(2007, 1, 1),
},
)
)
offset_cases.append(
(
MonthBegin(-1),
{
datetime(2007, 1, 1): datetime(2006, 12, 1),
datetime(2008, 5, 31): datetime(2008, 5, 1),
datetime(2008, 12, 31): datetime(2008, 12, 1),
datetime(2006, 12, 29): datetime(2006, 12, 1),
datetime(2006, 1, 2): datetime(2006, 1, 1),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
class TestMonthEnd:
def test_day_of_month(self):
dt = datetime(2007, 1, 1)
offset = MonthEnd()
result = dt + offset
assert result == Timestamp(2007, 1, 31)
result = result + offset
assert result == Timestamp(2007, 2, 28)
def test_normalize(self):
dt = datetime(2007, 1, 1, 3)
result = dt + MonthEnd(normalize=True)
expected = dt.replace(hour=0) + MonthEnd()
assert result == expected
offset_cases = []
offset_cases.append(
(
MonthEnd(),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 2, 29),
datetime(2006, 12, 29): datetime(2006, 12, 31),
datetime(2006, 12, 31): datetime(2007, 1, 31),
datetime(2007, 1, 1): datetime(2007, 1, 31),
datetime(2006, 12, 1): datetime(2006, 12, 31),
},
)
)
offset_cases.append(
(
MonthEnd(0),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 1, 31),
datetime(2006, 12, 29): datetime(2006, 12, 31),
datetime(2006, 12, 31): datetime(2006, 12, 31),
datetime(2007, 1, 1): datetime(2007, 1, 31),
},
)
)
offset_cases.append(
(
MonthEnd(2),
{
datetime(2008, 1, 1): datetime(2008, 2, 29),
datetime(2008, 1, 31): datetime(2008, 3, 31),
datetime(2006, 12, 29): datetime(2007, 1, 31),
datetime(2006, 12, 31): datetime(2007, 2, 28),
datetime(2007, 1, 1): datetime(2007, 2, 28),
datetime(2006, 11, 1): datetime(2006, 12, 31),
},
)
)
offset_cases.append(
(
MonthEnd(-1),
{
datetime(2007, 1, 1): datetime(2006, 12, 31),
datetime(2008, 6, 30): datetime(2008, 5, 31),
datetime(2008, 12, 31): datetime(2008, 11, 30),
datetime(2006, 12, 29): datetime(2006, 11, 30),
datetime(2006, 12, 30): datetime(2006, 11, 30),
datetime(2007, 1, 1): datetime(2006, 12, 31),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
on_offset_cases = [
(MonthEnd(), datetime(2007, 12, 31), True),
(MonthEnd(), datetime(2008, 1, 1), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)

File diff suppressed because it is too large Load Diff

View File

@ -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()

View File

@ -0,0 +1,303 @@
"""
Tests for the following offsets:
- QuarterBegin
- QuarterEnd
"""
from __future__ import annotations
from datetime import datetime
import pytest
import pandas._testing as tm
from pandas.tests.tseries.offsets.common import (
assert_is_on_offset,
assert_offset_equal,
)
from pandas.tseries.offsets import (
QuarterBegin,
QuarterEnd,
)
@pytest.mark.parametrize("klass", (QuarterBegin, QuarterEnd))
def test_quarterly_dont_normalize(klass):
date = datetime(2012, 3, 31, 5, 30)
result = date + klass()
assert result.time() == date.time()
@pytest.mark.parametrize("offset", [QuarterBegin(), QuarterEnd()])
@pytest.mark.parametrize(
"date",
[
datetime(2016, m, d)
for m in [10, 11, 12]
for d in [1, 2, 3, 28, 29, 30, 31]
if not (m == 11 and d == 31)
],
)
def test_on_offset(offset, date):
res = offset.is_on_offset(date)
slow_version = date == (date + offset) - offset
assert res == slow_version
class TestQuarterBegin:
def test_repr(self):
expected = "<QuarterBegin: startingMonth=3>"
assert repr(QuarterBegin()) == expected
expected = "<QuarterBegin: startingMonth=3>"
assert repr(QuarterBegin(startingMonth=3)) == expected
expected = "<QuarterBegin: startingMonth=1>"
assert repr(QuarterBegin(startingMonth=1)) == expected
def test_is_anchored(self):
msg = "QuarterBegin.is_anchored is deprecated "
with tm.assert_produces_warning(FutureWarning, match=msg):
assert QuarterBegin(startingMonth=1).is_anchored()
assert QuarterBegin().is_anchored()
assert not QuarterBegin(2, startingMonth=1).is_anchored()
def test_offset_corner_case(self):
# corner
offset = QuarterBegin(n=-1, startingMonth=1)
assert datetime(2010, 2, 1) + offset == datetime(2010, 1, 1)
offset_cases = []
offset_cases.append(
(
QuarterBegin(startingMonth=1),
{
datetime(2007, 12, 1): datetime(2008, 1, 1),
datetime(2008, 1, 1): datetime(2008, 4, 1),
datetime(2008, 2, 15): datetime(2008, 4, 1),
datetime(2008, 2, 29): datetime(2008, 4, 1),
datetime(2008, 3, 15): datetime(2008, 4, 1),
datetime(2008, 3, 31): datetime(2008, 4, 1),
datetime(2008, 4, 15): datetime(2008, 7, 1),
datetime(2008, 4, 1): datetime(2008, 7, 1),
},
)
)
offset_cases.append(
(
QuarterBegin(startingMonth=2),
{
datetime(2008, 1, 1): datetime(2008, 2, 1),
datetime(2008, 1, 31): datetime(2008, 2, 1),
datetime(2008, 1, 15): datetime(2008, 2, 1),
datetime(2008, 2, 29): datetime(2008, 5, 1),
datetime(2008, 3, 15): datetime(2008, 5, 1),
datetime(2008, 3, 31): datetime(2008, 5, 1),
datetime(2008, 4, 15): datetime(2008, 5, 1),
datetime(2008, 4, 30): datetime(2008, 5, 1),
},
)
)
offset_cases.append(
(
QuarterBegin(startingMonth=1, n=0),
{
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2008, 12, 1): datetime(2009, 1, 1),
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2008, 2, 15): datetime(2008, 4, 1),
datetime(2008, 2, 29): datetime(2008, 4, 1),
datetime(2008, 3, 15): datetime(2008, 4, 1),
datetime(2008, 3, 31): datetime(2008, 4, 1),
datetime(2008, 4, 15): datetime(2008, 7, 1),
datetime(2008, 4, 30): datetime(2008, 7, 1),
},
)
)
offset_cases.append(
(
QuarterBegin(startingMonth=1, n=-1),
{
datetime(2008, 1, 1): datetime(2007, 10, 1),
datetime(2008, 1, 31): datetime(2008, 1, 1),
datetime(2008, 2, 15): datetime(2008, 1, 1),
datetime(2008, 2, 29): datetime(2008, 1, 1),
datetime(2008, 3, 15): datetime(2008, 1, 1),
datetime(2008, 3, 31): datetime(2008, 1, 1),
datetime(2008, 4, 15): datetime(2008, 4, 1),
datetime(2008, 4, 30): datetime(2008, 4, 1),
datetime(2008, 7, 1): datetime(2008, 4, 1),
},
)
)
offset_cases.append(
(
QuarterBegin(startingMonth=1, n=2),
{
datetime(2008, 1, 1): datetime(2008, 7, 1),
datetime(2008, 2, 15): datetime(2008, 7, 1),
datetime(2008, 2, 29): datetime(2008, 7, 1),
datetime(2008, 3, 15): datetime(2008, 7, 1),
datetime(2008, 3, 31): datetime(2008, 7, 1),
datetime(2008, 4, 15): datetime(2008, 10, 1),
datetime(2008, 4, 1): datetime(2008, 10, 1),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
class TestQuarterEnd:
def test_repr(self):
expected = "<QuarterEnd: startingMonth=3>"
assert repr(QuarterEnd()) == expected
expected = "<QuarterEnd: startingMonth=3>"
assert repr(QuarterEnd(startingMonth=3)) == expected
expected = "<QuarterEnd: startingMonth=1>"
assert repr(QuarterEnd(startingMonth=1)) == expected
def test_is_anchored(self):
msg = "QuarterEnd.is_anchored is deprecated "
with tm.assert_produces_warning(FutureWarning, match=msg):
assert QuarterEnd(startingMonth=1).is_anchored()
assert QuarterEnd().is_anchored()
assert not QuarterEnd(2, startingMonth=1).is_anchored()
def test_offset_corner_case(self):
# corner
offset = QuarterEnd(n=-1, startingMonth=1)
assert datetime(2010, 2, 1) + offset == datetime(2010, 1, 31)
offset_cases = []
offset_cases.append(
(
QuarterEnd(startingMonth=1),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 4, 30),
datetime(2008, 2, 15): datetime(2008, 4, 30),
datetime(2008, 2, 29): datetime(2008, 4, 30),
datetime(2008, 3, 15): datetime(2008, 4, 30),
datetime(2008, 3, 31): datetime(2008, 4, 30),
datetime(2008, 4, 15): datetime(2008, 4, 30),
datetime(2008, 4, 30): datetime(2008, 7, 31),
},
)
)
offset_cases.append(
(
QuarterEnd(startingMonth=2),
{
datetime(2008, 1, 1): datetime(2008, 2, 29),
datetime(2008, 1, 31): datetime(2008, 2, 29),
datetime(2008, 2, 15): datetime(2008, 2, 29),
datetime(2008, 2, 29): datetime(2008, 5, 31),
datetime(2008, 3, 15): datetime(2008, 5, 31),
datetime(2008, 3, 31): datetime(2008, 5, 31),
datetime(2008, 4, 15): datetime(2008, 5, 31),
datetime(2008, 4, 30): datetime(2008, 5, 31),
},
)
)
offset_cases.append(
(
QuarterEnd(startingMonth=1, n=0),
{
datetime(2008, 1, 1): datetime(2008, 1, 31),
datetime(2008, 1, 31): datetime(2008, 1, 31),
datetime(2008, 2, 15): datetime(2008, 4, 30),
datetime(2008, 2, 29): datetime(2008, 4, 30),
datetime(2008, 3, 15): datetime(2008, 4, 30),
datetime(2008, 3, 31): datetime(2008, 4, 30),
datetime(2008, 4, 15): datetime(2008, 4, 30),
datetime(2008, 4, 30): datetime(2008, 4, 30),
},
)
)
offset_cases.append(
(
QuarterEnd(startingMonth=1, n=-1),
{
datetime(2008, 1, 1): datetime(2007, 10, 31),
datetime(2008, 1, 31): datetime(2007, 10, 31),
datetime(2008, 2, 15): datetime(2008, 1, 31),
datetime(2008, 2, 29): datetime(2008, 1, 31),
datetime(2008, 3, 15): datetime(2008, 1, 31),
datetime(2008, 3, 31): datetime(2008, 1, 31),
datetime(2008, 4, 15): datetime(2008, 1, 31),
datetime(2008, 4, 30): datetime(2008, 1, 31),
datetime(2008, 7, 1): datetime(2008, 4, 30),
},
)
)
offset_cases.append(
(
QuarterEnd(startingMonth=1, n=2),
{
datetime(2008, 1, 31): datetime(2008, 7, 31),
datetime(2008, 2, 15): datetime(2008, 7, 31),
datetime(2008, 2, 29): datetime(2008, 7, 31),
datetime(2008, 3, 15): datetime(2008, 7, 31),
datetime(2008, 3, 31): datetime(2008, 7, 31),
datetime(2008, 4, 15): datetime(2008, 7, 31),
datetime(2008, 4, 30): datetime(2008, 10, 31),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
on_offset_cases = [
(QuarterEnd(1, startingMonth=1), datetime(2008, 1, 31), True),
(QuarterEnd(1, startingMonth=1), datetime(2007, 12, 31), False),
(QuarterEnd(1, startingMonth=1), datetime(2008, 2, 29), False),
(QuarterEnd(1, startingMonth=1), datetime(2007, 3, 30), False),
(QuarterEnd(1, startingMonth=1), datetime(2007, 3, 31), False),
(QuarterEnd(1, startingMonth=1), datetime(2008, 4, 30), True),
(QuarterEnd(1, startingMonth=1), datetime(2008, 5, 30), False),
(QuarterEnd(1, startingMonth=1), datetime(2008, 5, 31), False),
(QuarterEnd(1, startingMonth=1), datetime(2007, 6, 29), False),
(QuarterEnd(1, startingMonth=1), datetime(2007, 6, 30), False),
(QuarterEnd(1, startingMonth=2), datetime(2008, 1, 31), False),
(QuarterEnd(1, startingMonth=2), datetime(2007, 12, 31), False),
(QuarterEnd(1, startingMonth=2), datetime(2008, 2, 29), True),
(QuarterEnd(1, startingMonth=2), datetime(2007, 3, 30), False),
(QuarterEnd(1, startingMonth=2), datetime(2007, 3, 31), False),
(QuarterEnd(1, startingMonth=2), datetime(2008, 4, 30), False),
(QuarterEnd(1, startingMonth=2), datetime(2008, 5, 30), False),
(QuarterEnd(1, startingMonth=2), datetime(2008, 5, 31), True),
(QuarterEnd(1, startingMonth=2), datetime(2007, 6, 29), False),
(QuarterEnd(1, startingMonth=2), datetime(2007, 6, 30), False),
(QuarterEnd(1, startingMonth=3), datetime(2008, 1, 31), False),
(QuarterEnd(1, startingMonth=3), datetime(2007, 12, 31), True),
(QuarterEnd(1, startingMonth=3), datetime(2008, 2, 29), False),
(QuarterEnd(1, startingMonth=3), datetime(2007, 3, 30), False),
(QuarterEnd(1, startingMonth=3), datetime(2007, 3, 31), True),
(QuarterEnd(1, startingMonth=3), datetime(2008, 4, 30), False),
(QuarterEnd(1, startingMonth=3), datetime(2008, 5, 30), False),
(QuarterEnd(1, startingMonth=3), datetime(2008, 5, 31), False),
(QuarterEnd(1, startingMonth=3), datetime(2007, 6, 29), False),
(QuarterEnd(1, startingMonth=3), datetime(2007, 6, 30), True),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)

View File

@ -0,0 +1,405 @@
"""
Tests for offsets.Tick and subclasses
"""
from datetime import (
datetime,
timedelta,
)
from hypothesis import (
assume,
example,
given,
)
import numpy as np
import pytest
from pandas._libs.tslibs.offsets import delta_to_tick
from pandas.errors import OutOfBoundsTimedelta
from pandas import (
Timedelta,
Timestamp,
)
import pandas._testing as tm
from pandas._testing._hypothesis import INT_NEG_999_TO_POS_999
from pandas.tests.tseries.offsets.common import assert_offset_equal
from pandas.tseries import offsets
from pandas.tseries.offsets import (
Hour,
Micro,
Milli,
Minute,
Nano,
Second,
)
# ---------------------------------------------------------------------
# Test Helpers
tick_classes = [Hour, Minute, Second, Milli, Micro, Nano]
# ---------------------------------------------------------------------
def test_apply_ticks():
result = offsets.Hour(3) + offsets.Hour(4)
exp = offsets.Hour(7)
assert result == exp
def test_delta_to_tick():
delta = timedelta(3)
tick = delta_to_tick(delta)
assert tick == offsets.Day(3)
td = Timedelta(nanoseconds=5)
tick = delta_to_tick(td)
assert tick == Nano(5)
@pytest.mark.parametrize("cls", tick_classes)
@example(n=2, m=3)
@example(n=800, m=300)
@example(n=1000, m=5)
@given(n=INT_NEG_999_TO_POS_999, m=INT_NEG_999_TO_POS_999)
def test_tick_add_sub(cls, n, m):
# For all Tick subclasses and all integers n, m, we should have
# tick(n) + tick(m) == tick(n+m)
# tick(n) - tick(m) == tick(n-m)
left = cls(n)
right = cls(m)
expected = cls(n + m)
assert left + right == expected
expected = cls(n - m)
assert left - right == expected
@pytest.mark.arm_slow
@pytest.mark.parametrize("cls", tick_classes)
@example(n=2, m=3)
@given(n=INT_NEG_999_TO_POS_999, m=INT_NEG_999_TO_POS_999)
def test_tick_equality(cls, n, m):
assume(m != n)
# tick == tock iff tick.n == tock.n
left = cls(n)
right = cls(m)
assert left != right
right = cls(n)
assert left == right
assert not left != right
if n != 0:
assert cls(n) != cls(-n)
# ---------------------------------------------------------------------
def test_Hour():
assert_offset_equal(Hour(), datetime(2010, 1, 1), datetime(2010, 1, 1, 1))
assert_offset_equal(Hour(-1), datetime(2010, 1, 1, 1), datetime(2010, 1, 1))
assert_offset_equal(2 * Hour(), datetime(2010, 1, 1), datetime(2010, 1, 1, 2))
assert_offset_equal(-1 * Hour(), datetime(2010, 1, 1, 1), datetime(2010, 1, 1))
assert Hour(3) + Hour(2) == Hour(5)
assert Hour(3) - Hour(2) == Hour()
assert Hour(4) != Hour(1)
def test_Minute():
assert_offset_equal(Minute(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 1))
assert_offset_equal(Minute(-1), datetime(2010, 1, 1, 0, 1), datetime(2010, 1, 1))
assert_offset_equal(2 * Minute(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 2))
assert_offset_equal(-1 * Minute(), datetime(2010, 1, 1, 0, 1), datetime(2010, 1, 1))
assert Minute(3) + Minute(2) == Minute(5)
assert Minute(3) - Minute(2) == Minute()
assert Minute(5) != Minute()
def test_Second():
assert_offset_equal(Second(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 1))
assert_offset_equal(Second(-1), datetime(2010, 1, 1, 0, 0, 1), datetime(2010, 1, 1))
assert_offset_equal(
2 * Second(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 2)
)
assert_offset_equal(
-1 * Second(), datetime(2010, 1, 1, 0, 0, 1), datetime(2010, 1, 1)
)
assert Second(3) + Second(2) == Second(5)
assert Second(3) - Second(2) == Second()
def test_Millisecond():
assert_offset_equal(
Milli(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 1000)
)
assert_offset_equal(
Milli(-1), datetime(2010, 1, 1, 0, 0, 0, 1000), datetime(2010, 1, 1)
)
assert_offset_equal(
Milli(2), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2000)
)
assert_offset_equal(
2 * Milli(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2000)
)
assert_offset_equal(
-1 * Milli(), datetime(2010, 1, 1, 0, 0, 0, 1000), datetime(2010, 1, 1)
)
assert Milli(3) + Milli(2) == Milli(5)
assert Milli(3) - Milli(2) == Milli()
def test_MillisecondTimestampArithmetic():
assert_offset_equal(
Milli(), Timestamp("2010-01-01"), Timestamp("2010-01-01 00:00:00.001")
)
assert_offset_equal(
Milli(-1), Timestamp("2010-01-01 00:00:00.001"), Timestamp("2010-01-01")
)
def test_Microsecond():
assert_offset_equal(Micro(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 1))
assert_offset_equal(
Micro(-1), datetime(2010, 1, 1, 0, 0, 0, 1), datetime(2010, 1, 1)
)
assert_offset_equal(
2 * Micro(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2)
)
assert_offset_equal(
-1 * Micro(), datetime(2010, 1, 1, 0, 0, 0, 1), datetime(2010, 1, 1)
)
assert Micro(3) + Micro(2) == Micro(5)
assert Micro(3) - Micro(2) == Micro()
def test_NanosecondGeneric():
timestamp = Timestamp(datetime(2010, 1, 1))
assert timestamp.nanosecond == 0
result = timestamp + Nano(10)
assert result.nanosecond == 10
reverse_result = Nano(10) + timestamp
assert reverse_result.nanosecond == 10
def test_Nanosecond():
timestamp = Timestamp(datetime(2010, 1, 1))
assert_offset_equal(Nano(), timestamp, timestamp + np.timedelta64(1, "ns"))
assert_offset_equal(Nano(-1), timestamp + np.timedelta64(1, "ns"), timestamp)
assert_offset_equal(2 * Nano(), timestamp, timestamp + np.timedelta64(2, "ns"))
assert_offset_equal(-1 * Nano(), timestamp + np.timedelta64(1, "ns"), timestamp)
assert Nano(3) + Nano(2) == Nano(5)
assert Nano(3) - Nano(2) == Nano()
# GH9284
assert Nano(1) + Nano(10) == Nano(11)
assert Nano(5) + Micro(1) == Nano(1005)
assert Micro(5) + Nano(1) == Nano(5001)
@pytest.mark.parametrize(
"kls, expected",
[
(Hour, Timedelta(hours=5)),
(Minute, Timedelta(hours=2, minutes=3)),
(Second, Timedelta(hours=2, seconds=3)),
(Milli, Timedelta(hours=2, milliseconds=3)),
(Micro, Timedelta(hours=2, microseconds=3)),
(Nano, Timedelta(hours=2, nanoseconds=3)),
],
)
def test_tick_addition(kls, expected):
offset = kls(3)
td = Timedelta(hours=2)
for other in [td, td.to_pytimedelta(), td.to_timedelta64()]:
result = offset + other
assert isinstance(result, Timedelta)
assert result == expected
result = other + offset
assert isinstance(result, Timedelta)
assert result == expected
def test_tick_delta_overflow():
# GH#55503 raise OutOfBoundsTimedelta, not OverflowError
tick = offsets.Day(10**9)
msg = "Cannot cast 1000000000 days 00:00:00 to unit='ns' without overflow"
depr_msg = "Day.delta is deprecated"
with pytest.raises(OutOfBoundsTimedelta, match=msg):
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
tick.delta
@pytest.mark.parametrize("cls", tick_classes)
def test_tick_division(cls):
off = cls(10)
assert off / cls(5) == 2
assert off / 2 == cls(5)
assert off / 2.0 == cls(5)
assert off / off._as_pd_timedelta == 1
assert off / off._as_pd_timedelta.to_timedelta64() == 1
assert off / Nano(1) == off._as_pd_timedelta / Nano(1)._as_pd_timedelta
if cls is not Nano:
# A case where we end up with a smaller class
result = off / 1000
assert isinstance(result, offsets.Tick)
assert not isinstance(result, cls)
assert result._as_pd_timedelta == off._as_pd_timedelta / 1000
if cls._nanos_inc < Timedelta(seconds=1)._value:
# Case where we end up with a bigger class
result = off / 0.001
assert isinstance(result, offsets.Tick)
assert not isinstance(result, cls)
assert result._as_pd_timedelta == off._as_pd_timedelta / 0.001
def test_tick_mul_float():
off = Micro(2)
# Case where we retain type
result = off * 1.5
expected = Micro(3)
assert result == expected
assert isinstance(result, Micro)
# Case where we bump up to the next type
result = off * 1.25
expected = Nano(2500)
assert result == expected
assert isinstance(result, Nano)
@pytest.mark.parametrize("cls", tick_classes)
def test_tick_rdiv(cls):
off = cls(10)
delta = off._as_pd_timedelta
td64 = delta.to_timedelta64()
instance__type = ".".join([cls.__module__, cls.__name__])
msg = (
"unsupported operand type\\(s\\) for \\/: 'int'|'float' and "
f"'{instance__type}'"
)
with pytest.raises(TypeError, match=msg):
2 / off
with pytest.raises(TypeError, match=msg):
2.0 / off
assert (td64 * 2.5) / off == 2.5
if cls is not Nano:
# skip pytimedelta for Nano since it gets dropped
assert (delta.to_pytimedelta() * 2) / off == 2
result = np.array([2 * td64, td64]) / off
expected = np.array([2.0, 1.0])
tm.assert_numpy_array_equal(result, expected)
@pytest.mark.parametrize("cls1", tick_classes)
@pytest.mark.parametrize("cls2", tick_classes)
def test_tick_zero(cls1, cls2):
assert cls1(0) == cls2(0)
assert cls1(0) + cls2(0) == cls1(0)
if cls1 is not Nano:
assert cls1(2) + cls2(0) == cls1(2)
if cls1 is Nano:
assert cls1(2) + Nano(0) == cls1(2)
@pytest.mark.parametrize("cls", tick_classes)
def test_tick_equalities(cls):
assert cls() == cls(1)
@pytest.mark.parametrize("cls", tick_classes)
def test_tick_offset(cls):
msg = f"{cls.__name__}.is_anchored is deprecated "
with tm.assert_produces_warning(FutureWarning, match=msg):
assert not cls().is_anchored()
@pytest.mark.parametrize("cls", tick_classes)
def test_compare_ticks(cls):
three = cls(3)
four = cls(4)
assert three < cls(4)
assert cls(3) < four
assert four > cls(3)
assert cls(4) > three
assert cls(3) == cls(3)
assert cls(3) != cls(4)
@pytest.mark.parametrize("cls", tick_classes)
def test_compare_ticks_to_strs(cls):
# GH#23524
off = cls(19)
# These tests should work with any strings, but we particularly are
# interested in "infer" as that comparison is convenient to make in
# Datetime/Timedelta Array/Index constructors
assert not off == "infer"
assert not "foo" == off
instance_type = ".".join([cls.__module__, cls.__name__])
msg = (
"'<'|'<='|'>'|'>=' not supported between instances of "
f"'str' and '{instance_type}'|'{instance_type}' and 'str'"
)
for left, right in [("infer", off), (off, "infer")]:
with pytest.raises(TypeError, match=msg):
left < right
with pytest.raises(TypeError, match=msg):
left <= right
with pytest.raises(TypeError, match=msg):
left > right
with pytest.raises(TypeError, match=msg):
left >= right
@pytest.mark.parametrize("cls", tick_classes)
def test_compare_ticks_to_timedeltalike(cls):
off = cls(19)
td = off._as_pd_timedelta
others = [td, td.to_timedelta64()]
if cls is not Nano:
others.append(td.to_pytimedelta())
for other in others:
assert off == other
assert not off != other
assert not off < other
assert not off > other
assert off <= other
assert off >= other

View File

@ -0,0 +1,351 @@
"""
Tests for the following offsets:
- Week
- WeekOfMonth
- LastWeekOfMonth
"""
from __future__ import annotations
from datetime import (
datetime,
timedelta,
)
import pytest
from pandas._libs.tslibs import Timestamp
from pandas._libs.tslibs.offsets import (
Day,
LastWeekOfMonth,
Week,
WeekOfMonth,
)
import pandas._testing as tm
from pandas.tests.tseries.offsets.common import (
WeekDay,
assert_is_on_offset,
assert_offset_equal,
)
class TestWeek:
def test_repr(self):
assert repr(Week(weekday=0)) == "<Week: weekday=0>"
assert repr(Week(n=-1, weekday=0)) == "<-1 * Week: weekday=0>"
assert repr(Week(n=-2, weekday=0)) == "<-2 * Weeks: weekday=0>"
def test_corner(self):
with pytest.raises(ValueError, match="Day must be"):
Week(weekday=7)
with pytest.raises(ValueError, match="Day must be"):
Week(weekday=-1)
def test_is_anchored(self):
msg = "Week.is_anchored is deprecated "
with tm.assert_produces_warning(FutureWarning, match=msg):
assert Week(weekday=0).is_anchored()
assert not Week().is_anchored()
assert not Week(2, weekday=2).is_anchored()
assert not Week(2).is_anchored()
offset_cases = []
# not business week
offset_cases.append(
(
Week(),
{
datetime(2008, 1, 1): datetime(2008, 1, 8),
datetime(2008, 1, 4): datetime(2008, 1, 11),
datetime(2008, 1, 5): datetime(2008, 1, 12),
datetime(2008, 1, 6): datetime(2008, 1, 13),
datetime(2008, 1, 7): datetime(2008, 1, 14),
},
)
)
# Mon
offset_cases.append(
(
Week(weekday=0),
{
datetime(2007, 12, 31): datetime(2008, 1, 7),
datetime(2008, 1, 4): datetime(2008, 1, 7),
datetime(2008, 1, 5): datetime(2008, 1, 7),
datetime(2008, 1, 6): datetime(2008, 1, 7),
datetime(2008, 1, 7): datetime(2008, 1, 14),
},
)
)
# n=0 -> roll forward. Mon
offset_cases.append(
(
Week(0, weekday=0),
{
datetime(2007, 12, 31): datetime(2007, 12, 31),
datetime(2008, 1, 4): datetime(2008, 1, 7),
datetime(2008, 1, 5): datetime(2008, 1, 7),
datetime(2008, 1, 6): datetime(2008, 1, 7),
datetime(2008, 1, 7): datetime(2008, 1, 7),
},
)
)
# n=0 -> roll forward. Mon
offset_cases.append(
(
Week(-2, weekday=1),
{
datetime(2010, 4, 6): datetime(2010, 3, 23),
datetime(2010, 4, 8): datetime(2010, 3, 30),
datetime(2010, 4, 5): datetime(2010, 3, 23),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
@pytest.mark.parametrize("weekday", range(7))
def test_is_on_offset(self, weekday):
offset = Week(weekday=weekday)
for day in range(1, 8):
date = datetime(2008, 1, day)
expected = day % 7 == weekday
assert_is_on_offset(offset, date, expected)
@pytest.mark.parametrize(
"n,date",
[
(2, "1862-01-13 09:03:34.873477378+0210"),
(-2, "1856-10-24 16:18:36.556360110-0717"),
],
)
def test_is_on_offset_weekday_none(self, n, date):
# GH 18510 Week with weekday = None, normalize = False
# should always be is_on_offset
offset = Week(n=n, weekday=None)
ts = Timestamp(date, tz="Africa/Lusaka")
fast = offset.is_on_offset(ts)
slow = (ts + offset) - offset == ts
assert fast == slow
def test_week_add_invalid(self):
# Week with weekday should raise TypeError and _not_ AttributeError
# when adding invalid offset
offset = Week(weekday=1)
other = Day()
with pytest.raises(TypeError, match="Cannot add"):
offset + other
class TestWeekOfMonth:
def test_constructor(self):
with pytest.raises(ValueError, match="^Week"):
WeekOfMonth(n=1, week=4, weekday=0)
with pytest.raises(ValueError, match="^Week"):
WeekOfMonth(n=1, week=-1, weekday=0)
with pytest.raises(ValueError, match="^Day"):
WeekOfMonth(n=1, week=0, weekday=-1)
with pytest.raises(ValueError, match="^Day"):
WeekOfMonth(n=1, week=0, weekday=-7)
def test_repr(self):
assert (
repr(WeekOfMonth(weekday=1, week=2)) == "<WeekOfMonth: week=2, weekday=1>"
)
def test_offset(self):
date1 = datetime(2011, 1, 4) # 1st Tuesday of Month
date2 = datetime(2011, 1, 11) # 2nd Tuesday of Month
date3 = datetime(2011, 1, 18) # 3rd Tuesday of Month
date4 = datetime(2011, 1, 25) # 4th Tuesday of Month
# see for loop for structure
test_cases = [
(-2, 2, 1, date1, datetime(2010, 11, 16)),
(-2, 2, 1, date2, datetime(2010, 11, 16)),
(-2, 2, 1, date3, datetime(2010, 11, 16)),
(-2, 2, 1, date4, datetime(2010, 12, 21)),
(-1, 2, 1, date1, datetime(2010, 12, 21)),
(-1, 2, 1, date2, datetime(2010, 12, 21)),
(-1, 2, 1, date3, datetime(2010, 12, 21)),
(-1, 2, 1, date4, datetime(2011, 1, 18)),
(0, 0, 1, date1, datetime(2011, 1, 4)),
(0, 0, 1, date2, datetime(2011, 2, 1)),
(0, 0, 1, date3, datetime(2011, 2, 1)),
(0, 0, 1, date4, datetime(2011, 2, 1)),
(0, 1, 1, date1, datetime(2011, 1, 11)),
(0, 1, 1, date2, datetime(2011, 1, 11)),
(0, 1, 1, date3, datetime(2011, 2, 8)),
(0, 1, 1, date4, datetime(2011, 2, 8)),
(0, 0, 1, date1, datetime(2011, 1, 4)),
(0, 1, 1, date2, datetime(2011, 1, 11)),
(0, 2, 1, date3, datetime(2011, 1, 18)),
(0, 3, 1, date4, datetime(2011, 1, 25)),
(1, 0, 0, date1, datetime(2011, 2, 7)),
(1, 0, 0, date2, datetime(2011, 2, 7)),
(1, 0, 0, date3, datetime(2011, 2, 7)),
(1, 0, 0, date4, datetime(2011, 2, 7)),
(1, 0, 1, date1, datetime(2011, 2, 1)),
(1, 0, 1, date2, datetime(2011, 2, 1)),
(1, 0, 1, date3, datetime(2011, 2, 1)),
(1, 0, 1, date4, datetime(2011, 2, 1)),
(1, 0, 2, date1, datetime(2011, 1, 5)),
(1, 0, 2, date2, datetime(2011, 2, 2)),
(1, 0, 2, date3, datetime(2011, 2, 2)),
(1, 0, 2, date4, datetime(2011, 2, 2)),
(1, 2, 1, date1, datetime(2011, 1, 18)),
(1, 2, 1, date2, datetime(2011, 1, 18)),
(1, 2, 1, date3, datetime(2011, 2, 15)),
(1, 2, 1, date4, datetime(2011, 2, 15)),
(2, 2, 1, date1, datetime(2011, 2, 15)),
(2, 2, 1, date2, datetime(2011, 2, 15)),
(2, 2, 1, date3, datetime(2011, 3, 15)),
(2, 2, 1, date4, datetime(2011, 3, 15)),
]
for n, week, weekday, dt, expected in test_cases:
offset = WeekOfMonth(n, week=week, weekday=weekday)
assert_offset_equal(offset, dt, expected)
# try subtracting
result = datetime(2011, 2, 1) - WeekOfMonth(week=1, weekday=2)
assert result == datetime(2011, 1, 12)
result = datetime(2011, 2, 3) - WeekOfMonth(week=0, weekday=2)
assert result == datetime(2011, 2, 2)
on_offset_cases = [
(0, 0, datetime(2011, 2, 7), True),
(0, 0, datetime(2011, 2, 6), False),
(0, 0, datetime(2011, 2, 14), False),
(1, 0, datetime(2011, 2, 14), True),
(0, 1, datetime(2011, 2, 1), True),
(0, 1, datetime(2011, 2, 8), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
week, weekday, dt, expected = case
offset = WeekOfMonth(week=week, weekday=weekday)
assert offset.is_on_offset(dt) == expected
@pytest.mark.parametrize(
"n,week,date,tz",
[
(2, 2, "1916-05-15 01:14:49.583410462+0422", "Asia/Qyzylorda"),
(-3, 1, "1980-12-08 03:38:52.878321185+0500", "Asia/Oral"),
],
)
def test_is_on_offset_nanoseconds(self, n, week, date, tz):
# GH 18864
# Make sure that nanoseconds don't trip up is_on_offset (and with it apply)
offset = WeekOfMonth(n=n, week=week, weekday=0)
ts = Timestamp(date, tz=tz)
fast = offset.is_on_offset(ts)
slow = (ts + offset) - offset == ts
assert fast == slow
class TestLastWeekOfMonth:
def test_constructor(self):
with pytest.raises(ValueError, match="^N cannot be 0"):
LastWeekOfMonth(n=0, weekday=1)
with pytest.raises(ValueError, match="^Day"):
LastWeekOfMonth(n=1, weekday=-1)
with pytest.raises(ValueError, match="^Day"):
LastWeekOfMonth(n=1, weekday=7)
def test_offset(self):
# Saturday
last_sat = datetime(2013, 8, 31)
next_sat = datetime(2013, 9, 28)
offset_sat = LastWeekOfMonth(n=1, weekday=5)
one_day_before = last_sat + timedelta(days=-1)
assert one_day_before + offset_sat == last_sat
one_day_after = last_sat + timedelta(days=+1)
assert one_day_after + offset_sat == next_sat
# Test On that day
assert last_sat + offset_sat == next_sat
# Thursday
offset_thur = LastWeekOfMonth(n=1, weekday=3)
last_thurs = datetime(2013, 1, 31)
next_thurs = datetime(2013, 2, 28)
one_day_before = last_thurs + timedelta(days=-1)
assert one_day_before + offset_thur == last_thurs
one_day_after = last_thurs + timedelta(days=+1)
assert one_day_after + offset_thur == next_thurs
# Test on that day
assert last_thurs + offset_thur == next_thurs
three_before = last_thurs + timedelta(days=-3)
assert three_before + offset_thur == last_thurs
two_after = last_thurs + timedelta(days=+2)
assert two_after + offset_thur == next_thurs
offset_sunday = LastWeekOfMonth(n=1, weekday=WeekDay.SUN)
assert datetime(2013, 7, 31) + offset_sunday == datetime(2013, 8, 25)
on_offset_cases = [
(WeekDay.SUN, datetime(2013, 1, 27), True),
(WeekDay.SAT, datetime(2013, 3, 30), True),
(WeekDay.MON, datetime(2013, 2, 18), False), # Not the last Mon
(WeekDay.SUN, datetime(2013, 2, 25), False), # Not a SUN
(WeekDay.MON, datetime(2013, 2, 25), True),
(WeekDay.SAT, datetime(2013, 11, 30), True),
(WeekDay.SAT, datetime(2006, 8, 26), True),
(WeekDay.SAT, datetime(2007, 8, 25), True),
(WeekDay.SAT, datetime(2008, 8, 30), True),
(WeekDay.SAT, datetime(2009, 8, 29), True),
(WeekDay.SAT, datetime(2010, 8, 28), True),
(WeekDay.SAT, datetime(2011, 8, 27), True),
(WeekDay.SAT, datetime(2019, 8, 31), True),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
weekday, dt, expected = case
offset = LastWeekOfMonth(weekday=weekday)
assert offset.is_on_offset(dt) == expected
@pytest.mark.parametrize(
"n,weekday,date,tz",
[
(4, 6, "1917-05-27 20:55:27.084284178+0200", "Europe/Warsaw"),
(-4, 5, "2005-08-27 05:01:42.799392561-0500", "America/Rainy_River"),
],
)
def test_last_week_of_month_on_offset(self, n, weekday, date, tz):
# GH 19036, GH 18977 _adjust_dst was incorrect for LastWeekOfMonth
offset = LastWeekOfMonth(n=n, weekday=weekday)
ts = Timestamp(date, tz=tz)
slow = (ts + offset) - offset == ts
fast = offset.is_on_offset(ts)
assert fast == slow
def test_repr(self):
assert (
repr(LastWeekOfMonth(n=2, weekday=1)) == "<2 * LastWeekOfMonths: weekday=1>"
)

View File

@ -0,0 +1,339 @@
"""
Tests for the following offsets:
- YearBegin
- YearEnd
"""
from __future__ import annotations
from datetime import datetime
import numpy as np
import pytest
from pandas import Timestamp
from pandas.tests.tseries.offsets.common import (
assert_is_on_offset,
assert_offset_equal,
)
from pandas.tseries.offsets import (
YearBegin,
YearEnd,
)
class TestYearBegin:
def test_misspecified(self):
with pytest.raises(ValueError, match="Month must go from 1 to 12"):
YearBegin(month=13)
offset_cases = []
offset_cases.append(
(
YearBegin(),
{
datetime(2008, 1, 1): datetime(2009, 1, 1),
datetime(2008, 6, 30): datetime(2009, 1, 1),
datetime(2008, 12, 31): datetime(2009, 1, 1),
datetime(2005, 12, 30): datetime(2006, 1, 1),
datetime(2005, 12, 31): datetime(2006, 1, 1),
},
)
)
offset_cases.append(
(
YearBegin(0),
{
datetime(2008, 1, 1): datetime(2008, 1, 1),
datetime(2008, 6, 30): datetime(2009, 1, 1),
datetime(2008, 12, 31): datetime(2009, 1, 1),
datetime(2005, 12, 30): datetime(2006, 1, 1),
datetime(2005, 12, 31): datetime(2006, 1, 1),
},
)
)
offset_cases.append(
(
YearBegin(3),
{
datetime(2008, 1, 1): datetime(2011, 1, 1),
datetime(2008, 6, 30): datetime(2011, 1, 1),
datetime(2008, 12, 31): datetime(2011, 1, 1),
datetime(2005, 12, 30): datetime(2008, 1, 1),
datetime(2005, 12, 31): datetime(2008, 1, 1),
},
)
)
offset_cases.append(
(
YearBegin(-1),
{
datetime(2007, 1, 1): datetime(2006, 1, 1),
datetime(2007, 1, 15): datetime(2007, 1, 1),
datetime(2008, 6, 30): datetime(2008, 1, 1),
datetime(2008, 12, 31): datetime(2008, 1, 1),
datetime(2006, 12, 29): datetime(2006, 1, 1),
datetime(2006, 12, 30): datetime(2006, 1, 1),
datetime(2007, 1, 1): datetime(2006, 1, 1),
},
)
)
offset_cases.append(
(
YearBegin(-2),
{
datetime(2007, 1, 1): datetime(2005, 1, 1),
datetime(2008, 6, 30): datetime(2007, 1, 1),
datetime(2008, 12, 31): datetime(2007, 1, 1),
},
)
)
offset_cases.append(
(
YearBegin(month=4),
{
datetime(2007, 4, 1): datetime(2008, 4, 1),
datetime(2007, 4, 15): datetime(2008, 4, 1),
datetime(2007, 3, 1): datetime(2007, 4, 1),
datetime(2007, 12, 15): datetime(2008, 4, 1),
datetime(2012, 1, 31): datetime(2012, 4, 1),
},
)
)
offset_cases.append(
(
YearBegin(0, month=4),
{
datetime(2007, 4, 1): datetime(2007, 4, 1),
datetime(2007, 3, 1): datetime(2007, 4, 1),
datetime(2007, 12, 15): datetime(2008, 4, 1),
datetime(2012, 1, 31): datetime(2012, 4, 1),
},
)
)
offset_cases.append(
(
YearBegin(4, month=4),
{
datetime(2007, 4, 1): datetime(2011, 4, 1),
datetime(2007, 4, 15): datetime(2011, 4, 1),
datetime(2007, 3, 1): datetime(2010, 4, 1),
datetime(2007, 12, 15): datetime(2011, 4, 1),
datetime(2012, 1, 31): datetime(2015, 4, 1),
},
)
)
offset_cases.append(
(
YearBegin(-1, month=4),
{
datetime(2007, 4, 1): datetime(2006, 4, 1),
datetime(2007, 3, 1): datetime(2006, 4, 1),
datetime(2007, 12, 15): datetime(2007, 4, 1),
datetime(2012, 1, 31): datetime(2011, 4, 1),
},
)
)
offset_cases.append(
(
YearBegin(-3, month=4),
{
datetime(2007, 4, 1): datetime(2004, 4, 1),
datetime(2007, 3, 1): datetime(2004, 4, 1),
datetime(2007, 12, 15): datetime(2005, 4, 1),
datetime(2012, 1, 31): datetime(2009, 4, 1),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
on_offset_cases = [
(YearBegin(), datetime(2007, 1, 3), False),
(YearBegin(), datetime(2008, 1, 1), True),
(YearBegin(), datetime(2006, 12, 31), False),
(YearBegin(), datetime(2006, 1, 2), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
class TestYearEnd:
def test_misspecified(self):
with pytest.raises(ValueError, match="Month must go from 1 to 12"):
YearEnd(month=13)
offset_cases = []
offset_cases.append(
(
YearEnd(),
{
datetime(2008, 1, 1): datetime(2008, 12, 31),
datetime(2008, 6, 30): datetime(2008, 12, 31),
datetime(2008, 12, 31): datetime(2009, 12, 31),
datetime(2005, 12, 30): datetime(2005, 12, 31),
datetime(2005, 12, 31): datetime(2006, 12, 31),
},
)
)
offset_cases.append(
(
YearEnd(0),
{
datetime(2008, 1, 1): datetime(2008, 12, 31),
datetime(2008, 6, 30): datetime(2008, 12, 31),
datetime(2008, 12, 31): datetime(2008, 12, 31),
datetime(2005, 12, 30): datetime(2005, 12, 31),
},
)
)
offset_cases.append(
(
YearEnd(-1),
{
datetime(2007, 1, 1): datetime(2006, 12, 31),
datetime(2008, 6, 30): datetime(2007, 12, 31),
datetime(2008, 12, 31): datetime(2007, 12, 31),
datetime(2006, 12, 29): datetime(2005, 12, 31),
datetime(2006, 12, 30): datetime(2005, 12, 31),
datetime(2007, 1, 1): datetime(2006, 12, 31),
},
)
)
offset_cases.append(
(
YearEnd(-2),
{
datetime(2007, 1, 1): datetime(2005, 12, 31),
datetime(2008, 6, 30): datetime(2006, 12, 31),
datetime(2008, 12, 31): datetime(2006, 12, 31),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
on_offset_cases = [
(YearEnd(), datetime(2007, 12, 31), True),
(YearEnd(), datetime(2008, 1, 1), False),
(YearEnd(), datetime(2006, 12, 31), True),
(YearEnd(), datetime(2006, 12, 29), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
class TestYearEndDiffMonth:
offset_cases = []
offset_cases.append(
(
YearEnd(month=3),
{
datetime(2008, 1, 1): datetime(2008, 3, 31),
datetime(2008, 2, 15): datetime(2008, 3, 31),
datetime(2008, 3, 31): datetime(2009, 3, 31),
datetime(2008, 3, 30): datetime(2008, 3, 31),
datetime(2005, 3, 31): datetime(2006, 3, 31),
datetime(2006, 7, 30): datetime(2007, 3, 31),
},
)
)
offset_cases.append(
(
YearEnd(0, month=3),
{
datetime(2008, 1, 1): datetime(2008, 3, 31),
datetime(2008, 2, 28): datetime(2008, 3, 31),
datetime(2008, 3, 31): datetime(2008, 3, 31),
datetime(2005, 3, 30): datetime(2005, 3, 31),
},
)
)
offset_cases.append(
(
YearEnd(-1, month=3),
{
datetime(2007, 1, 1): datetime(2006, 3, 31),
datetime(2008, 2, 28): datetime(2007, 3, 31),
datetime(2008, 3, 31): datetime(2007, 3, 31),
datetime(2006, 3, 29): datetime(2005, 3, 31),
datetime(2006, 3, 30): datetime(2005, 3, 31),
datetime(2007, 3, 1): datetime(2006, 3, 31),
},
)
)
offset_cases.append(
(
YearEnd(-2, month=3),
{
datetime(2007, 1, 1): datetime(2005, 3, 31),
datetime(2008, 6, 30): datetime(2007, 3, 31),
datetime(2008, 3, 31): datetime(2006, 3, 31),
},
)
)
@pytest.mark.parametrize("case", offset_cases)
def test_offset(self, case):
offset, cases = case
for base, expected in cases.items():
assert_offset_equal(offset, base, expected)
on_offset_cases = [
(YearEnd(month=3), datetime(2007, 3, 31), True),
(YearEnd(month=3), datetime(2008, 1, 1), False),
(YearEnd(month=3), datetime(2006, 3, 31), True),
(YearEnd(month=3), datetime(2006, 3, 29), False),
]
@pytest.mark.parametrize("case", on_offset_cases)
def test_is_on_offset(self, case):
offset, dt, expected = case
assert_is_on_offset(offset, dt, expected)
def test_add_out_of_pydatetime_range():
# GH#50348 don't raise in Timestamp.replace
ts = Timestamp(np.datetime64("-20000-12-31"))
off = YearEnd()
result = ts + off
# TODO(cython3): "arg: datetime" annotation will impose
# datetime limitations on Timestamp. The fused type below works in cy3
# ctypedef fused datetimelike:
# _Timestamp
# datetime
# expected = Timestamp(np.datetime64("-19999-12-31"))
# assert result == expected
assert result.year in (-19999, 1973)
assert result.month == 12
assert result.day == 31