import dateutil.tz from dateutil.tz import tzlocal import pytest import pytz from pandas._libs.tslibs.ccalendar import MONTHS from pandas._libs.tslibs.offsets import MonthEnd from pandas._libs.tslibs.period import INVALID_FREQ_ERR_MSG from pandas import ( DatetimeIndex, Period, PeriodIndex, Timestamp, date_range, period_range, ) import pandas._testing as tm class TestToPeriod: def test_dti_to_period(self): dti = date_range(start="1/1/2005", end="12/1/2005", freq="ME") pi1 = dti.to_period() pi2 = dti.to_period(freq="D") pi3 = dti.to_period(freq="3D") assert pi1[0] == Period("Jan 2005", freq="M") assert pi2[0] == Period("1/31/2005", freq="D") assert pi3[0] == Period("1/31/2005", freq="3D") assert pi1[-1] == Period("Nov 2005", freq="M") assert pi2[-1] == Period("11/30/2005", freq="D") assert pi3[-1], Period("11/30/2005", freq="3D") tm.assert_index_equal(pi1, period_range("1/1/2005", "11/1/2005", freq="M")) tm.assert_index_equal( pi2, period_range("1/1/2005", "11/1/2005", freq="M").asfreq("D") ) tm.assert_index_equal( pi3, period_range("1/1/2005", "11/1/2005", freq="M").asfreq("3D") ) @pytest.mark.parametrize("month", MONTHS) def test_to_period_quarterly(self, month): # make sure we can make the round trip freq = f"Q-{month}" rng = period_range("1989Q3", "1991Q3", freq=freq) stamps = rng.to_timestamp() result = stamps.to_period(freq) tm.assert_index_equal(rng, result) @pytest.mark.parametrize("off", ["BQE", "QS", "BQS"]) def test_to_period_quarterlyish(self, off): rng = date_range("01-Jan-2012", periods=8, freq=off) prng = rng.to_period() assert prng.freq == "QE-DEC" @pytest.mark.parametrize("off", ["BYE", "YS", "BYS"]) def test_to_period_annualish(self, off): rng = date_range("01-Jan-2012", periods=8, freq=off) prng = rng.to_period() assert prng.freq == "YE-DEC" def test_to_period_monthish(self): offsets = ["MS", "BME"] for off in offsets: rng = date_range("01-Jan-2012", periods=8, freq=off) prng = rng.to_period() assert prng.freqstr == "M" rng = date_range("01-Jan-2012", periods=8, freq="ME") prng = rng.to_period() assert prng.freqstr == "M" with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): date_range("01-Jan-2012", periods=8, freq="EOM") @pytest.mark.parametrize( "freq_offset, freq_period", [ ("2ME", "2M"), (MonthEnd(2), MonthEnd(2)), ], ) def test_dti_to_period_2monthish(self, freq_offset, freq_period): dti = date_range("2020-01-01", periods=3, freq=freq_offset) pi = dti.to_period() tm.assert_index_equal(pi, period_range("2020-01", "2020-05", freq=freq_period)) @pytest.mark.parametrize( "freq, freq_depr", [ ("2ME", "2M"), ("2QE", "2Q"), ("2QE-SEP", "2Q-SEP"), ("1YE", "1Y"), ("2YE-MAR", "2Y-MAR"), ("1YE", "1A"), ("2YE-MAR", "2A-MAR"), ], ) def test_to_period_frequency_M_Q_Y_A_deprecated(self, freq, freq_depr): # GH#9586 msg = f"'{freq_depr[1:]}' is deprecated and will be removed " f"in a future version, please use '{freq[1:]}' instead." rng = date_range("01-Jan-2012", periods=8, freq=freq) prng = rng.to_period() with tm.assert_produces_warning(FutureWarning, match=msg): assert prng.freq == freq_depr def test_to_period_infer(self): # https://github.com/pandas-dev/pandas/issues/33358 rng = date_range( start="2019-12-22 06:40:00+00:00", end="2019-12-22 08:45:00+00:00", freq="5min", ) with tm.assert_produces_warning(UserWarning): pi1 = rng.to_period("5min") with tm.assert_produces_warning(UserWarning): pi2 = rng.to_period() tm.assert_index_equal(pi1, pi2) @pytest.mark.filterwarnings(r"ignore:PeriodDtype\[B\] is deprecated:FutureWarning") def test_period_dt64_round_trip(self): dti = date_range("1/1/2000", "1/7/2002", freq="B") pi = dti.to_period() tm.assert_index_equal(pi.to_timestamp(), dti) dti = date_range("1/1/2000", "1/7/2002", freq="B") pi = dti.to_period(freq="h") tm.assert_index_equal(pi.to_timestamp(), dti) def test_to_period_millisecond(self): index = DatetimeIndex( [ Timestamp("2007-01-01 10:11:12.123456Z"), Timestamp("2007-01-01 10:11:13.789123Z"), ] ) with tm.assert_produces_warning(UserWarning): # warning that timezone info will be lost period = index.to_period(freq="ms") assert 2 == len(period) assert period[0] == Period("2007-01-01 10:11:12.123Z", "ms") assert period[1] == Period("2007-01-01 10:11:13.789Z", "ms") def test_to_period_microsecond(self): index = DatetimeIndex( [ Timestamp("2007-01-01 10:11:12.123456Z"), Timestamp("2007-01-01 10:11:13.789123Z"), ] ) with tm.assert_produces_warning(UserWarning): # warning that timezone info will be lost period = index.to_period(freq="us") assert 2 == len(period) assert period[0] == Period("2007-01-01 10:11:12.123456Z", "us") assert period[1] == Period("2007-01-01 10:11:13.789123Z", "us") @pytest.mark.parametrize( "tz", ["US/Eastern", pytz.utc, tzlocal(), "dateutil/US/Eastern", dateutil.tz.tzutc()], ) def test_to_period_tz(self, tz): ts = date_range("1/1/2000", "2/1/2000", tz=tz) with tm.assert_produces_warning(UserWarning): # GH#21333 warning that timezone info will be lost # filter warning about freq deprecation result = ts.to_period()[0] expected = ts[0].to_period(ts.freq) assert result == expected expected = date_range("1/1/2000", "2/1/2000").to_period() with tm.assert_produces_warning(UserWarning): # GH#21333 warning that timezone info will be lost result = ts.to_period(ts.freq) tm.assert_index_equal(result, expected) @pytest.mark.parametrize("tz", ["Etc/GMT-1", "Etc/GMT+1"]) def test_to_period_tz_utc_offset_consistency(self, tz): # GH#22905 ts = date_range("1/1/2000", "2/1/2000", tz="Etc/GMT-1") with tm.assert_produces_warning(UserWarning): result = ts.to_period()[0] expected = ts[0].to_period(ts.freq) assert result == expected def test_to_period_nofreq(self): idx = DatetimeIndex(["2000-01-01", "2000-01-02", "2000-01-04"]) msg = "You must pass a freq argument as current index has none." with pytest.raises(ValueError, match=msg): idx.to_period() idx = DatetimeIndex(["2000-01-01", "2000-01-02", "2000-01-03"], freq="infer") assert idx.freqstr == "D" expected = PeriodIndex(["2000-01-01", "2000-01-02", "2000-01-03"], freq="D") tm.assert_index_equal(idx.to_period(), expected) # GH#7606 idx = DatetimeIndex(["2000-01-01", "2000-01-02", "2000-01-03"]) assert idx.freqstr is None tm.assert_index_equal(idx.to_period(), expected) @pytest.mark.parametrize("freq", ["2BMS", "1SME-15"]) def test_to_period_offsets_not_supported(self, freq): # GH#56243 msg = f"{freq[1:]} is not supported as period frequency" ts = date_range("1/1/2012", periods=4, freq=freq) with pytest.raises(ValueError, match=msg): ts.to_period()