test_week.py 12 KB

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