8th day of python challenges 111-117
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import frequencies as libfrequencies, resolution
|
||||
from pandas._libs.tslibs.frequencies import (
|
||||
FreqGroup,
|
||||
_period_code_map,
|
||||
get_freq,
|
||||
get_freq_code,
|
||||
)
|
||||
|
||||
import pandas.tseries.offsets as offsets
|
||||
|
||||
|
||||
@pytest.fixture(params=list(_period_code_map.items()))
|
||||
def period_code_item(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected",
|
||||
[
|
||||
("A", 1000),
|
||||
("3A", 1000),
|
||||
("-1A", 1000),
|
||||
("Y", 1000),
|
||||
("3Y", 1000),
|
||||
("-1Y", 1000),
|
||||
("W", 4000),
|
||||
("W-MON", 4001),
|
||||
("W-FRI", 4005),
|
||||
],
|
||||
)
|
||||
def test_freq_code(freqstr, expected):
|
||||
assert get_freq(freqstr) == expected
|
||||
|
||||
|
||||
def test_freq_code_match(period_code_item):
|
||||
freqstr, code = period_code_item
|
||||
assert get_freq(freqstr) == code
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected",
|
||||
[
|
||||
("A", 1000),
|
||||
("3A", 1000),
|
||||
("-1A", 1000),
|
||||
("A-JAN", 1000),
|
||||
("A-MAY", 1000),
|
||||
("Y", 1000),
|
||||
("3Y", 1000),
|
||||
("-1Y", 1000),
|
||||
("Y-JAN", 1000),
|
||||
("Y-MAY", 1000),
|
||||
(offsets.YearEnd(), 1000),
|
||||
(offsets.YearEnd(month=1), 1000),
|
||||
(offsets.YearEnd(month=5), 1000),
|
||||
("W", 4000),
|
||||
("W-MON", 4000),
|
||||
("W-FRI", 4000),
|
||||
(offsets.Week(), 4000),
|
||||
(offsets.Week(weekday=1), 4000),
|
||||
(offsets.Week(weekday=5), 4000),
|
||||
("T", FreqGroup.FR_MIN),
|
||||
],
|
||||
)
|
||||
def test_freq_group(freqstr, expected):
|
||||
assert resolution.get_freq_group(freqstr) == expected
|
||||
|
||||
|
||||
def test_freq_group_match(period_code_item):
|
||||
freqstr, code = period_code_item
|
||||
|
||||
str_group = resolution.get_freq_group(freqstr)
|
||||
code_group = resolution.get_freq_group(code)
|
||||
|
||||
assert str_group == code_group == code // 1000 * 1000
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,exp_freqstr",
|
||||
[("D", "D"), ("W", "D"), ("M", "D"), ("S", "S"), ("T", "S"), ("H", "S")],
|
||||
)
|
||||
def test_get_to_timestamp_base(freqstr, exp_freqstr):
|
||||
tsb = libfrequencies.get_to_timestamp_base
|
||||
|
||||
assert tsb(get_freq_code(freqstr)[0]) == get_freq_code(exp_freqstr)[0]
|
||||
|
||||
|
||||
_reso = resolution.Resolution
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected",
|
||||
[
|
||||
("A", "year"),
|
||||
("Q", "quarter"),
|
||||
("M", "month"),
|
||||
("D", "day"),
|
||||
("H", "hour"),
|
||||
("T", "minute"),
|
||||
("S", "second"),
|
||||
("L", "millisecond"),
|
||||
("U", "microsecond"),
|
||||
("N", "nanosecond"),
|
||||
],
|
||||
)
|
||||
def test_get_str_from_freq(freqstr, expected):
|
||||
assert _reso.get_str_from_freq(freqstr) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", ["A", "Q", "M", "D", "H", "T", "S", "L", "U", "N"])
|
||||
def test_get_freq_roundtrip(freq):
|
||||
result = _reso.get_freq(_reso.get_str_from_freq(freq))
|
||||
assert freq == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", ["D", "H", "T", "S", "L", "U"])
|
||||
def test_get_freq_roundtrip2(freq):
|
||||
result = _reso.get_freq(_reso.get_str(_reso.get_reso_from_freq(freq)))
|
||||
assert freq == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"args,expected",
|
||||
[
|
||||
((1.5, "T"), (90, "S")),
|
||||
((62.4, "T"), (3744, "S")),
|
||||
((1.04, "H"), (3744, "S")),
|
||||
((1, "D"), (1, "D")),
|
||||
((0.342931, "H"), (1234551600, "U")),
|
||||
((1.2345, "D"), (106660800, "L")),
|
||||
],
|
||||
)
|
||||
def test_resolution_bumping(args, expected):
|
||||
# see gh-14378
|
||||
assert _reso.get_stride_from_decimal(*args) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"args",
|
||||
[
|
||||
(0.5, "N"),
|
||||
# Too much precision in the input can prevent.
|
||||
(0.3429324798798269273987982, "H"),
|
||||
],
|
||||
)
|
||||
def test_cat(args):
|
||||
msg = "Could not convert to integer offset at any resolution"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
_reso.get_stride_from_decimal(*args)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freq_input,expected",
|
||||
[
|
||||
# Frequency string.
|
||||
("A", (get_freq("A"), 1)),
|
||||
("3D", (get_freq("D"), 3)),
|
||||
("-2M", (get_freq("M"), -2)),
|
||||
# Tuple.
|
||||
(("D", 1), (get_freq("D"), 1)),
|
||||
(("A", 3), (get_freq("A"), 3)),
|
||||
(("M", -2), (get_freq("M"), -2)),
|
||||
((5, "T"), (FreqGroup.FR_MIN, 5)),
|
||||
# Numeric Tuple.
|
||||
((1000, 1), (1000, 1)),
|
||||
# Offsets.
|
||||
(offsets.Day(), (get_freq("D"), 1)),
|
||||
(offsets.Day(3), (get_freq("D"), 3)),
|
||||
(offsets.Day(-2), (get_freq("D"), -2)),
|
||||
(offsets.MonthEnd(), (get_freq("M"), 1)),
|
||||
(offsets.MonthEnd(3), (get_freq("M"), 3)),
|
||||
(offsets.MonthEnd(-2), (get_freq("M"), -2)),
|
||||
(offsets.Week(), (get_freq("W"), 1)),
|
||||
(offsets.Week(3), (get_freq("W"), 3)),
|
||||
(offsets.Week(-2), (get_freq("W"), -2)),
|
||||
(offsets.Hour(), (FreqGroup.FR_HR, 1)),
|
||||
# Monday is weekday=0.
|
||||
(offsets.Week(weekday=1), (get_freq("W-TUE"), 1)),
|
||||
(offsets.Week(3, weekday=0), (get_freq("W-MON"), 3)),
|
||||
(offsets.Week(-2, weekday=4), (get_freq("W-FRI"), -2)),
|
||||
],
|
||||
)
|
||||
def test_get_freq_code(freq_input, expected):
|
||||
assert get_freq_code(freq_input) == expected
|
||||
|
||||
|
||||
def test_get_code_invalid():
|
||||
with pytest.raises(ValueError, match="Invalid frequency"):
|
||||
get_freq_code((5, "baz"))
|
||||
@@ -0,0 +1,535 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.ccalendar import DAYS, MONTHS
|
||||
from pandas._libs.tslibs.frequencies import INVALID_FREQ_ERR_MSG
|
||||
from pandas.compat import is_platform_windows
|
||||
|
||||
from pandas import DatetimeIndex, Index, Series, Timestamp, date_range, period_range
|
||||
from pandas.core.tools.datetimes import to_datetime
|
||||
import pandas.util.testing as tm
|
||||
|
||||
import pandas.tseries.frequencies as frequencies
|
||||
import pandas.tseries.offsets as offsets
|
||||
|
||||
|
||||
def _check_generated_range(start, periods, freq):
|
||||
"""
|
||||
Check the range generated from a given start, frequency, and period count.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
start : str
|
||||
The start date.
|
||||
periods : int
|
||||
The number of periods.
|
||||
freq : str
|
||||
The frequency of the range.
|
||||
"""
|
||||
freq = freq.upper()
|
||||
|
||||
gen = date_range(start, periods=periods, freq=freq)
|
||||
index = DatetimeIndex(gen.values)
|
||||
|
||||
if not freq.startswith("Q-"):
|
||||
assert frequencies.infer_freq(index) == gen.freqstr
|
||||
else:
|
||||
inf_freq = frequencies.infer_freq(index)
|
||||
is_dec_range = inf_freq == "Q-DEC" and gen.freqstr in (
|
||||
"Q",
|
||||
"Q-DEC",
|
||||
"Q-SEP",
|
||||
"Q-JUN",
|
||||
"Q-MAR",
|
||||
)
|
||||
is_nov_range = inf_freq == "Q-NOV" and gen.freqstr in (
|
||||
"Q-NOV",
|
||||
"Q-AUG",
|
||||
"Q-MAY",
|
||||
"Q-FEB",
|
||||
)
|
||||
is_oct_range = inf_freq == "Q-OCT" and gen.freqstr in (
|
||||
"Q-OCT",
|
||||
"Q-JUL",
|
||||
"Q-APR",
|
||||
"Q-JAN",
|
||||
)
|
||||
assert is_dec_range or is_nov_range or is_oct_range
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
params=[
|
||||
(timedelta(1), "D"),
|
||||
(timedelta(hours=1), "H"),
|
||||
(timedelta(minutes=1), "T"),
|
||||
(timedelta(seconds=1), "S"),
|
||||
(np.timedelta64(1, "ns"), "N"),
|
||||
(timedelta(microseconds=1), "U"),
|
||||
(timedelta(microseconds=1000), "L"),
|
||||
]
|
||||
)
|
||||
def base_delta_code_pair(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(params=[1, 2, 3, 4])
|
||||
def count(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(params=DAYS)
|
||||
def day(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(params=MONTHS)
|
||||
def month(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(params=[5, 7])
|
||||
def periods(request):
|
||||
return request.param
|
||||
|
||||
|
||||
def test_raise_if_period_index():
|
||||
index = period_range(start="1/1/1990", periods=20, freq="M")
|
||||
msg = "Check the `freq` attribute instead of using infer_freq"
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
frequencies.infer_freq(index)
|
||||
|
||||
|
||||
def test_raise_if_too_few():
|
||||
index = DatetimeIndex(["12/31/1998", "1/3/1999"])
|
||||
msg = "Need at least 3 dates to infer frequency"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
frequencies.infer_freq(index)
|
||||
|
||||
|
||||
def test_business_daily():
|
||||
index = DatetimeIndex(["01/01/1999", "1/4/1999", "1/5/1999"])
|
||||
assert frequencies.infer_freq(index) == "B"
|
||||
|
||||
|
||||
def test_business_daily_look_alike():
|
||||
# see gh-16624
|
||||
#
|
||||
# Do not infer "B when "weekend" (2-day gap) in wrong place.
|
||||
index = DatetimeIndex(["12/31/1998", "1/3/1999", "1/4/1999"])
|
||||
assert frequencies.infer_freq(index) is None
|
||||
|
||||
|
||||
def test_day_corner():
|
||||
index = DatetimeIndex(["1/1/2000", "1/2/2000", "1/3/2000"])
|
||||
assert frequencies.infer_freq(index) == "D"
|
||||
|
||||
|
||||
def test_non_datetime_index():
|
||||
dates = to_datetime(["1/1/2000", "1/2/2000", "1/3/2000"])
|
||||
assert frequencies.infer_freq(dates) == "D"
|
||||
|
||||
|
||||
def test_fifth_week_of_month_infer():
|
||||
# see gh-9425
|
||||
#
|
||||
# Only attempt to infer up to WOM-4.
|
||||
index = DatetimeIndex(["2014-03-31", "2014-06-30", "2015-03-30"])
|
||||
assert frequencies.infer_freq(index) is None
|
||||
|
||||
|
||||
def test_week_of_month_fake():
|
||||
# All of these dates are on same day
|
||||
# of week and are 4 or 5 weeks apart.
|
||||
index = DatetimeIndex(["2013-08-27", "2013-10-01", "2013-10-29", "2013-11-26"])
|
||||
assert frequencies.infer_freq(index) != "WOM-4TUE"
|
||||
|
||||
|
||||
def test_fifth_week_of_month():
|
||||
# see gh-9425
|
||||
#
|
||||
# Only supports freq up to WOM-4.
|
||||
msg = (
|
||||
"Of the four parameters: start, end, periods, "
|
||||
"and freq, exactly three must be specified"
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
date_range("2014-01-01", freq="WOM-5MON")
|
||||
|
||||
|
||||
def test_monthly_ambiguous():
|
||||
rng = DatetimeIndex(["1/31/2000", "2/29/2000", "3/31/2000"])
|
||||
assert rng.inferred_freq == "M"
|
||||
|
||||
|
||||
def test_annual_ambiguous():
|
||||
rng = DatetimeIndex(["1/31/2000", "1/31/2001", "1/31/2002"])
|
||||
assert rng.inferred_freq == "A-JAN"
|
||||
|
||||
|
||||
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 = "{count:d}{code}".format(count=count, code=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
|
||||
|
||||
|
||||
def test_weekly_infer(periods, day):
|
||||
_check_generated_range("1/1/2000", periods, "W-{day}".format(day=day))
|
||||
|
||||
|
||||
def test_week_of_month_infer(periods, day, count):
|
||||
_check_generated_range(
|
||||
"1/1/2000", periods, "WOM-{count}{day}".format(count=count, day=day)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", ["M", "BM", "BMS"])
|
||||
def test_monthly_infer(periods, freq):
|
||||
_check_generated_range("1/1/2000", periods, "M")
|
||||
|
||||
|
||||
def test_quarterly_infer(month, periods):
|
||||
_check_generated_range("1/1/2000", periods, "Q-{month}".format(month=month))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("annual", ["A", "BA"])
|
||||
def test_annually_infer(month, periods, annual):
|
||||
_check_generated_range(
|
||||
"1/1/2000", periods, "{annual}-{month}".format(annual=annual, month=month)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freq,expected", [("Q", "Q-DEC"), ("Q-NOV", "Q-NOV"), ("Q-OCT", "Q-OCT")]
|
||||
)
|
||||
def test_infer_freq_index(freq, expected):
|
||||
rng = period_range("1959Q2", "2009Q3", freq=freq)
|
||||
rng = Index(rng.to_timestamp("D", how="e").astype(object))
|
||||
|
||||
assert rng.inferred_freq == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected,dates",
|
||||
list(
|
||||
{
|
||||
"AS-JAN": ["2009-01-01", "2010-01-01", "2011-01-01", "2012-01-01"],
|
||||
"Q-OCT": ["2009-01-31", "2009-04-30", "2009-07-31", "2009-10-31"],
|
||||
"M": ["2010-11-30", "2010-12-31", "2011-01-31", "2011-02-28"],
|
||||
"W-SAT": ["2010-12-25", "2011-01-01", "2011-01-08", "2011-01-15"],
|
||||
"D": ["2011-01-01", "2011-01-02", "2011-01-03", "2011-01-04"],
|
||||
"H": [
|
||||
"2011-12-31 22:00",
|
||||
"2011-12-31 23:00",
|
||||
"2012-01-01 00:00",
|
||||
"2012-01-01 01:00",
|
||||
],
|
||||
}.items()
|
||||
),
|
||||
)
|
||||
def test_infer_freq_tz(tz_naive_fixture, expected, dates):
|
||||
# see gh-7310
|
||||
tz = tz_naive_fixture
|
||||
idx = DatetimeIndex(dates, tz=tz)
|
||||
assert idx.inferred_freq == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_pair",
|
||||
[
|
||||
["2013-11-02", "2013-11-5"], # Fall DST
|
||||
["2014-03-08", "2014-03-11"], # Spring DST
|
||||
["2014-01-01", "2014-01-03"], # Regular Time
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"freq", ["3H", "10T", "3601S", "3600001L", "3600000001U", "3600000000001N"]
|
||||
)
|
||||
def test_infer_freq_tz_transition(tz_naive_fixture, date_pair, freq):
|
||||
# see gh-8772
|
||||
tz = tz_naive_fixture
|
||||
idx = date_range(date_pair[0], date_pair[1], freq=freq, tz=tz)
|
||||
assert idx.inferred_freq == freq
|
||||
|
||||
|
||||
def test_infer_freq_tz_transition_custom():
|
||||
index = date_range("2013-11-03", periods=5, freq="3H").tz_localize(
|
||||
"America/Chicago"
|
||||
)
|
||||
assert index.inferred_freq is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data,expected",
|
||||
[
|
||||
# Hourly freq in a day must result in "H"
|
||||
(
|
||||
[
|
||||
"2014-07-01 09:00",
|
||||
"2014-07-01 10:00",
|
||||
"2014-07-01 11:00",
|
||||
"2014-07-01 12:00",
|
||||
"2014-07-01 13:00",
|
||||
"2014-07-01 14:00",
|
||||
],
|
||||
"H",
|
||||
),
|
||||
(
|
||||
[
|
||||
"2014-07-01 09:00",
|
||||
"2014-07-01 10:00",
|
||||
"2014-07-01 11:00",
|
||||
"2014-07-01 12:00",
|
||||
"2014-07-01 13:00",
|
||||
"2014-07-01 14:00",
|
||||
"2014-07-01 15:00",
|
||||
"2014-07-01 16:00",
|
||||
"2014-07-02 09:00",
|
||||
"2014-07-02 10:00",
|
||||
"2014-07-02 11:00",
|
||||
],
|
||||
"BH",
|
||||
),
|
||||
(
|
||||
[
|
||||
"2014-07-04 09:00",
|
||||
"2014-07-04 10:00",
|
||||
"2014-07-04 11:00",
|
||||
"2014-07-04 12:00",
|
||||
"2014-07-04 13:00",
|
||||
"2014-07-04 14:00",
|
||||
"2014-07-04 15:00",
|
||||
"2014-07-04 16:00",
|
||||
"2014-07-07 09:00",
|
||||
"2014-07-07 10:00",
|
||||
"2014-07-07 11:00",
|
||||
],
|
||||
"BH",
|
||||
),
|
||||
(
|
||||
[
|
||||
"2014-07-04 09:00",
|
||||
"2014-07-04 10:00",
|
||||
"2014-07-04 11:00",
|
||||
"2014-07-04 12:00",
|
||||
"2014-07-04 13:00",
|
||||
"2014-07-04 14:00",
|
||||
"2014-07-04 15:00",
|
||||
"2014-07-04 16:00",
|
||||
"2014-07-07 09:00",
|
||||
"2014-07-07 10:00",
|
||||
"2014-07-07 11:00",
|
||||
"2014-07-07 12:00",
|
||||
"2014-07-07 13:00",
|
||||
"2014-07-07 14:00",
|
||||
"2014-07-07 15:00",
|
||||
"2014-07-07 16:00",
|
||||
"2014-07-08 09:00",
|
||||
"2014-07-08 10:00",
|
||||
"2014-07-08 11:00",
|
||||
"2014-07-08 12:00",
|
||||
"2014-07-08 13:00",
|
||||
"2014-07-08 14:00",
|
||||
"2014-07-08 15:00",
|
||||
"2014-07-08 16:00",
|
||||
],
|
||||
"BH",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_infer_freq_business_hour(data, expected):
|
||||
# see gh-7905
|
||||
idx = DatetimeIndex(data)
|
||||
assert idx.inferred_freq == expected
|
||||
|
||||
|
||||
def test_not_monotonic():
|
||||
rng = DatetimeIndex(["1/31/2000", "1/31/2001", "1/31/2002"])
|
||||
rng = rng[::-1]
|
||||
|
||||
assert rng.inferred_freq == "-1A-JAN"
|
||||
|
||||
|
||||
def test_non_datetime_index2():
|
||||
rng = DatetimeIndex(["1/31/2000", "1/31/2001", "1/31/2002"])
|
||||
vals = rng.to_pydatetime()
|
||||
|
||||
result = frequencies.infer_freq(vals)
|
||||
assert result == rng.inferred_freq
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"idx", [tm.makeIntIndex(10), tm.makeFloatIndex(10), tm.makePeriodIndex(10)]
|
||||
)
|
||||
def test_invalid_index_types(idx):
|
||||
msg = (
|
||||
"(cannot infer freq from a non-convertible)|"
|
||||
"(Check the `freq` attribute instead of using infer_freq)"
|
||||
)
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
frequencies.infer_freq(idx)
|
||||
|
||||
|
||||
@pytest.mark.skipif(is_platform_windows(), reason="see gh-10822: Windows issue")
|
||||
@pytest.mark.parametrize("idx", [tm.makeStringIndex(10), tm.makeUnicodeIndex(10)])
|
||||
def test_invalid_index_types_unicode(idx):
|
||||
# see gh-10822
|
||||
#
|
||||
# Odd error message on conversions to datetime for unicode.
|
||||
msg = "Unknown string format"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
frequencies.infer_freq(idx)
|
||||
|
||||
|
||||
def test_string_datetime_like_compat():
|
||||
# see gh-6463
|
||||
data = ["2004-01", "2004-02", "2004-03", "2004-04"]
|
||||
|
||||
expected = frequencies.infer_freq(data)
|
||||
result = frequencies.infer_freq(Index(data))
|
||||
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_series():
|
||||
# see gh-6407
|
||||
s = Series(date_range("20130101", "20130110"))
|
||||
inferred = frequencies.infer_freq(s)
|
||||
assert inferred == "D"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("end", [10, 10.0])
|
||||
def test_series_invalid_type(end):
|
||||
# see gh-6407
|
||||
msg = "cannot infer freq from a non-convertible dtype on a Series"
|
||||
s = Series(np.arange(end))
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
frequencies.infer_freq(s)
|
||||
|
||||
|
||||
def test_series_inconvertible_string():
|
||||
# see gh-6407
|
||||
msg = "Unknown string format"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
frequencies.infer_freq(Series(["foo", "bar"]))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", [None, "L"])
|
||||
def test_series_period_index(freq):
|
||||
# see gh-6407
|
||||
#
|
||||
# Cannot infer on PeriodIndex
|
||||
msg = "cannot infer freq from a non-convertible dtype on a Series"
|
||||
s = Series(period_range("2013", periods=10, freq=freq))
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
frequencies.infer_freq(s)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", ["M", "L", "S"])
|
||||
def test_series_datetime_index(freq):
|
||||
s = Series(date_range("20130101", periods=10, freq=freq))
|
||||
inferred = frequencies.infer_freq(s)
|
||||
assert inferred == freq
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"offset_func",
|
||||
[
|
||||
frequencies.get_offset,
|
||||
lambda freq: date_range("2011-01-01", periods=5, freq=freq),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"freq",
|
||||
[
|
||||
"WEEKDAY",
|
||||
"EOM",
|
||||
"W@MON",
|
||||
"W@TUE",
|
||||
"W@WED",
|
||||
"W@THU",
|
||||
"W@FRI",
|
||||
"W@SAT",
|
||||
"W@SUN",
|
||||
"Q@JAN",
|
||||
"Q@FEB",
|
||||
"Q@MAR",
|
||||
"A@JAN",
|
||||
"A@FEB",
|
||||
"A@MAR",
|
||||
"A@APR",
|
||||
"A@MAY",
|
||||
"A@JUN",
|
||||
"A@JUL",
|
||||
"A@AUG",
|
||||
"A@SEP",
|
||||
"A@OCT",
|
||||
"A@NOV",
|
||||
"A@DEC",
|
||||
"Y@JAN",
|
||||
"WOM@1MON",
|
||||
"WOM@2MON",
|
||||
"WOM@3MON",
|
||||
"WOM@4MON",
|
||||
"WOM@1TUE",
|
||||
"WOM@2TUE",
|
||||
"WOM@3TUE",
|
||||
"WOM@4TUE",
|
||||
"WOM@1WED",
|
||||
"WOM@2WED",
|
||||
"WOM@3WED",
|
||||
"WOM@4WED",
|
||||
"WOM@1THU",
|
||||
"WOM@2THU",
|
||||
"WOM@3THU",
|
||||
"WOM@4THU",
|
||||
"WOM@1FRI",
|
||||
"WOM@2FRI",
|
||||
"WOM@3FRI",
|
||||
"WOM@4FRI",
|
||||
],
|
||||
)
|
||||
def test_legacy_offset_warnings(offset_func, freq):
|
||||
with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG):
|
||||
offset_func(freq)
|
||||
|
||||
|
||||
def test_ms_vs_capital_ms():
|
||||
left = frequencies.get_offset("ms")
|
||||
right = frequencies.get_offset("MS")
|
||||
|
||||
assert left == offsets.Milli()
|
||||
assert right == offsets.MonthBegin()
|
||||
@@ -0,0 +1,176 @@
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas import Timedelta
|
||||
|
||||
import pandas.tseries.frequencies as frequencies
|
||||
import pandas.tseries.offsets as offsets
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freq_input,expected",
|
||||
[
|
||||
(frequencies.to_offset("10us"), offsets.Micro(10)),
|
||||
(offsets.Hour(), offsets.Hour()),
|
||||
((5, "T"), offsets.Minute(5)),
|
||||
("2h30min", offsets.Minute(150)),
|
||||
("2h 30min", offsets.Minute(150)),
|
||||
("2h30min15s", offsets.Second(150 * 60 + 15)),
|
||||
("2h 60min", offsets.Hour(3)),
|
||||
("2h 20.5min", offsets.Second(8430)),
|
||||
("1.5min", offsets.Second(90)),
|
||||
("0.5S", offsets.Milli(500)),
|
||||
("15l500u", offsets.Micro(15500)),
|
||||
("10s75L", offsets.Milli(10075)),
|
||||
("1s0.25ms", offsets.Micro(1000250)),
|
||||
("1s0.25L", offsets.Micro(1000250)),
|
||||
("2800N", offsets.Nano(2800)),
|
||||
("2SM", offsets.SemiMonthEnd(2)),
|
||||
("2SM-16", offsets.SemiMonthEnd(2, day_of_month=16)),
|
||||
("2SMS-14", offsets.SemiMonthBegin(2, day_of_month=14)),
|
||||
("2SMS-15", offsets.SemiMonthBegin(2)),
|
||||
],
|
||||
)
|
||||
def test_to_offset(freq_input, expected):
|
||||
result = frequencies.to_offset(freq_input)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected", [("-1S", -1), ("-2SM", -2), ("-1SMS", -1), ("-5min10s", -310)]
|
||||
)
|
||||
def test_to_offset_negative(freqstr, expected):
|
||||
result = frequencies.to_offset(freqstr)
|
||||
assert result.n == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr",
|
||||
[
|
||||
"2h20m",
|
||||
"U1",
|
||||
"-U",
|
||||
"3U1",
|
||||
"-2-3U",
|
||||
"-2D:3H",
|
||||
"1.5.0S",
|
||||
"2SMS-15-15",
|
||||
"2SMS-15D",
|
||||
"100foo",
|
||||
# Invalid leading +/- signs.
|
||||
"+-1d",
|
||||
"-+1h",
|
||||
"+1",
|
||||
"-7",
|
||||
"+d",
|
||||
"-m",
|
||||
# Invalid shortcut anchors.
|
||||
"SM-0",
|
||||
"SM-28",
|
||||
"SM-29",
|
||||
"SM-FOO",
|
||||
"BSM",
|
||||
"SM--1",
|
||||
"SMS-1",
|
||||
"SMS-28",
|
||||
"SMS-30",
|
||||
"SMS-BAR",
|
||||
"SMS-BYR",
|
||||
"BSMS",
|
||||
"SMS--2",
|
||||
],
|
||||
)
|
||||
def test_to_offset_invalid(freqstr):
|
||||
# see gh-13930
|
||||
|
||||
# We escape string because some of our
|
||||
# inputs contain regex special characters.
|
||||
msg = re.escape("Invalid frequency: {freqstr}".format(freqstr=freqstr))
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
frequencies.to_offset(freqstr)
|
||||
|
||||
|
||||
def test_to_offset_no_evaluate():
|
||||
with pytest.raises(ValueError, match="Could not evaluate"):
|
||||
frequencies.to_offset(("", ""))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected",
|
||||
[
|
||||
("2D 3H", offsets.Hour(51)),
|
||||
("2 D3 H", offsets.Hour(51)),
|
||||
("2 D 3 H", offsets.Hour(51)),
|
||||
(" 2 D 3 H ", offsets.Hour(51)),
|
||||
(" H ", offsets.Hour()),
|
||||
(" 3 H ", offsets.Hour(3)),
|
||||
],
|
||||
)
|
||||
def test_to_offset_whitespace(freqstr, expected):
|
||||
result = frequencies.to_offset(freqstr)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected", [("00H 00T 01S", 1), ("-00H 03T 14S", -194)]
|
||||
)
|
||||
def test_to_offset_leading_zero(freqstr, expected):
|
||||
result = frequencies.to_offset(freqstr)
|
||||
assert result.n == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freqstr,expected", [("+1d", 1), ("+2h30min", 150)])
|
||||
def test_to_offset_leading_plus(freqstr, expected):
|
||||
result = frequencies.to_offset(freqstr)
|
||||
assert result.n == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"kwargs,expected",
|
||||
[
|
||||
(dict(days=1, seconds=1), offsets.Second(86401)),
|
||||
(dict(days=-1, seconds=1), offsets.Second(-86399)),
|
||||
(dict(hours=1, minutes=10), offsets.Minute(70)),
|
||||
(dict(hours=1, minutes=-10), offsets.Minute(50)),
|
||||
(dict(weeks=1), offsets.Day(7)),
|
||||
(dict(hours=1), offsets.Hour(1)),
|
||||
(dict(hours=1), frequencies.to_offset("60min")),
|
||||
(dict(microseconds=1), offsets.Micro(1)),
|
||||
],
|
||||
)
|
||||
def test_to_offset_pd_timedelta(kwargs, expected):
|
||||
# see gh-9064
|
||||
td = Timedelta(**kwargs)
|
||||
result = frequencies.to_offset(td)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_to_offset_pd_timedelta_invalid():
|
||||
# see gh-9064
|
||||
msg = "Invalid frequency: 0 days 00:00:00"
|
||||
td = Timedelta(microseconds=0)
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
frequencies.to_offset(td)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"shortcut,expected",
|
||||
[
|
||||
("W", offsets.Week(weekday=6)),
|
||||
("W-SUN", offsets.Week(weekday=6)),
|
||||
("Q", offsets.QuarterEnd(startingMonth=12)),
|
||||
("Q-DEC", offsets.QuarterEnd(startingMonth=12)),
|
||||
("Q-MAY", offsets.QuarterEnd(startingMonth=5)),
|
||||
("SM", offsets.SemiMonthEnd(day_of_month=15)),
|
||||
("SM-15", offsets.SemiMonthEnd(day_of_month=15)),
|
||||
("SM-1", offsets.SemiMonthEnd(day_of_month=1)),
|
||||
("SM-27", offsets.SemiMonthEnd(day_of_month=27)),
|
||||
("SMS-2", offsets.SemiMonthBegin(day_of_month=2)),
|
||||
("SMS-27", offsets.SemiMonthBegin(day_of_month=27)),
|
||||
],
|
||||
)
|
||||
def test_anchored_shortcuts(shortcut, expected):
|
||||
result = frequencies.to_offset(shortcut)
|
||||
assert result == expected
|
||||
@@ -0,0 +1,83 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas import DatetimeIndex
|
||||
import pandas.util.testing as tm
|
||||
|
||||
from pandas.tseries.holiday import (
|
||||
AbstractHolidayCalendar,
|
||||
Holiday,
|
||||
Timestamp,
|
||||
USFederalHolidayCalendar,
|
||||
USThanksgivingDay,
|
||||
get_calendar,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"transform", [lambda x: x, lambda x: x.strftime("%Y-%m-%d"), lambda x: Timestamp(x)]
|
||||
)
|
||||
def test_calendar(transform):
|
||||
start_date = datetime(2012, 1, 1)
|
||||
end_date = datetime(2012, 12, 31)
|
||||
|
||||
calendar = USFederalHolidayCalendar()
|
||||
holidays = calendar.holidays(transform(start_date), transform(end_date))
|
||||
|
||||
expected = [
|
||||
datetime(2012, 1, 2),
|
||||
datetime(2012, 1, 16),
|
||||
datetime(2012, 2, 20),
|
||||
datetime(2012, 5, 28),
|
||||
datetime(2012, 7, 4),
|
||||
datetime(2012, 9, 3),
|
||||
datetime(2012, 10, 8),
|
||||
datetime(2012, 11, 12),
|
||||
datetime(2012, 11, 22),
|
||||
datetime(2012, 12, 25),
|
||||
]
|
||||
|
||||
assert list(holidays.to_pydatetime()) == expected
|
||||
|
||||
|
||||
def test_calendar_caching():
|
||||
# see gh-9552.
|
||||
|
||||
class TestCalendar(AbstractHolidayCalendar):
|
||||
def __init__(self, name=None, rules=None):
|
||||
super().__init__(name=name, rules=rules)
|
||||
|
||||
jan1 = TestCalendar(rules=[Holiday("jan1", year=2015, month=1, day=1)])
|
||||
jan2 = TestCalendar(rules=[Holiday("jan2", year=2015, month=1, day=2)])
|
||||
|
||||
# Getting holidays for Jan 1 should not alter results for Jan 2.
|
||||
tm.assert_index_equal(jan1.holidays(), DatetimeIndex(["01-Jan-2015"]))
|
||||
tm.assert_index_equal(jan2.holidays(), DatetimeIndex(["02-Jan-2015"]))
|
||||
|
||||
|
||||
def test_calendar_observance_dates():
|
||||
# see gh-11477
|
||||
us_fed_cal = get_calendar("USFederalHolidayCalendar")
|
||||
holidays0 = us_fed_cal.holidays(
|
||||
datetime(2015, 7, 3), datetime(2015, 7, 3)
|
||||
) # <-- same start and end dates
|
||||
holidays1 = us_fed_cal.holidays(
|
||||
datetime(2015, 7, 3), datetime(2015, 7, 6)
|
||||
) # <-- different start and end dates
|
||||
holidays2 = us_fed_cal.holidays(
|
||||
datetime(2015, 7, 3), datetime(2015, 7, 3)
|
||||
) # <-- same start and end dates
|
||||
|
||||
# These should all produce the same result.
|
||||
#
|
||||
# In addition, calling with different start and end
|
||||
# dates should not alter the output if we call the
|
||||
# function again with the same start and end date.
|
||||
tm.assert_index_equal(holidays0, holidays1)
|
||||
tm.assert_index_equal(holidays0, holidays2)
|
||||
|
||||
|
||||
def test_rule_from_name():
|
||||
us_fed_cal = get_calendar("USFederalHolidayCalendar")
|
||||
assert us_fed_cal.rule_from_name("Thanksgiving") == USThanksgivingDay
|
||||
@@ -0,0 +1,38 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pandas.tseries.holiday import (
|
||||
AbstractHolidayCalendar,
|
||||
USMartinLutherKingJr,
|
||||
USMemorialDay,
|
||||
)
|
||||
|
||||
|
||||
def test_no_mlk_before_1986():
|
||||
# see gh-10278
|
||||
class MLKCalendar(AbstractHolidayCalendar):
|
||||
rules = [USMartinLutherKingJr]
|
||||
|
||||
holidays = MLKCalendar().holidays(start="1984", end="1988").to_pydatetime().tolist()
|
||||
|
||||
# Testing to make sure holiday is not incorrectly observed before 1986.
|
||||
assert holidays == [datetime(1986, 1, 20, 0, 0), datetime(1987, 1, 19, 0, 0)]
|
||||
|
||||
|
||||
def test_memorial_day():
|
||||
class MemorialDay(AbstractHolidayCalendar):
|
||||
rules = [USMemorialDay]
|
||||
|
||||
holidays = MemorialDay().holidays(start="1971", end="1980").to_pydatetime().tolist()
|
||||
|
||||
# Fixes 5/31 error and checked manually against Wikipedia.
|
||||
assert holidays == [
|
||||
datetime(1971, 5, 31, 0, 0),
|
||||
datetime(1972, 5, 29, 0, 0),
|
||||
datetime(1973, 5, 28, 0, 0),
|
||||
datetime(1974, 5, 27, 0, 0),
|
||||
datetime(1975, 5, 26, 0, 0),
|
||||
datetime(1976, 5, 31, 0, 0),
|
||||
datetime(1977, 5, 30, 0, 0),
|
||||
datetime(1978, 5, 29, 0, 0),
|
||||
datetime(1979, 5, 28, 0, 0),
|
||||
]
|
||||
@@ -0,0 +1,268 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from pytz import utc
|
||||
|
||||
import pandas.util.testing as tm
|
||||
|
||||
from pandas.tseries.holiday import (
|
||||
MO,
|
||||
SA,
|
||||
AbstractHolidayCalendar,
|
||||
DateOffset,
|
||||
EasterMonday,
|
||||
GoodFriday,
|
||||
Holiday,
|
||||
HolidayCalendarFactory,
|
||||
Timestamp,
|
||||
USColumbusDay,
|
||||
USLaborDay,
|
||||
USMartinLutherKingJr,
|
||||
USMemorialDay,
|
||||
USPresidentsDay,
|
||||
USThanksgivingDay,
|
||||
get_calendar,
|
||||
next_monday,
|
||||
)
|
||||
|
||||
|
||||
def _check_holiday_results(holiday, start, end, expected):
|
||||
"""
|
||||
Check that the dates for a given holiday match in date and timezone.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
holiday : Holiday
|
||||
The holiday to check.
|
||||
start : datetime-like
|
||||
The start date of range in which to collect dates for a given holiday.
|
||||
end : datetime-like
|
||||
The end date of range in which to collect dates for a given holiday.
|
||||
expected : list
|
||||
The list of dates we expect to get.
|
||||
"""
|
||||
assert list(holiday.dates(start, end)) == expected
|
||||
|
||||
# Verify that timezone info is preserved.
|
||||
assert list(
|
||||
holiday.dates(utc.localize(Timestamp(start)), utc.localize(Timestamp(end)))
|
||||
) == [utc.localize(dt) for dt in expected]
|
||||
|
||||
|
||||
@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):
|
||||
_check_holiday_results(holiday, start_date, end_date, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"holiday,start,expected",
|
||||
[
|
||||
(USMemorialDay, datetime(2015, 7, 1), []),
|
||||
(USMemorialDay, "2015-05-25", "2015-05-25"),
|
||||
(USLaborDay, datetime(2015, 7, 1), []),
|
||||
(USLaborDay, "2015-09-07", "2015-09-07"),
|
||||
(USColumbusDay, datetime(2015, 7, 1), []),
|
||||
(USColumbusDay, "2015-10-12", "2015-10-12"),
|
||||
(USThanksgivingDay, datetime(2015, 7, 1), []),
|
||||
(USThanksgivingDay, "2015-11-26", "2015-11-26"),
|
||||
(USMartinLutherKingJr, datetime(2015, 7, 1), []),
|
||||
(USMartinLutherKingJr, "2015-01-19", "2015-01-19"),
|
||||
(USPresidentsDay, datetime(2015, 7, 1), []),
|
||||
(USPresidentsDay, "2015-02-16", "2015-02-16"),
|
||||
(GoodFriday, datetime(2015, 7, 1), []),
|
||||
(GoodFriday, "2015-04-03", "2015-04-03"),
|
||||
(EasterMonday, "2015-04-06", "2015-04-06"),
|
||||
(EasterMonday, datetime(2015, 7, 1), []),
|
||||
(EasterMonday, "2015-04-05", []),
|
||||
("New Years Day", "2015-01-01", "2015-01-01"),
|
||||
("New Years Day", "2010-12-31", "2010-12-31"),
|
||||
("New Years Day", datetime(2015, 7, 1), []),
|
||||
("New Years Day", "2011-01-01", []),
|
||||
("July 4th", "2015-07-03", "2015-07-03"),
|
||||
("July 4th", datetime(2015, 7, 1), []),
|
||||
("July 4th", "2015-07-04", []),
|
||||
("Veterans Day", "2012-11-12", "2012-11-12"),
|
||||
("Veterans Day", datetime(2015, 7, 1), []),
|
||||
("Veterans Day", "2012-11-11", []),
|
||||
("Christmas", "2011-12-26", "2011-12-26"),
|
||||
("Christmas", datetime(2015, 7, 1), []),
|
||||
("Christmas", "2011-12-25", []),
|
||||
],
|
||||
)
|
||||
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)
|
||||
|
||||
if isinstance(expected, str):
|
||||
expected = [Timestamp(expected)]
|
||||
|
||||
_check_holiday_results(holiday, start, start, 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", dict(year=2012, month=5, day=28)),
|
||||
(
|
||||
"Range",
|
||||
dict(
|
||||
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 == calendar.__class__
|
||||
|
||||
|
||||
def test_factory():
|
||||
class_1 = HolidayCalendarFactory(
|
||||
"MemorialDay", AbstractHolidayCalendar, USMemorialDay
|
||||
)
|
||||
class_2 = HolidayCalendarFactory(
|
||||
"Thanksgiving", AbstractHolidayCalendar, USThanksgivingDay
|
||||
)
|
||||
class_3 = HolidayCalendarFactory("Combined", class_1, class_2)
|
||||
|
||||
assert len(class_1.rules) == 1
|
||||
assert len(class_2.rules) == 1
|
||||
assert len(class_3.rules) == 2
|
||||
|
||||
|
||||
def test_both_offset_observance_raises():
|
||||
# see gh-10217
|
||||
msg = "Cannot use both offset and observance"
|
||||
with pytest.raises(NotImplementedError, match=msg):
|
||||
Holiday(
|
||||
"Cyber Monday",
|
||||
month=11,
|
||||
day=1,
|
||||
offset=[DateOffset(weekday=SA(4))],
|
||||
observance=next_monday,
|
||||
)
|
||||
@@ -0,0 +1,87 @@
|
||||
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)
|
||||
|
||||
|
||||
@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", [(_SATURDAY, _MONDAY), (_SUNDAY, _MONDAY), (_MONDAY, _TUESDAY)]
|
||||
)
|
||||
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", [(_SATURDAY, _THURSDAY), (_SUNDAY, _FRIDAY), (_TUESDAY, _MONDAY)]
|
||||
)
|
||||
def test_before_nearest_workday(day, expected):
|
||||
assert before_nearest_workday(day) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"day,expected", [(_SATURDAY, _MONDAY), (_SUNDAY, _TUESDAY), (_FRIDAY, _MONDAY)]
|
||||
)
|
||||
def test_after_nearest_workday(day, expected):
|
||||
assert after_nearest_workday(day) == expected
|
||||
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
Assertion helpers for offsets tests
|
||||
"""
|
||||
|
||||
|
||||
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:
|
||||
raise AssertionError(
|
||||
"\nExpected: {expected}\nActual: {actual}\nFor Offset: {offset})"
|
||||
"\nAt Date: {base}".format(
|
||||
expected=expected, actual=actual, offset=offset, base=base
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def assert_onOffset(offset, date, expected):
|
||||
actual = offset.onOffset(date)
|
||||
assert actual == expected, (
|
||||
"\nExpected: {expected}\nActual: {actual}\nFor Offset: {offset})"
|
||||
"\nAt Date: {date}".format(
|
||||
expected=expected, actual=actual, offset=offset, date=date
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
import pytest
|
||||
|
||||
import pandas.tseries.offsets as offsets
|
||||
|
||||
|
||||
@pytest.fixture(params=[getattr(offsets, o) for o in offsets.__all__])
|
||||
def offset_types(request):
|
||||
"""
|
||||
Fixture for all the datetime offsets available for a time series.
|
||||
"""
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
params=[
|
||||
getattr(offsets, o)
|
||||
for o in offsets.__all__
|
||||
if issubclass(getattr(offsets, o), offsets.MonthOffset) and o != "MonthOffset"
|
||||
]
|
||||
)
|
||||
def month_classes(request):
|
||||
"""
|
||||
Fixture for month based datetime offsets available for a time series.
|
||||
"""
|
||||
return request.param
|
||||
@@ -0,0 +1,689 @@
|
||||
"""
|
||||
Tests for Fiscal Year and Fiscal Quarter offset classes
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.frequencies import INVALID_FREQ_ERR_MSG
|
||||
|
||||
from pandas import Timestamp
|
||||
|
||||
from pandas.tseries.frequencies import get_offset
|
||||
from pandas.tseries.offsets import FY5253, FY5253Quarter
|
||||
|
||||
from .common import assert_offset_equal, assert_onOffset
|
||||
from .test_offsets import Base, WeekDay
|
||||
|
||||
|
||||
def makeFY5253LastOfMonthQuarter(*args, **kwds):
|
||||
return FY5253Quarter(*args, variation="last", **kwds)
|
||||
|
||||
|
||||
def makeFY5253NearestEndMonthQuarter(*args, **kwds):
|
||||
return FY5253Quarter(*args, variation="nearest", **kwds)
|
||||
|
||||
|
||||
def makeFY5253NearestEndMonth(*args, **kwds):
|
||||
return FY5253(*args, variation="nearest", **kwds)
|
||||
|
||||
|
||||
def makeFY5253LastOfMonth(*args, **kwds):
|
||||
return FY5253(*args, variation="last", **kwds)
|
||||
|
||||
|
||||
def test_get_offset_name():
|
||||
assert (
|
||||
makeFY5253LastOfMonthQuarter(
|
||||
weekday=1, startingMonth=3, qtr_with_extra_week=4
|
||||
).freqstr
|
||||
== "REQ-L-MAR-TUE-4"
|
||||
)
|
||||
assert (
|
||||
makeFY5253NearestEndMonthQuarter(
|
||||
weekday=1, startingMonth=3, qtr_with_extra_week=3
|
||||
).freqstr
|
||||
== "REQ-N-MAR-TUE-3"
|
||||
)
|
||||
|
||||
|
||||
def test_get_offset():
|
||||
with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG):
|
||||
get_offset("gibberish")
|
||||
with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG):
|
||||
get_offset("QS-JAN-B")
|
||||
|
||||
pairs = [
|
||||
("RE-N-DEC-MON", makeFY5253NearestEndMonth(weekday=0, startingMonth=12)),
|
||||
("RE-L-DEC-TUE", makeFY5253LastOfMonth(weekday=1, startingMonth=12)),
|
||||
(
|
||||
"REQ-L-MAR-TUE-4",
|
||||
makeFY5253LastOfMonthQuarter(
|
||||
weekday=1, startingMonth=3, qtr_with_extra_week=4
|
||||
),
|
||||
),
|
||||
(
|
||||
"REQ-L-DEC-MON-3",
|
||||
makeFY5253LastOfMonthQuarter(
|
||||
weekday=0, startingMonth=12, qtr_with_extra_week=3
|
||||
),
|
||||
),
|
||||
(
|
||||
"REQ-N-DEC-MON-3",
|
||||
makeFY5253NearestEndMonthQuarter(
|
||||
weekday=0, startingMonth=12, qtr_with_extra_week=3
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
for name, expected in pairs:
|
||||
offset = get_offset(name)
|
||||
assert (
|
||||
offset == expected
|
||||
), "Expected {name!r} to yield {expected!r} (actual: {offset!r})".format(
|
||||
name=name, expected=expected, offset=offset
|
||||
)
|
||||
|
||||
|
||||
class TestFY5253LastOfMonth(Base):
|
||||
offset_lom_sat_aug = makeFY5253LastOfMonth(1, startingMonth=8, weekday=WeekDay.SAT)
|
||||
offset_lom_sat_sep = makeFY5253LastOfMonth(1, startingMonth=9, weekday=WeekDay.SAT)
|
||||
|
||||
on_offset_cases = [
|
||||
# From Wikipedia (see:
|
||||
# http://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_onOffset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_onOffset(offset, dt, expected)
|
||||
|
||||
def test_apply(self):
|
||||
offset_lom_aug_sat = makeFY5253LastOfMonth(startingMonth=8, weekday=WeekDay.SAT)
|
||||
offset_lom_aug_sat_1 = makeFY5253LastOfMonth(
|
||||
n=1, startingMonth=8, weekday=WeekDay.SAT
|
||||
)
|
||||
|
||||
date_seq_lom_aug_sat = [
|
||||
datetime(2006, 8, 26),
|
||||
datetime(2007, 8, 25),
|
||||
datetime(2008, 8, 30),
|
||||
datetime(2009, 8, 29),
|
||||
datetime(2010, 8, 28),
|
||||
datetime(2011, 8, 27),
|
||||
datetime(2012, 8, 25),
|
||||
datetime(2013, 8, 31),
|
||||
datetime(2014, 8, 30),
|
||||
datetime(2015, 8, 29),
|
||||
datetime(2016, 8, 27),
|
||||
]
|
||||
|
||||
tests = [
|
||||
(offset_lom_aug_sat, date_seq_lom_aug_sat),
|
||||
(offset_lom_aug_sat_1, date_seq_lom_aug_sat),
|
||||
(offset_lom_aug_sat, [datetime(2006, 8, 25)] + date_seq_lom_aug_sat),
|
||||
(offset_lom_aug_sat_1, [datetime(2006, 8, 27)] + date_seq_lom_aug_sat[1:]),
|
||||
(
|
||||
makeFY5253LastOfMonth(n=-1, startingMonth=8, weekday=WeekDay.SAT),
|
||||
list(reversed(date_seq_lom_aug_sat)),
|
||||
),
|
||||
]
|
||||
for test in tests:
|
||||
offset, data = test
|
||||
current = data[0]
|
||||
for datum in data[1:]:
|
||||
current = current + offset
|
||||
assert current == datum
|
||||
|
||||
|
||||
class TestFY5253NearestEndMonth(Base):
|
||||
def test_get_year_end(self):
|
||||
assert makeFY5253NearestEndMonth(
|
||||
startingMonth=8, weekday=WeekDay.SAT
|
||||
).get_year_end(datetime(2013, 1, 1)) == datetime(2013, 8, 31)
|
||||
assert makeFY5253NearestEndMonth(
|
||||
startingMonth=8, weekday=WeekDay.SUN
|
||||
).get_year_end(datetime(2013, 1, 1)) == datetime(2013, 9, 1)
|
||||
assert makeFY5253NearestEndMonth(
|
||||
startingMonth=8, weekday=WeekDay.FRI
|
||||
).get_year_end(datetime(2013, 1, 1)) == datetime(2013, 8, 30)
|
||||
|
||||
offset_n = FY5253(weekday=WeekDay.TUE, startingMonth=12, variation="nearest")
|
||||
assert offset_n.get_year_end(datetime(2012, 1, 1)) == datetime(2013, 1, 1)
|
||||
assert offset_n.get_year_end(datetime(2012, 1, 10)) == datetime(2013, 1, 1)
|
||||
|
||||
assert offset_n.get_year_end(datetime(2013, 1, 1)) == datetime(2013, 12, 31)
|
||||
assert offset_n.get_year_end(datetime(2013, 1, 2)) == datetime(2013, 12, 31)
|
||||
assert offset_n.get_year_end(datetime(2013, 1, 3)) == datetime(2013, 12, 31)
|
||||
assert offset_n.get_year_end(datetime(2013, 1, 10)) == datetime(2013, 12, 31)
|
||||
|
||||
JNJ = FY5253(n=1, startingMonth=12, weekday=6, variation="nearest")
|
||||
assert JNJ.get_year_end(datetime(2006, 1, 1)) == datetime(2006, 12, 31)
|
||||
|
||||
offset_lom_aug_sat = makeFY5253NearestEndMonth(
|
||||
1, startingMonth=8, weekday=WeekDay.SAT
|
||||
)
|
||||
offset_lom_aug_thu = makeFY5253NearestEndMonth(
|
||||
1, startingMonth=8, weekday=WeekDay.THU
|
||||
)
|
||||
offset_n = FY5253(weekday=WeekDay.TUE, startingMonth=12, variation="nearest")
|
||||
|
||||
on_offset_cases = [
|
||||
# From Wikipedia (see:
|
||||
# http://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_onOffset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_onOffset(offset, dt, expected)
|
||||
|
||||
def test_apply(self):
|
||||
date_seq_nem_8_sat = [
|
||||
datetime(2006, 9, 2),
|
||||
datetime(2007, 9, 1),
|
||||
datetime(2008, 8, 30),
|
||||
datetime(2009, 8, 29),
|
||||
datetime(2010, 8, 28),
|
||||
datetime(2011, 9, 3),
|
||||
]
|
||||
|
||||
JNJ = [
|
||||
datetime(2005, 1, 2),
|
||||
datetime(2006, 1, 1),
|
||||
datetime(2006, 12, 31),
|
||||
datetime(2007, 12, 30),
|
||||
datetime(2008, 12, 28),
|
||||
datetime(2010, 1, 3),
|
||||
datetime(2011, 1, 2),
|
||||
datetime(2012, 1, 1),
|
||||
datetime(2012, 12, 30),
|
||||
]
|
||||
|
||||
DEC_SAT = FY5253(n=-1, startingMonth=12, weekday=5, variation="nearest")
|
||||
|
||||
tests = [
|
||||
(
|
||||
makeFY5253NearestEndMonth(startingMonth=8, weekday=WeekDay.SAT),
|
||||
date_seq_nem_8_sat,
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=1, startingMonth=8, weekday=WeekDay.SAT),
|
||||
date_seq_nem_8_sat,
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(startingMonth=8, weekday=WeekDay.SAT),
|
||||
[datetime(2006, 9, 1)] + date_seq_nem_8_sat,
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=1, startingMonth=8, weekday=WeekDay.SAT),
|
||||
[datetime(2006, 9, 3)] + date_seq_nem_8_sat[1:],
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=-1, startingMonth=8, weekday=WeekDay.SAT),
|
||||
list(reversed(date_seq_nem_8_sat)),
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=1, startingMonth=12, weekday=WeekDay.SUN),
|
||||
JNJ,
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=-1, startingMonth=12, weekday=WeekDay.SUN),
|
||||
list(reversed(JNJ)),
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=1, startingMonth=12, weekday=WeekDay.SUN),
|
||||
[datetime(2005, 1, 2), datetime(2006, 1, 1)],
|
||||
),
|
||||
(
|
||||
makeFY5253NearestEndMonth(n=1, startingMonth=12, weekday=WeekDay.SUN),
|
||||
[datetime(2006, 1, 2), datetime(2006, 12, 31)],
|
||||
),
|
||||
(DEC_SAT, [datetime(2013, 1, 15), datetime(2012, 12, 29)]),
|
||||
]
|
||||
for test in tests:
|
||||
offset, data = test
|
||||
current = data[0]
|
||||
for datum in data[1:]:
|
||||
current = current + offset
|
||||
assert current == datum
|
||||
|
||||
|
||||
class TestFY5253LastOfMonthQuarter(Base):
|
||||
def test_isAnchored(self):
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
).isAnchored()
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
weekday=WeekDay.SAT, startingMonth=3, qtr_with_extra_week=4
|
||||
).isAnchored()
|
||||
assert not makeFY5253LastOfMonthQuarter(
|
||||
2, startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
).isAnchored()
|
||||
|
||||
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_onOffset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_onOffset(offset, dt, expected)
|
||||
|
||||
def test_year_has_extra_week(self):
|
||||
# End of long Q1
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(2011, 4, 2))
|
||||
|
||||
# Start of long Q1
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(2010, 12, 26))
|
||||
|
||||
# End of year before year with long Q1
|
||||
assert not makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(2010, 12, 25))
|
||||
|
||||
for year in [
|
||||
x for x in range(1994, 2011 + 1) if x not in [2011, 2005, 2000, 1994]
|
||||
]:
|
||||
assert not makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(year, 4, 2))
|
||||
|
||||
# Other long years
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(2005, 4, 2))
|
||||
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(2000, 4, 2))
|
||||
|
||||
assert makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
).year_has_extra_week(datetime(1994, 4, 2))
|
||||
|
||||
def test_get_weeks(self):
|
||||
sat_dec_1 = makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=1
|
||||
)
|
||||
sat_dec_4 = makeFY5253LastOfMonthQuarter(
|
||||
1, startingMonth=12, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
|
||||
assert sat_dec_1.get_weeks(datetime(2011, 4, 2)) == [14, 13, 13, 13]
|
||||
assert sat_dec_4.get_weeks(datetime(2011, 4, 2)) == [13, 13, 13, 14]
|
||||
assert sat_dec_1.get_weeks(datetime(2010, 12, 25)) == [13, 13, 13, 13]
|
||||
|
||||
|
||||
class TestFY5253NearestEndMonthQuarter(Base):
|
||||
|
||||
offset_nem_sat_aug_4 = makeFY5253NearestEndMonthQuarter(
|
||||
1, startingMonth=8, weekday=WeekDay.SAT, qtr_with_extra_week=4
|
||||
)
|
||||
offset_nem_thu_aug_4 = makeFY5253NearestEndMonthQuarter(
|
||||
1, startingMonth=8, weekday=WeekDay.THU, qtr_with_extra_week=4
|
||||
)
|
||||
offset_n = FY5253(weekday=WeekDay.TUE, startingMonth=12, variation="nearest")
|
||||
|
||||
on_offset_cases = [
|
||||
# From Wikipedia
|
||||
(offset_nem_sat_aug_4, datetime(2006, 9, 2), True),
|
||||
(offset_nem_sat_aug_4, datetime(2007, 9, 1), True),
|
||||
(offset_nem_sat_aug_4, datetime(2008, 8, 30), True),
|
||||
(offset_nem_sat_aug_4, datetime(2009, 8, 29), True),
|
||||
(offset_nem_sat_aug_4, datetime(2010, 8, 28), True),
|
||||
(offset_nem_sat_aug_4, datetime(2011, 9, 3), True),
|
||||
(offset_nem_sat_aug_4, datetime(2016, 9, 3), True),
|
||||
(offset_nem_sat_aug_4, datetime(2017, 9, 2), True),
|
||||
(offset_nem_sat_aug_4, datetime(2018, 9, 1), True),
|
||||
(offset_nem_sat_aug_4, datetime(2019, 8, 31), True),
|
||||
(offset_nem_sat_aug_4, datetime(2006, 8, 27), False),
|
||||
(offset_nem_sat_aug_4, datetime(2007, 8, 28), False),
|
||||
(offset_nem_sat_aug_4, datetime(2008, 8, 31), False),
|
||||
(offset_nem_sat_aug_4, datetime(2009, 8, 30), False),
|
||||
(offset_nem_sat_aug_4, datetime(2010, 8, 29), False),
|
||||
(offset_nem_sat_aug_4, datetime(2011, 8, 28), False),
|
||||
(offset_nem_sat_aug_4, datetime(2006, 8, 25), False),
|
||||
(offset_nem_sat_aug_4, datetime(2007, 8, 24), False),
|
||||
(offset_nem_sat_aug_4, datetime(2008, 8, 29), False),
|
||||
(offset_nem_sat_aug_4, datetime(2009, 8, 28), False),
|
||||
(offset_nem_sat_aug_4, datetime(2010, 8, 27), False),
|
||||
(offset_nem_sat_aug_4, datetime(2011, 8, 26), False),
|
||||
(offset_nem_sat_aug_4, datetime(2019, 8, 30), False),
|
||||
# From Micron, see:
|
||||
# http://google.brand.edgar-online.com/?sym=MU&formtypeID=7
|
||||
(offset_nem_thu_aug_4, datetime(2012, 8, 30), True),
|
||||
(offset_nem_thu_aug_4, datetime(2011, 9, 1), True),
|
||||
# See: http://google.brand.edgar-online.com/?sym=MU&formtypeID=13
|
||||
(offset_nem_thu_aug_4, datetime(2013, 5, 30), True),
|
||||
(offset_nem_thu_aug_4, datetime(2013, 2, 28), True),
|
||||
(offset_nem_thu_aug_4, datetime(2012, 11, 29), True),
|
||||
(offset_nem_thu_aug_4, datetime(2012, 5, 31), True),
|
||||
(offset_nem_thu_aug_4, datetime(2007, 3, 1), True),
|
||||
(offset_nem_thu_aug_4, datetime(1994, 3, 3), True),
|
||||
(offset_n, datetime(2012, 12, 31), False),
|
||||
(offset_n, datetime(2013, 1, 1), True),
|
||||
(offset_n, datetime(2013, 1, 2), False),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("case", on_offset_cases)
|
||||
def test_onOffset(self, case):
|
||||
offset, dt, expected = case
|
||||
assert_onOffset(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.onOffset(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.onOffset(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.onOffset(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.onOffset(ts)
|
||||
assert fast == slow
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,139 @@
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
import warnings
|
||||
|
||||
from hypothesis import assume, given, strategies as st
|
||||
from hypothesis.extra.dateutil import timezones as dateutil_timezones
|
||||
from hypothesis.extra.pytz import timezones as pytz_timezones
|
||||
import pytest
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from pandas.tseries.offsets import (
|
||||
BMonthBegin,
|
||||
BMonthEnd,
|
||||
BQuarterBegin,
|
||||
BQuarterEnd,
|
||||
BYearBegin,
|
||||
BYearEnd,
|
||||
MonthBegin,
|
||||
MonthEnd,
|
||||
QuarterBegin,
|
||||
QuarterEnd,
|
||||
YearBegin,
|
||||
YearEnd,
|
||||
)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# Helpers for generating random data
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
min_dt = (pd.Timestamp(1900, 1, 1).to_pydatetime(),)
|
||||
max_dt = (pd.Timestamp(1900, 1, 1).to_pydatetime(),)
|
||||
|
||||
gen_date_range = st.builds(
|
||||
pd.date_range,
|
||||
start=st.datetimes(
|
||||
# TODO: Choose the min/max values more systematically
|
||||
min_value=pd.Timestamp(1900, 1, 1).to_pydatetime(),
|
||||
max_value=pd.Timestamp(2100, 1, 1).to_pydatetime(),
|
||||
),
|
||||
periods=st.integers(min_value=2, max_value=100),
|
||||
freq=st.sampled_from("Y Q M D H T s ms us ns".split()),
|
||||
tz=st.one_of(st.none(), dateutil_timezones(), pytz_timezones()),
|
||||
)
|
||||
|
||||
gen_random_datetime = st.datetimes(
|
||||
min_value=min_dt,
|
||||
max_value=max_dt,
|
||||
timezones=st.one_of(st.none(), dateutil_timezones(), pytz_timezones()),
|
||||
)
|
||||
|
||||
# The strategy for each type is registered in conftest.py, as they don't carry
|
||||
# enough runtime information (e.g. type hints) to infer how to build them.
|
||||
gen_yqm_offset = st.one_of(
|
||||
*map(
|
||||
st.from_type,
|
||||
[
|
||||
MonthBegin,
|
||||
MonthEnd,
|
||||
BMonthBegin,
|
||||
BMonthEnd,
|
||||
QuarterBegin,
|
||||
QuarterEnd,
|
||||
BQuarterBegin,
|
||||
BQuarterEnd,
|
||||
YearBegin,
|
||||
YearEnd,
|
||||
BYearBegin,
|
||||
BYearEnd,
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# Offset-specific behaviour tests
|
||||
|
||||
|
||||
# Based on CI runs: Always passes on OSX, fails on Linux, sometimes on Windows
|
||||
@pytest.mark.xfail(strict=False, reason="inconsistent between OSs, Pythons")
|
||||
@given(gen_random_datetime, gen_yqm_offset)
|
||||
def test_on_offset_implementations(dt, offset):
|
||||
assume(not offset.normalize)
|
||||
# check that the class-specific implementations of onOffset match
|
||||
# the general case definition:
|
||||
# (dt + offset) - offset == dt
|
||||
compare = (dt + offset) - offset
|
||||
assert offset.onOffset(dt) == (compare == dt)
|
||||
|
||||
|
||||
@pytest.mark.xfail(
|
||||
reason="res_v2 below is incorrect, needs to use the "
|
||||
"commented-out version with tz_localize. "
|
||||
"But with that fix in place, hypothesis then "
|
||||
"has errors in timezone generation."
|
||||
)
|
||||
@given(gen_yqm_offset, gen_date_range)
|
||||
def test_apply_index_implementations(offset, rng):
|
||||
# offset.apply_index(dti)[i] should match dti[i] + offset
|
||||
assume(offset.n != 0) # TODO: test for that case separately
|
||||
|
||||
# rng = pd.date_range(start='1/1/2000', periods=100000, freq='T')
|
||||
ser = pd.Series(rng)
|
||||
|
||||
res = rng + offset
|
||||
res_v2 = offset.apply_index(rng)
|
||||
# res_v2 = offset.apply_index(rng.tz_localize(None)).tz_localize(rng.tz)
|
||||
assert (res == res_v2).all()
|
||||
|
||||
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
|
||||
# TODO: Check randomly assorted entries, not just first/last
|
||||
|
||||
|
||||
@pytest.mark.xfail # TODO: reason?
|
||||
@given(gen_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
|
||||
# Note that dti includes a transition across DST boundary
|
||||
dti = pd.date_range(
|
||||
start="2017-10-30 12:00:00", end="2017-11-06", freq="D", tz="US/Eastern"
|
||||
)
|
||||
assert (dti.hour == 12).all() # we haven't screwed up yet
|
||||
|
||||
res = dti + offset
|
||||
assert (res.hour == 12).all()
|
||||
@@ -0,0 +1,322 @@
|
||||
"""
|
||||
Tests for offsets.Tick and subclasses
|
||||
"""
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from hypothesis import assume, example, given, settings, strategies as st
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas import Timedelta, Timestamp
|
||||
import pandas.util.testing as tm
|
||||
|
||||
from pandas.tseries import offsets
|
||||
from pandas.tseries.offsets import Hour, Micro, Milli, Minute, Nano, Second
|
||||
|
||||
from .common import assert_offset_equal
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Test Helpers
|
||||
|
||||
tick_classes = [Hour, Minute, Second, Milli, Micro, Nano]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_apply_ticks():
|
||||
result = offsets.Hour(3).apply(offsets.Hour(4))
|
||||
exp = offsets.Hour(7)
|
||||
assert result == exp
|
||||
|
||||
|
||||
def test_delta_to_tick():
|
||||
delta = timedelta(3)
|
||||
|
||||
tick = offsets._delta_to_tick(delta)
|
||||
assert tick == offsets.Day(3)
|
||||
|
||||
td = Timedelta(nanoseconds=5)
|
||||
tick = offsets._delta_to_tick(td)
|
||||
assert tick == Nano(5)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
@settings(deadline=None) # GH 24641
|
||||
@example(n=2, m=3)
|
||||
@example(n=800, m=300)
|
||||
@example(n=1000, m=5)
|
||||
@given(n=st.integers(-999, 999), m=st.integers(-999, 999))
|
||||
def test_tick_add_sub(cls, n, m):
|
||||
# For all Tick subclasses and all integers n, m, we should have
|
||||
# tick(n) + tick(m) == tick(n+m)
|
||||
# tick(n) - tick(m) == tick(n-m)
|
||||
left = cls(n)
|
||||
right = cls(m)
|
||||
expected = cls(n + m)
|
||||
|
||||
assert left + right == expected
|
||||
assert left.apply(right) == expected
|
||||
|
||||
expected = cls(n - m)
|
||||
assert left - right == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
@settings(deadline=None)
|
||||
@example(n=2, m=3)
|
||||
@given(n=st.integers(-999, 999), m=st.integers(-999, 999))
|
||||
def test_tick_equality(cls, n, m):
|
||||
assume(m != n)
|
||||
# tick == tock iff tick.n == tock.n
|
||||
left = cls(n)
|
||||
right = cls(m)
|
||||
assert left != right
|
||||
assert not (left == right)
|
||||
|
||||
right = cls(n)
|
||||
assert left == right
|
||||
assert not (left != right)
|
||||
|
||||
if n != 0:
|
||||
assert cls(n) != cls(-n)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_Hour():
|
||||
assert_offset_equal(Hour(), datetime(2010, 1, 1), datetime(2010, 1, 1, 1))
|
||||
assert_offset_equal(Hour(-1), datetime(2010, 1, 1, 1), datetime(2010, 1, 1))
|
||||
assert_offset_equal(2 * Hour(), datetime(2010, 1, 1), datetime(2010, 1, 1, 2))
|
||||
assert_offset_equal(-1 * Hour(), datetime(2010, 1, 1, 1), datetime(2010, 1, 1))
|
||||
|
||||
assert Hour(3) + Hour(2) == Hour(5)
|
||||
assert Hour(3) - Hour(2) == Hour()
|
||||
|
||||
assert Hour(4) != Hour(1)
|
||||
|
||||
|
||||
def test_Minute():
|
||||
assert_offset_equal(Minute(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 1))
|
||||
assert_offset_equal(Minute(-1), datetime(2010, 1, 1, 0, 1), datetime(2010, 1, 1))
|
||||
assert_offset_equal(2 * Minute(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 2))
|
||||
assert_offset_equal(-1 * Minute(), datetime(2010, 1, 1, 0, 1), datetime(2010, 1, 1))
|
||||
|
||||
assert Minute(3) + Minute(2) == Minute(5)
|
||||
assert Minute(3) - Minute(2) == Minute()
|
||||
assert Minute(5) != Minute()
|
||||
|
||||
|
||||
def test_Second():
|
||||
assert_offset_equal(Second(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 1))
|
||||
assert_offset_equal(Second(-1), datetime(2010, 1, 1, 0, 0, 1), datetime(2010, 1, 1))
|
||||
assert_offset_equal(
|
||||
2 * Second(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 2)
|
||||
)
|
||||
assert_offset_equal(
|
||||
-1 * Second(), datetime(2010, 1, 1, 0, 0, 1), datetime(2010, 1, 1)
|
||||
)
|
||||
|
||||
assert Second(3) + Second(2) == Second(5)
|
||||
assert Second(3) - Second(2) == Second()
|
||||
|
||||
|
||||
def test_Millisecond():
|
||||
assert_offset_equal(
|
||||
Milli(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 1000)
|
||||
)
|
||||
assert_offset_equal(
|
||||
Milli(-1), datetime(2010, 1, 1, 0, 0, 0, 1000), datetime(2010, 1, 1)
|
||||
)
|
||||
assert_offset_equal(
|
||||
Milli(2), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2000)
|
||||
)
|
||||
assert_offset_equal(
|
||||
2 * Milli(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2000)
|
||||
)
|
||||
assert_offset_equal(
|
||||
-1 * Milli(), datetime(2010, 1, 1, 0, 0, 0, 1000), datetime(2010, 1, 1)
|
||||
)
|
||||
|
||||
assert Milli(3) + Milli(2) == Milli(5)
|
||||
assert Milli(3) - Milli(2) == Milli()
|
||||
|
||||
|
||||
def test_MillisecondTimestampArithmetic():
|
||||
assert_offset_equal(
|
||||
Milli(), Timestamp("2010-01-01"), Timestamp("2010-01-01 00:00:00.001")
|
||||
)
|
||||
assert_offset_equal(
|
||||
Milli(-1), Timestamp("2010-01-01 00:00:00.001"), Timestamp("2010-01-01")
|
||||
)
|
||||
|
||||
|
||||
def test_Microsecond():
|
||||
assert_offset_equal(Micro(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 1))
|
||||
assert_offset_equal(
|
||||
Micro(-1), datetime(2010, 1, 1, 0, 0, 0, 1), datetime(2010, 1, 1)
|
||||
)
|
||||
|
||||
assert_offset_equal(
|
||||
2 * Micro(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2)
|
||||
)
|
||||
assert_offset_equal(
|
||||
-1 * Micro(), datetime(2010, 1, 1, 0, 0, 0, 1), datetime(2010, 1, 1)
|
||||
)
|
||||
|
||||
assert Micro(3) + Micro(2) == Micro(5)
|
||||
assert Micro(3) - Micro(2) == Micro()
|
||||
|
||||
|
||||
def test_NanosecondGeneric():
|
||||
timestamp = Timestamp(datetime(2010, 1, 1))
|
||||
assert timestamp.nanosecond == 0
|
||||
|
||||
result = timestamp + Nano(10)
|
||||
assert result.nanosecond == 10
|
||||
|
||||
reverse_result = Nano(10) + timestamp
|
||||
assert reverse_result.nanosecond == 10
|
||||
|
||||
|
||||
def test_Nanosecond():
|
||||
timestamp = Timestamp(datetime(2010, 1, 1))
|
||||
assert_offset_equal(Nano(), timestamp, timestamp + np.timedelta64(1, "ns"))
|
||||
assert_offset_equal(Nano(-1), timestamp + np.timedelta64(1, "ns"), timestamp)
|
||||
assert_offset_equal(2 * Nano(), timestamp, timestamp + np.timedelta64(2, "ns"))
|
||||
assert_offset_equal(-1 * Nano(), timestamp + np.timedelta64(1, "ns"), timestamp)
|
||||
|
||||
assert Nano(3) + Nano(2) == Nano(5)
|
||||
assert Nano(3) - Nano(2) == Nano()
|
||||
|
||||
# GH9284
|
||||
assert Nano(1) + Nano(10) == Nano(11)
|
||||
assert Nano(5) + Micro(1) == Nano(1005)
|
||||
assert Micro(5) + Nano(1) == Nano(5001)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"kls, expected",
|
||||
[
|
||||
(Hour, Timedelta(hours=5)),
|
||||
(Minute, Timedelta(hours=2, minutes=3)),
|
||||
(Second, Timedelta(hours=2, seconds=3)),
|
||||
(Milli, Timedelta(hours=2, milliseconds=3)),
|
||||
(Micro, Timedelta(hours=2, microseconds=3)),
|
||||
(Nano, Timedelta(hours=2, nanoseconds=3)),
|
||||
],
|
||||
)
|
||||
def test_tick_addition(kls, expected):
|
||||
offset = kls(3)
|
||||
result = offset + Timedelta(hours=2)
|
||||
assert isinstance(result, Timedelta)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_tick_division(cls):
|
||||
off = cls(10)
|
||||
|
||||
assert off / cls(5) == 2
|
||||
assert off / 2 == cls(5)
|
||||
assert off / 2.0 == cls(5)
|
||||
|
||||
assert off / off.delta == 1
|
||||
assert off / off.delta.to_timedelta64() == 1
|
||||
|
||||
assert off / Nano(1) == off.delta / Nano(1).delta
|
||||
|
||||
if cls is not Nano:
|
||||
# A case where we end up with a smaller class
|
||||
result = off / 1000
|
||||
assert isinstance(result, offsets.Tick)
|
||||
assert not isinstance(result, cls)
|
||||
assert result.delta == off.delta / 1000
|
||||
|
||||
if cls._inc < Timedelta(seconds=1):
|
||||
# Case where we end up with a bigger class
|
||||
result = off / 0.001
|
||||
assert isinstance(result, offsets.Tick)
|
||||
assert not isinstance(result, cls)
|
||||
assert result.delta == off.delta / 0.001
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_tick_rdiv(cls):
|
||||
off = cls(10)
|
||||
delta = off.delta
|
||||
td64 = delta.to_timedelta64()
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
2 / off
|
||||
with pytest.raises(TypeError):
|
||||
2.0 / off
|
||||
|
||||
assert (td64 * 2.5) / off == 2.5
|
||||
|
||||
if cls is not Nano:
|
||||
# skip pytimedelta for Nano since it gets dropped
|
||||
assert (delta.to_pytimedelta() * 2) / off == 2
|
||||
|
||||
result = np.array([2 * td64, td64]) / off
|
||||
expected = np.array([2.0, 1.0])
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls1", tick_classes)
|
||||
@pytest.mark.parametrize("cls2", tick_classes)
|
||||
def test_tick_zero(cls1, cls2):
|
||||
assert cls1(0) == cls2(0)
|
||||
assert cls1(0) + cls2(0) == cls1(0)
|
||||
|
||||
if cls1 is not Nano:
|
||||
assert cls1(2) + cls2(0) == cls1(2)
|
||||
|
||||
if cls1 is Nano:
|
||||
assert cls1(2) + Nano(0) == cls1(2)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_tick_equalities(cls):
|
||||
assert cls() == cls(1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", tick_classes)
|
||||
def test_tick_offset(cls):
|
||||
assert not cls().isAnchored()
|
||||
|
||||
|
||||
@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
|
||||
|
||||
for left, right in [("infer", off), (off, "infer")]:
|
||||
with pytest.raises(TypeError):
|
||||
left < right
|
||||
with pytest.raises(TypeError):
|
||||
left <= right
|
||||
with pytest.raises(TypeError):
|
||||
left > right
|
||||
with pytest.raises(TypeError):
|
||||
left >= right
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user