test_month.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. """
  2. Tests for the following offsets:
  3. - SemiMonthBegin
  4. - SemiMonthEnd
  5. - MonthBegin
  6. - MonthEnd
  7. """
  8. from __future__ import annotations
  9. from datetime import datetime
  10. import pytest
  11. from pandas._libs.tslibs import Timestamp
  12. from pandas._libs.tslibs.offsets import (
  13. MonthBegin,
  14. MonthEnd,
  15. SemiMonthBegin,
  16. SemiMonthEnd,
  17. )
  18. from pandas import (
  19. DatetimeIndex,
  20. Series,
  21. _testing as tm,
  22. date_range,
  23. )
  24. from pandas.tests.tseries.offsets.common import (
  25. assert_is_on_offset,
  26. assert_offset_equal,
  27. )
  28. class TestSemiMonthEnd:
  29. def test_offset_whole_year(self):
  30. dates = (
  31. datetime(2007, 12, 31),
  32. datetime(2008, 1, 15),
  33. datetime(2008, 1, 31),
  34. datetime(2008, 2, 15),
  35. datetime(2008, 2, 29),
  36. datetime(2008, 3, 15),
  37. datetime(2008, 3, 31),
  38. datetime(2008, 4, 15),
  39. datetime(2008, 4, 30),
  40. datetime(2008, 5, 15),
  41. datetime(2008, 5, 31),
  42. datetime(2008, 6, 15),
  43. datetime(2008, 6, 30),
  44. datetime(2008, 7, 15),
  45. datetime(2008, 7, 31),
  46. datetime(2008, 8, 15),
  47. datetime(2008, 8, 31),
  48. datetime(2008, 9, 15),
  49. datetime(2008, 9, 30),
  50. datetime(2008, 10, 15),
  51. datetime(2008, 10, 31),
  52. datetime(2008, 11, 15),
  53. datetime(2008, 11, 30),
  54. datetime(2008, 12, 15),
  55. datetime(2008, 12, 31),
  56. )
  57. for base, exp_date in zip(dates[:-1], dates[1:]):
  58. assert_offset_equal(SemiMonthEnd(), base, exp_date)
  59. # ensure .apply_index works as expected
  60. shift = DatetimeIndex(dates[:-1])
  61. with tm.assert_produces_warning(None):
  62. # GH#22535 check that we don't get a FutureWarning from adding
  63. # an integer array to PeriodIndex
  64. result = SemiMonthEnd() + shift
  65. exp = DatetimeIndex(dates[1:])
  66. tm.assert_index_equal(result, exp)
  67. # ensure generating a range with DatetimeIndex gives same result
  68. result = date_range(start=dates[0], end=dates[-1], freq="SM")
  69. exp = DatetimeIndex(dates, freq="SM")
  70. tm.assert_index_equal(result, exp)
  71. offset_cases = []
  72. offset_cases.append(
  73. (
  74. SemiMonthEnd(),
  75. {
  76. datetime(2008, 1, 1): datetime(2008, 1, 15),
  77. datetime(2008, 1, 15): datetime(2008, 1, 31),
  78. datetime(2008, 1, 31): datetime(2008, 2, 15),
  79. datetime(2006, 12, 14): datetime(2006, 12, 15),
  80. datetime(2006, 12, 29): datetime(2006, 12, 31),
  81. datetime(2006, 12, 31): datetime(2007, 1, 15),
  82. datetime(2007, 1, 1): datetime(2007, 1, 15),
  83. datetime(2006, 12, 1): datetime(2006, 12, 15),
  84. datetime(2006, 12, 15): datetime(2006, 12, 31),
  85. },
  86. )
  87. )
  88. offset_cases.append(
  89. (
  90. SemiMonthEnd(day_of_month=20),
  91. {
  92. datetime(2008, 1, 1): datetime(2008, 1, 20),
  93. datetime(2008, 1, 15): datetime(2008, 1, 20),
  94. datetime(2008, 1, 21): datetime(2008, 1, 31),
  95. datetime(2008, 1, 31): datetime(2008, 2, 20),
  96. datetime(2006, 12, 14): datetime(2006, 12, 20),
  97. datetime(2006, 12, 29): datetime(2006, 12, 31),
  98. datetime(2006, 12, 31): datetime(2007, 1, 20),
  99. datetime(2007, 1, 1): datetime(2007, 1, 20),
  100. datetime(2006, 12, 1): datetime(2006, 12, 20),
  101. datetime(2006, 12, 15): datetime(2006, 12, 20),
  102. },
  103. )
  104. )
  105. offset_cases.append(
  106. (
  107. SemiMonthEnd(0),
  108. {
  109. datetime(2008, 1, 1): datetime(2008, 1, 15),
  110. datetime(2008, 1, 16): datetime(2008, 1, 31),
  111. datetime(2008, 1, 15): datetime(2008, 1, 15),
  112. datetime(2008, 1, 31): datetime(2008, 1, 31),
  113. datetime(2006, 12, 29): datetime(2006, 12, 31),
  114. datetime(2006, 12, 31): datetime(2006, 12, 31),
  115. datetime(2007, 1, 1): datetime(2007, 1, 15),
  116. },
  117. )
  118. )
  119. offset_cases.append(
  120. (
  121. SemiMonthEnd(0, day_of_month=16),
  122. {
  123. datetime(2008, 1, 1): datetime(2008, 1, 16),
  124. datetime(2008, 1, 16): datetime(2008, 1, 16),
  125. datetime(2008, 1, 15): datetime(2008, 1, 16),
  126. datetime(2008, 1, 31): datetime(2008, 1, 31),
  127. datetime(2006, 12, 29): datetime(2006, 12, 31),
  128. datetime(2006, 12, 31): datetime(2006, 12, 31),
  129. datetime(2007, 1, 1): datetime(2007, 1, 16),
  130. },
  131. )
  132. )
  133. offset_cases.append(
  134. (
  135. SemiMonthEnd(2),
  136. {
  137. datetime(2008, 1, 1): datetime(2008, 1, 31),
  138. datetime(2008, 1, 31): datetime(2008, 2, 29),
  139. datetime(2006, 12, 29): datetime(2007, 1, 15),
  140. datetime(2006, 12, 31): datetime(2007, 1, 31),
  141. datetime(2007, 1, 1): datetime(2007, 1, 31),
  142. datetime(2007, 1, 16): datetime(2007, 2, 15),
  143. datetime(2006, 11, 1): datetime(2006, 11, 30),
  144. },
  145. )
  146. )
  147. offset_cases.append(
  148. (
  149. SemiMonthEnd(-1),
  150. {
  151. datetime(2007, 1, 1): datetime(2006, 12, 31),
  152. datetime(2008, 6, 30): datetime(2008, 6, 15),
  153. datetime(2008, 12, 31): datetime(2008, 12, 15),
  154. datetime(2006, 12, 29): datetime(2006, 12, 15),
  155. datetime(2006, 12, 30): datetime(2006, 12, 15),
  156. datetime(2007, 1, 1): datetime(2006, 12, 31),
  157. },
  158. )
  159. )
  160. offset_cases.append(
  161. (
  162. SemiMonthEnd(-1, day_of_month=4),
  163. {
  164. datetime(2007, 1, 1): datetime(2006, 12, 31),
  165. datetime(2007, 1, 4): datetime(2006, 12, 31),
  166. datetime(2008, 6, 30): datetime(2008, 6, 4),
  167. datetime(2008, 12, 31): datetime(2008, 12, 4),
  168. datetime(2006, 12, 5): datetime(2006, 12, 4),
  169. datetime(2006, 12, 30): datetime(2006, 12, 4),
  170. datetime(2007, 1, 1): datetime(2006, 12, 31),
  171. },
  172. )
  173. )
  174. offset_cases.append(
  175. (
  176. SemiMonthEnd(-2),
  177. {
  178. datetime(2007, 1, 1): datetime(2006, 12, 15),
  179. datetime(2008, 6, 30): datetime(2008, 5, 31),
  180. datetime(2008, 3, 15): datetime(2008, 2, 15),
  181. datetime(2008, 12, 31): datetime(2008, 11, 30),
  182. datetime(2006, 12, 29): datetime(2006, 11, 30),
  183. datetime(2006, 12, 14): datetime(2006, 11, 15),
  184. datetime(2007, 1, 1): datetime(2006, 12, 15),
  185. },
  186. )
  187. )
  188. @pytest.mark.parametrize("case", offset_cases)
  189. def test_offset(self, case):
  190. offset, cases = case
  191. for base, expected in cases.items():
  192. assert_offset_equal(offset, base, expected)
  193. @pytest.mark.parametrize("case", offset_cases)
  194. def test_apply_index(self, case):
  195. # https://github.com/pandas-dev/pandas/issues/34580
  196. offset, cases = case
  197. shift = DatetimeIndex(cases.keys())
  198. exp = DatetimeIndex(cases.values())
  199. with tm.assert_produces_warning(None):
  200. # GH#22535 check that we don't get a FutureWarning from adding
  201. # an integer array to PeriodIndex
  202. result = offset + shift
  203. tm.assert_index_equal(result, exp)
  204. on_offset_cases = [
  205. (datetime(2007, 12, 31), True),
  206. (datetime(2007, 12, 15), True),
  207. (datetime(2007, 12, 14), False),
  208. (datetime(2007, 12, 1), False),
  209. (datetime(2008, 2, 29), True),
  210. ]
  211. @pytest.mark.parametrize("case", on_offset_cases)
  212. def test_is_on_offset(self, case):
  213. dt, expected = case
  214. assert_is_on_offset(SemiMonthEnd(), dt, expected)
  215. @pytest.mark.parametrize("klass", [Series, DatetimeIndex])
  216. def test_vectorized_offset_addition(self, klass):
  217. shift = klass(
  218. [
  219. Timestamp("2000-01-15 00:15:00", tz="US/Central"),
  220. Timestamp("2000-02-15", tz="US/Central"),
  221. ],
  222. name="a",
  223. )
  224. with tm.assert_produces_warning(None):
  225. # GH#22535 check that we don't get a FutureWarning from adding
  226. # an integer array to PeriodIndex
  227. result = shift + SemiMonthEnd()
  228. result2 = SemiMonthEnd() + shift
  229. exp = klass(
  230. [
  231. Timestamp("2000-01-31 00:15:00", tz="US/Central"),
  232. Timestamp("2000-02-29", tz="US/Central"),
  233. ],
  234. name="a",
  235. )
  236. tm.assert_equal(result, exp)
  237. tm.assert_equal(result2, exp)
  238. shift = klass(
  239. [
  240. Timestamp("2000-01-01 00:15:00", tz="US/Central"),
  241. Timestamp("2000-02-01", tz="US/Central"),
  242. ],
  243. name="a",
  244. )
  245. with tm.assert_produces_warning(None):
  246. # GH#22535 check that we don't get a FutureWarning from adding
  247. # an integer array to PeriodIndex
  248. result = shift + SemiMonthEnd()
  249. result2 = SemiMonthEnd() + shift
  250. exp = klass(
  251. [
  252. Timestamp("2000-01-15 00:15:00", tz="US/Central"),
  253. Timestamp("2000-02-15", tz="US/Central"),
  254. ],
  255. name="a",
  256. )
  257. tm.assert_equal(result, exp)
  258. tm.assert_equal(result2, exp)
  259. class TestSemiMonthBegin:
  260. def test_offset_whole_year(self):
  261. dates = (
  262. datetime(2007, 12, 15),
  263. datetime(2008, 1, 1),
  264. datetime(2008, 1, 15),
  265. datetime(2008, 2, 1),
  266. datetime(2008, 2, 15),
  267. datetime(2008, 3, 1),
  268. datetime(2008, 3, 15),
  269. datetime(2008, 4, 1),
  270. datetime(2008, 4, 15),
  271. datetime(2008, 5, 1),
  272. datetime(2008, 5, 15),
  273. datetime(2008, 6, 1),
  274. datetime(2008, 6, 15),
  275. datetime(2008, 7, 1),
  276. datetime(2008, 7, 15),
  277. datetime(2008, 8, 1),
  278. datetime(2008, 8, 15),
  279. datetime(2008, 9, 1),
  280. datetime(2008, 9, 15),
  281. datetime(2008, 10, 1),
  282. datetime(2008, 10, 15),
  283. datetime(2008, 11, 1),
  284. datetime(2008, 11, 15),
  285. datetime(2008, 12, 1),
  286. datetime(2008, 12, 15),
  287. )
  288. for base, exp_date in zip(dates[:-1], dates[1:]):
  289. assert_offset_equal(SemiMonthBegin(), base, exp_date)
  290. # ensure .apply_index works as expected
  291. shift = DatetimeIndex(dates[:-1])
  292. with tm.assert_produces_warning(None):
  293. # GH#22535 check that we don't get a FutureWarning from adding
  294. # an integer array to PeriodIndex
  295. result = SemiMonthBegin() + shift
  296. exp = DatetimeIndex(dates[1:])
  297. tm.assert_index_equal(result, exp)
  298. # ensure generating a range with DatetimeIndex gives same result
  299. result = date_range(start=dates[0], end=dates[-1], freq="SMS")
  300. exp = DatetimeIndex(dates, freq="SMS")
  301. tm.assert_index_equal(result, exp)
  302. offset_cases = [
  303. (
  304. SemiMonthBegin(),
  305. {
  306. datetime(2008, 1, 1): datetime(2008, 1, 15),
  307. datetime(2008, 1, 15): datetime(2008, 2, 1),
  308. datetime(2008, 1, 31): datetime(2008, 2, 1),
  309. datetime(2006, 12, 14): datetime(2006, 12, 15),
  310. datetime(2006, 12, 29): datetime(2007, 1, 1),
  311. datetime(2006, 12, 31): datetime(2007, 1, 1),
  312. datetime(2007, 1, 1): datetime(2007, 1, 15),
  313. datetime(2006, 12, 1): datetime(2006, 12, 15),
  314. datetime(2006, 12, 15): datetime(2007, 1, 1),
  315. },
  316. ),
  317. (
  318. SemiMonthBegin(day_of_month=20),
  319. {
  320. datetime(2008, 1, 1): datetime(2008, 1, 20),
  321. datetime(2008, 1, 15): datetime(2008, 1, 20),
  322. datetime(2008, 1, 21): datetime(2008, 2, 1),
  323. datetime(2008, 1, 31): datetime(2008, 2, 1),
  324. datetime(2006, 12, 14): datetime(2006, 12, 20),
  325. datetime(2006, 12, 29): datetime(2007, 1, 1),
  326. datetime(2006, 12, 31): datetime(2007, 1, 1),
  327. datetime(2007, 1, 1): datetime(2007, 1, 20),
  328. datetime(2006, 12, 1): datetime(2006, 12, 20),
  329. datetime(2006, 12, 15): datetime(2006, 12, 20),
  330. },
  331. ),
  332. (
  333. SemiMonthBegin(0),
  334. {
  335. datetime(2008, 1, 1): datetime(2008, 1, 1),
  336. datetime(2008, 1, 16): datetime(2008, 2, 1),
  337. datetime(2008, 1, 15): datetime(2008, 1, 15),
  338. datetime(2008, 1, 31): datetime(2008, 2, 1),
  339. datetime(2006, 12, 29): datetime(2007, 1, 1),
  340. datetime(2006, 12, 2): datetime(2006, 12, 15),
  341. datetime(2007, 1, 1): datetime(2007, 1, 1),
  342. },
  343. ),
  344. (
  345. SemiMonthBegin(0, day_of_month=16),
  346. {
  347. datetime(2008, 1, 1): datetime(2008, 1, 1),
  348. datetime(2008, 1, 16): datetime(2008, 1, 16),
  349. datetime(2008, 1, 15): datetime(2008, 1, 16),
  350. datetime(2008, 1, 31): datetime(2008, 2, 1),
  351. datetime(2006, 12, 29): datetime(2007, 1, 1),
  352. datetime(2006, 12, 31): datetime(2007, 1, 1),
  353. datetime(2007, 1, 5): datetime(2007, 1, 16),
  354. datetime(2007, 1, 1): datetime(2007, 1, 1),
  355. },
  356. ),
  357. (
  358. SemiMonthBegin(2),
  359. {
  360. datetime(2008, 1, 1): datetime(2008, 2, 1),
  361. datetime(2008, 1, 31): datetime(2008, 2, 15),
  362. datetime(2006, 12, 1): datetime(2007, 1, 1),
  363. datetime(2006, 12, 29): datetime(2007, 1, 15),
  364. datetime(2006, 12, 15): datetime(2007, 1, 15),
  365. datetime(2007, 1, 1): datetime(2007, 2, 1),
  366. datetime(2007, 1, 16): datetime(2007, 2, 15),
  367. datetime(2006, 11, 1): datetime(2006, 12, 1),
  368. },
  369. ),
  370. (
  371. SemiMonthBegin(-1),
  372. {
  373. datetime(2007, 1, 1): datetime(2006, 12, 15),
  374. datetime(2008, 6, 30): datetime(2008, 6, 15),
  375. datetime(2008, 6, 14): datetime(2008, 6, 1),
  376. datetime(2008, 12, 31): datetime(2008, 12, 15),
  377. datetime(2006, 12, 29): datetime(2006, 12, 15),
  378. datetime(2006, 12, 15): datetime(2006, 12, 1),
  379. datetime(2007, 1, 1): datetime(2006, 12, 15),
  380. },
  381. ),
  382. (
  383. SemiMonthBegin(-1, day_of_month=4),
  384. {
  385. datetime(2007, 1, 1): datetime(2006, 12, 4),
  386. datetime(2007, 1, 4): datetime(2007, 1, 1),
  387. datetime(2008, 6, 30): datetime(2008, 6, 4),
  388. datetime(2008, 12, 31): datetime(2008, 12, 4),
  389. datetime(2006, 12, 5): datetime(2006, 12, 4),
  390. datetime(2006, 12, 30): datetime(2006, 12, 4),
  391. datetime(2006, 12, 2): datetime(2006, 12, 1),
  392. datetime(2007, 1, 1): datetime(2006, 12, 4),
  393. },
  394. ),
  395. (
  396. SemiMonthBegin(-2),
  397. {
  398. datetime(2007, 1, 1): datetime(2006, 12, 1),
  399. datetime(2008, 6, 30): datetime(2008, 6, 1),
  400. datetime(2008, 6, 14): datetime(2008, 5, 15),
  401. datetime(2008, 12, 31): datetime(2008, 12, 1),
  402. datetime(2006, 12, 29): datetime(2006, 12, 1),
  403. datetime(2006, 12, 15): datetime(2006, 11, 15),
  404. datetime(2007, 1, 1): datetime(2006, 12, 1),
  405. },
  406. ),
  407. ]
  408. @pytest.mark.parametrize("case", offset_cases)
  409. def test_offset(self, case):
  410. offset, cases = case
  411. for base, expected in cases.items():
  412. assert_offset_equal(offset, base, expected)
  413. @pytest.mark.parametrize("case", offset_cases)
  414. def test_apply_index(self, case):
  415. offset, cases = case
  416. shift = DatetimeIndex(cases.keys())
  417. with tm.assert_produces_warning(None):
  418. # GH#22535 check that we don't get a FutureWarning from adding
  419. # an integer array to PeriodIndex
  420. result = offset + shift
  421. exp = DatetimeIndex(cases.values())
  422. tm.assert_index_equal(result, exp)
  423. on_offset_cases = [
  424. (datetime(2007, 12, 1), True),
  425. (datetime(2007, 12, 15), True),
  426. (datetime(2007, 12, 14), False),
  427. (datetime(2007, 12, 31), False),
  428. (datetime(2008, 2, 15), True),
  429. ]
  430. @pytest.mark.parametrize("case", on_offset_cases)
  431. def test_is_on_offset(self, case):
  432. dt, expected = case
  433. assert_is_on_offset(SemiMonthBegin(), dt, expected)
  434. @pytest.mark.parametrize("klass", [Series, DatetimeIndex])
  435. def test_vectorized_offset_addition(self, klass):
  436. shift = klass(
  437. [
  438. Timestamp("2000-01-15 00:15:00", tz="US/Central"),
  439. Timestamp("2000-02-15", tz="US/Central"),
  440. ],
  441. name="a",
  442. )
  443. with tm.assert_produces_warning(None):
  444. # GH#22535 check that we don't get a FutureWarning from adding
  445. # an integer array to PeriodIndex
  446. result = shift + SemiMonthBegin()
  447. result2 = SemiMonthBegin() + shift
  448. exp = klass(
  449. [
  450. Timestamp("2000-02-01 00:15:00", tz="US/Central"),
  451. Timestamp("2000-03-01", tz="US/Central"),
  452. ],
  453. name="a",
  454. )
  455. tm.assert_equal(result, exp)
  456. tm.assert_equal(result2, exp)
  457. shift = klass(
  458. [
  459. Timestamp("2000-01-01 00:15:00", tz="US/Central"),
  460. Timestamp("2000-02-01", tz="US/Central"),
  461. ],
  462. name="a",
  463. )
  464. with tm.assert_produces_warning(None):
  465. # GH#22535 check that we don't get a FutureWarning from adding
  466. # an integer array to PeriodIndex
  467. result = shift + SemiMonthBegin()
  468. result2 = SemiMonthBegin() + shift
  469. exp = klass(
  470. [
  471. Timestamp("2000-01-15 00:15:00", tz="US/Central"),
  472. Timestamp("2000-02-15", tz="US/Central"),
  473. ],
  474. name="a",
  475. )
  476. tm.assert_equal(result, exp)
  477. tm.assert_equal(result2, exp)
  478. class TestMonthBegin:
  479. offset_cases = []
  480. # NOTE: I'm not entirely happy with the logic here for Begin -ss
  481. # see thread 'offset conventions' on the ML
  482. offset_cases.append(
  483. (
  484. MonthBegin(),
  485. {
  486. datetime(2008, 1, 31): datetime(2008, 2, 1),
  487. datetime(2008, 2, 1): datetime(2008, 3, 1),
  488. datetime(2006, 12, 31): datetime(2007, 1, 1),
  489. datetime(2006, 12, 1): datetime(2007, 1, 1),
  490. datetime(2007, 1, 31): datetime(2007, 2, 1),
  491. },
  492. )
  493. )
  494. offset_cases.append(
  495. (
  496. MonthBegin(0),
  497. {
  498. datetime(2008, 1, 31): datetime(2008, 2, 1),
  499. datetime(2008, 1, 1): datetime(2008, 1, 1),
  500. datetime(2006, 12, 3): datetime(2007, 1, 1),
  501. datetime(2007, 1, 31): datetime(2007, 2, 1),
  502. },
  503. )
  504. )
  505. offset_cases.append(
  506. (
  507. MonthBegin(2),
  508. {
  509. datetime(2008, 2, 29): datetime(2008, 4, 1),
  510. datetime(2008, 1, 31): datetime(2008, 3, 1),
  511. datetime(2006, 12, 31): datetime(2007, 2, 1),
  512. datetime(2007, 12, 28): datetime(2008, 2, 1),
  513. datetime(2007, 1, 1): datetime(2007, 3, 1),
  514. datetime(2006, 11, 1): datetime(2007, 1, 1),
  515. },
  516. )
  517. )
  518. offset_cases.append(
  519. (
  520. MonthBegin(-1),
  521. {
  522. datetime(2007, 1, 1): datetime(2006, 12, 1),
  523. datetime(2008, 5, 31): datetime(2008, 5, 1),
  524. datetime(2008, 12, 31): datetime(2008, 12, 1),
  525. datetime(2006, 12, 29): datetime(2006, 12, 1),
  526. datetime(2006, 1, 2): datetime(2006, 1, 1),
  527. },
  528. )
  529. )
  530. @pytest.mark.parametrize("case", offset_cases)
  531. def test_offset(self, case):
  532. offset, cases = case
  533. for base, expected in cases.items():
  534. assert_offset_equal(offset, base, expected)
  535. class TestMonthEnd:
  536. def test_day_of_month(self):
  537. dt = datetime(2007, 1, 1)
  538. offset = MonthEnd()
  539. result = dt + offset
  540. assert result == Timestamp(2007, 1, 31)
  541. result = result + offset
  542. assert result == Timestamp(2007, 2, 28)
  543. def test_normalize(self):
  544. dt = datetime(2007, 1, 1, 3)
  545. result = dt + MonthEnd(normalize=True)
  546. expected = dt.replace(hour=0) + MonthEnd()
  547. assert result == expected
  548. offset_cases = []
  549. offset_cases.append(
  550. (
  551. MonthEnd(),
  552. {
  553. datetime(2008, 1, 1): datetime(2008, 1, 31),
  554. datetime(2008, 1, 31): datetime(2008, 2, 29),
  555. datetime(2006, 12, 29): datetime(2006, 12, 31),
  556. datetime(2006, 12, 31): datetime(2007, 1, 31),
  557. datetime(2007, 1, 1): datetime(2007, 1, 31),
  558. datetime(2006, 12, 1): datetime(2006, 12, 31),
  559. },
  560. )
  561. )
  562. offset_cases.append(
  563. (
  564. MonthEnd(0),
  565. {
  566. datetime(2008, 1, 1): datetime(2008, 1, 31),
  567. datetime(2008, 1, 31): datetime(2008, 1, 31),
  568. datetime(2006, 12, 29): datetime(2006, 12, 31),
  569. datetime(2006, 12, 31): datetime(2006, 12, 31),
  570. datetime(2007, 1, 1): datetime(2007, 1, 31),
  571. },
  572. )
  573. )
  574. offset_cases.append(
  575. (
  576. MonthEnd(2),
  577. {
  578. datetime(2008, 1, 1): datetime(2008, 2, 29),
  579. datetime(2008, 1, 31): datetime(2008, 3, 31),
  580. datetime(2006, 12, 29): datetime(2007, 1, 31),
  581. datetime(2006, 12, 31): datetime(2007, 2, 28),
  582. datetime(2007, 1, 1): datetime(2007, 2, 28),
  583. datetime(2006, 11, 1): datetime(2006, 12, 31),
  584. },
  585. )
  586. )
  587. offset_cases.append(
  588. (
  589. MonthEnd(-1),
  590. {
  591. datetime(2007, 1, 1): datetime(2006, 12, 31),
  592. datetime(2008, 6, 30): datetime(2008, 5, 31),
  593. datetime(2008, 12, 31): datetime(2008, 11, 30),
  594. datetime(2006, 12, 29): datetime(2006, 11, 30),
  595. datetime(2006, 12, 30): datetime(2006, 11, 30),
  596. datetime(2007, 1, 1): datetime(2006, 12, 31),
  597. },
  598. )
  599. )
  600. @pytest.mark.parametrize("case", offset_cases)
  601. def test_offset(self, case):
  602. offset, cases = case
  603. for base, expected in cases.items():
  604. assert_offset_equal(offset, base, expected)
  605. on_offset_cases = [
  606. (MonthEnd(), datetime(2007, 12, 31), True),
  607. (MonthEnd(), datetime(2008, 1, 1), False),
  608. ]
  609. @pytest.mark.parametrize("case", on_offset_cases)
  610. def test_is_on_offset(self, case):
  611. offset, dt, expected = case
  612. assert_is_on_offset(offset, dt, expected)