test_week.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. """
  2. Tests for the following offsets:
  3. - Week
  4. - WeekOfMonth
  5. - LastWeekOfMonth
  6. """
  7. from __future__ import annotations
  8. from datetime import (
  9. datetime,
  10. timedelta,
  11. )
  12. import pytest
  13. from pandas._libs.tslibs import Timestamp
  14. from pandas._libs.tslibs.offsets import (
  15. Day,
  16. LastWeekOfMonth,
  17. Week,
  18. WeekOfMonth,
  19. )
  20. import pandas._testing as tm
  21. from pandas.tests.tseries.offsets.common import (
  22. WeekDay,
  23. assert_is_on_offset,
  24. assert_offset_equal,
  25. )
  26. class TestWeek:
  27. def test_repr(self):
  28. assert repr(Week(weekday=0)) == "<Week: weekday=0>"
  29. assert repr(Week(n=-1, weekday=0)) == "<-1 * Week: weekday=0>"
  30. assert repr(Week(n=-2, weekday=0)) == "<-2 * Weeks: weekday=0>"
  31. def test_corner(self):
  32. with pytest.raises(ValueError, match="Day must be"):
  33. Week(weekday=7)
  34. with pytest.raises(ValueError, match="Day must be"):
  35. Week(weekday=-1)
  36. def test_is_anchored(self):
  37. msg = "Week.is_anchored is deprecated "
  38. with tm.assert_produces_warning(FutureWarning, match=msg):
  39. assert Week(weekday=0).is_anchored()
  40. assert not Week().is_anchored()
  41. assert not Week(2, weekday=2).is_anchored()
  42. assert not Week(2).is_anchored()
  43. offset_cases = []
  44. # not business week
  45. offset_cases.append(
  46. (
  47. Week(),
  48. {
  49. datetime(2008, 1, 1): datetime(2008, 1, 8),
  50. datetime(2008, 1, 4): datetime(2008, 1, 11),
  51. datetime(2008, 1, 5): datetime(2008, 1, 12),
  52. datetime(2008, 1, 6): datetime(2008, 1, 13),
  53. datetime(2008, 1, 7): datetime(2008, 1, 14),
  54. },
  55. )
  56. )
  57. # Mon
  58. offset_cases.append(
  59. (
  60. Week(weekday=0),
  61. {
  62. datetime(2007, 12, 31): datetime(2008, 1, 7),
  63. datetime(2008, 1, 4): datetime(2008, 1, 7),
  64. datetime(2008, 1, 5): datetime(2008, 1, 7),
  65. datetime(2008, 1, 6): datetime(2008, 1, 7),
  66. datetime(2008, 1, 7): datetime(2008, 1, 14),
  67. },
  68. )
  69. )
  70. # n=0 -> roll forward. Mon
  71. offset_cases.append(
  72. (
  73. Week(0, weekday=0),
  74. {
  75. datetime(2007, 12, 31): datetime(2007, 12, 31),
  76. datetime(2008, 1, 4): datetime(2008, 1, 7),
  77. datetime(2008, 1, 5): datetime(2008, 1, 7),
  78. datetime(2008, 1, 6): datetime(2008, 1, 7),
  79. datetime(2008, 1, 7): datetime(2008, 1, 7),
  80. },
  81. )
  82. )
  83. # n=0 -> roll forward. Mon
  84. offset_cases.append(
  85. (
  86. Week(-2, weekday=1),
  87. {
  88. datetime(2010, 4, 6): datetime(2010, 3, 23),
  89. datetime(2010, 4, 8): datetime(2010, 3, 30),
  90. datetime(2010, 4, 5): datetime(2010, 3, 23),
  91. },
  92. )
  93. )
  94. @pytest.mark.parametrize("case", offset_cases)
  95. def test_offset(self, case):
  96. offset, cases = case
  97. for base, expected in cases.items():
  98. assert_offset_equal(offset, base, expected)
  99. @pytest.mark.parametrize("weekday", range(7))
  100. def test_is_on_offset(self, weekday):
  101. offset = Week(weekday=weekday)
  102. for day in range(1, 8):
  103. date = datetime(2008, 1, day)
  104. expected = day % 7 == weekday
  105. assert_is_on_offset(offset, date, expected)
  106. @pytest.mark.parametrize(
  107. "n,date",
  108. [
  109. (2, "1862-01-13 09:03:34.873477378+0210"),
  110. (-2, "1856-10-24 16:18:36.556360110-0717"),
  111. ],
  112. )
  113. def test_is_on_offset_weekday_none(self, n, date):
  114. # GH 18510 Week with weekday = None, normalize = False
  115. # should always be is_on_offset
  116. offset = Week(n=n, weekday=None)
  117. ts = Timestamp(date, tz="Africa/Lusaka")
  118. fast = offset.is_on_offset(ts)
  119. slow = (ts + offset) - offset == ts
  120. assert fast == slow
  121. def test_week_add_invalid(self):
  122. # Week with weekday should raise TypeError and _not_ AttributeError
  123. # when adding invalid offset
  124. offset = Week(weekday=1)
  125. other = Day()
  126. with pytest.raises(TypeError, match="Cannot add"):
  127. offset + other
  128. class TestWeekOfMonth:
  129. def test_constructor(self):
  130. with pytest.raises(ValueError, match="^Week"):
  131. WeekOfMonth(n=1, week=4, weekday=0)
  132. with pytest.raises(ValueError, match="^Week"):
  133. WeekOfMonth(n=1, week=-1, weekday=0)
  134. with pytest.raises(ValueError, match="^Day"):
  135. WeekOfMonth(n=1, week=0, weekday=-1)
  136. with pytest.raises(ValueError, match="^Day"):
  137. WeekOfMonth(n=1, week=0, weekday=-7)
  138. def test_repr(self):
  139. assert (
  140. repr(WeekOfMonth(weekday=1, week=2)) == "<WeekOfMonth: week=2, weekday=1>"
  141. )
  142. def test_offset(self):
  143. date1 = datetime(2011, 1, 4) # 1st Tuesday of Month
  144. date2 = datetime(2011, 1, 11) # 2nd Tuesday of Month
  145. date3 = datetime(2011, 1, 18) # 3rd Tuesday of Month
  146. date4 = datetime(2011, 1, 25) # 4th Tuesday of Month
  147. # see for loop for structure
  148. test_cases = [
  149. (-2, 2, 1, date1, datetime(2010, 11, 16)),
  150. (-2, 2, 1, date2, datetime(2010, 11, 16)),
  151. (-2, 2, 1, date3, datetime(2010, 11, 16)),
  152. (-2, 2, 1, date4, datetime(2010, 12, 21)),
  153. (-1, 2, 1, date1, datetime(2010, 12, 21)),
  154. (-1, 2, 1, date2, datetime(2010, 12, 21)),
  155. (-1, 2, 1, date3, datetime(2010, 12, 21)),
  156. (-1, 2, 1, date4, datetime(2011, 1, 18)),
  157. (0, 0, 1, date1, datetime(2011, 1, 4)),
  158. (0, 0, 1, date2, datetime(2011, 2, 1)),
  159. (0, 0, 1, date3, datetime(2011, 2, 1)),
  160. (0, 0, 1, date4, datetime(2011, 2, 1)),
  161. (0, 1, 1, date1, datetime(2011, 1, 11)),
  162. (0, 1, 1, date2, datetime(2011, 1, 11)),
  163. (0, 1, 1, date3, datetime(2011, 2, 8)),
  164. (0, 1, 1, date4, datetime(2011, 2, 8)),
  165. (0, 0, 1, date1, datetime(2011, 1, 4)),
  166. (0, 1, 1, date2, datetime(2011, 1, 11)),
  167. (0, 2, 1, date3, datetime(2011, 1, 18)),
  168. (0, 3, 1, date4, datetime(2011, 1, 25)),
  169. (1, 0, 0, date1, datetime(2011, 2, 7)),
  170. (1, 0, 0, date2, datetime(2011, 2, 7)),
  171. (1, 0, 0, date3, datetime(2011, 2, 7)),
  172. (1, 0, 0, date4, datetime(2011, 2, 7)),
  173. (1, 0, 1, date1, datetime(2011, 2, 1)),
  174. (1, 0, 1, date2, datetime(2011, 2, 1)),
  175. (1, 0, 1, date3, datetime(2011, 2, 1)),
  176. (1, 0, 1, date4, datetime(2011, 2, 1)),
  177. (1, 0, 2, date1, datetime(2011, 1, 5)),
  178. (1, 0, 2, date2, datetime(2011, 2, 2)),
  179. (1, 0, 2, date3, datetime(2011, 2, 2)),
  180. (1, 0, 2, date4, datetime(2011, 2, 2)),
  181. (1, 2, 1, date1, datetime(2011, 1, 18)),
  182. (1, 2, 1, date2, datetime(2011, 1, 18)),
  183. (1, 2, 1, date3, datetime(2011, 2, 15)),
  184. (1, 2, 1, date4, datetime(2011, 2, 15)),
  185. (2, 2, 1, date1, datetime(2011, 2, 15)),
  186. (2, 2, 1, date2, datetime(2011, 2, 15)),
  187. (2, 2, 1, date3, datetime(2011, 3, 15)),
  188. (2, 2, 1, date4, datetime(2011, 3, 15)),
  189. ]
  190. for n, week, weekday, dt, expected in test_cases:
  191. offset = WeekOfMonth(n, week=week, weekday=weekday)
  192. assert_offset_equal(offset, dt, expected)
  193. # try subtracting
  194. result = datetime(2011, 2, 1) - WeekOfMonth(week=1, weekday=2)
  195. assert result == datetime(2011, 1, 12)
  196. result = datetime(2011, 2, 3) - WeekOfMonth(week=0, weekday=2)
  197. assert result == datetime(2011, 2, 2)
  198. on_offset_cases = [
  199. (0, 0, datetime(2011, 2, 7), True),
  200. (0, 0, datetime(2011, 2, 6), False),
  201. (0, 0, datetime(2011, 2, 14), False),
  202. (1, 0, datetime(2011, 2, 14), True),
  203. (0, 1, datetime(2011, 2, 1), True),
  204. (0, 1, datetime(2011, 2, 8), False),
  205. ]
  206. @pytest.mark.parametrize("case", on_offset_cases)
  207. def test_is_on_offset(self, case):
  208. week, weekday, dt, expected = case
  209. offset = WeekOfMonth(week=week, weekday=weekday)
  210. assert offset.is_on_offset(dt) == expected
  211. @pytest.mark.parametrize(
  212. "n,week,date,tz",
  213. [
  214. (2, 2, "1916-05-15 01:14:49.583410462+0422", "Asia/Qyzylorda"),
  215. (-3, 1, "1980-12-08 03:38:52.878321185+0500", "Asia/Oral"),
  216. ],
  217. )
  218. def test_is_on_offset_nanoseconds(self, n, week, date, tz):
  219. # GH 18864
  220. # Make sure that nanoseconds don't trip up is_on_offset (and with it apply)
  221. offset = WeekOfMonth(n=n, week=week, weekday=0)
  222. ts = Timestamp(date, tz=tz)
  223. fast = offset.is_on_offset(ts)
  224. slow = (ts + offset) - offset == ts
  225. assert fast == slow
  226. class TestLastWeekOfMonth:
  227. def test_constructor(self):
  228. with pytest.raises(ValueError, match="^N cannot be 0"):
  229. LastWeekOfMonth(n=0, weekday=1)
  230. with pytest.raises(ValueError, match="^Day"):
  231. LastWeekOfMonth(n=1, weekday=-1)
  232. with pytest.raises(ValueError, match="^Day"):
  233. LastWeekOfMonth(n=1, weekday=7)
  234. def test_offset(self):
  235. # Saturday
  236. last_sat = datetime(2013, 8, 31)
  237. next_sat = datetime(2013, 9, 28)
  238. offset_sat = LastWeekOfMonth(n=1, weekday=5)
  239. one_day_before = last_sat + timedelta(days=-1)
  240. assert one_day_before + offset_sat == last_sat
  241. one_day_after = last_sat + timedelta(days=+1)
  242. assert one_day_after + offset_sat == next_sat
  243. # Test On that day
  244. assert last_sat + offset_sat == next_sat
  245. # Thursday
  246. offset_thur = LastWeekOfMonth(n=1, weekday=3)
  247. last_thurs = datetime(2013, 1, 31)
  248. next_thurs = datetime(2013, 2, 28)
  249. one_day_before = last_thurs + timedelta(days=-1)
  250. assert one_day_before + offset_thur == last_thurs
  251. one_day_after = last_thurs + timedelta(days=+1)
  252. assert one_day_after + offset_thur == next_thurs
  253. # Test on that day
  254. assert last_thurs + offset_thur == next_thurs
  255. three_before = last_thurs + timedelta(days=-3)
  256. assert three_before + offset_thur == last_thurs
  257. two_after = last_thurs + timedelta(days=+2)
  258. assert two_after + offset_thur == next_thurs
  259. offset_sunday = LastWeekOfMonth(n=1, weekday=WeekDay.SUN)
  260. assert datetime(2013, 7, 31) + offset_sunday == datetime(2013, 8, 25)
  261. on_offset_cases = [
  262. (WeekDay.SUN, datetime(2013, 1, 27), True),
  263. (WeekDay.SAT, datetime(2013, 3, 30), True),
  264. (WeekDay.MON, datetime(2013, 2, 18), False), # Not the last Mon
  265. (WeekDay.SUN, datetime(2013, 2, 25), False), # Not a SUN
  266. (WeekDay.MON, datetime(2013, 2, 25), True),
  267. (WeekDay.SAT, datetime(2013, 11, 30), True),
  268. (WeekDay.SAT, datetime(2006, 8, 26), True),
  269. (WeekDay.SAT, datetime(2007, 8, 25), True),
  270. (WeekDay.SAT, datetime(2008, 8, 30), True),
  271. (WeekDay.SAT, datetime(2009, 8, 29), True),
  272. (WeekDay.SAT, datetime(2010, 8, 28), True),
  273. (WeekDay.SAT, datetime(2011, 8, 27), True),
  274. (WeekDay.SAT, datetime(2019, 8, 31), True),
  275. ]
  276. @pytest.mark.parametrize("case", on_offset_cases)
  277. def test_is_on_offset(self, case):
  278. weekday, dt, expected = case
  279. offset = LastWeekOfMonth(weekday=weekday)
  280. assert offset.is_on_offset(dt) == expected
  281. @pytest.mark.parametrize(
  282. "n,weekday,date,tz",
  283. [
  284. (4, 6, "1917-05-27 20:55:27.084284178+0200", "Europe/Warsaw"),
  285. (-4, 5, "2005-08-27 05:01:42.799392561-0500", "America/Rainy_River"),
  286. ],
  287. )
  288. def test_last_week_of_month_on_offset(self, n, weekday, date, tz):
  289. # GH 19036, GH 18977 _adjust_dst was incorrect for LastWeekOfMonth
  290. offset = LastWeekOfMonth(n=n, weekday=weekday)
  291. ts = Timestamp(date, tz=tz)
  292. slow = (ts + offset) - offset == ts
  293. fast = offset.is_on_offset(ts)
  294. assert fast == slow
  295. def test_repr(self):
  296. assert (
  297. repr(LastWeekOfMonth(n=2, weekday=1)) == "<2 * LastWeekOfMonths: weekday=1>"
  298. )