test_frequencies.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. from datetime import datetime, timedelta
  2. import numpy as np
  3. import pytest
  4. from pandas._libs.tslibs import frequencies as libfrequencies, resolution
  5. from pandas._libs.tslibs.ccalendar import MONTHS
  6. from pandas._libs.tslibs.frequencies import (
  7. INVALID_FREQ_ERR_MSG, FreqGroup, _period_code_map, get_freq, get_freq_code)
  8. import pandas.compat as compat
  9. from pandas.compat import is_platform_windows, range
  10. from pandas import (
  11. DatetimeIndex, Index, Series, Timedelta, Timestamp, date_range,
  12. period_range)
  13. from pandas.core.tools.datetimes import to_datetime
  14. import pandas.util.testing as tm
  15. import pandas.tseries.frequencies as frequencies
  16. import pandas.tseries.offsets as offsets
  17. class TestToOffset(object):
  18. def test_to_offset_multiple(self):
  19. freqstr = '2h30min'
  20. freqstr2 = '2h 30min'
  21. result = frequencies.to_offset(freqstr)
  22. assert (result == frequencies.to_offset(freqstr2))
  23. expected = offsets.Minute(150)
  24. assert (result == expected)
  25. freqstr = '2h30min15s'
  26. result = frequencies.to_offset(freqstr)
  27. expected = offsets.Second(150 * 60 + 15)
  28. assert (result == expected)
  29. freqstr = '2h 60min'
  30. result = frequencies.to_offset(freqstr)
  31. expected = offsets.Hour(3)
  32. assert (result == expected)
  33. freqstr = '2h 20.5min'
  34. result = frequencies.to_offset(freqstr)
  35. expected = offsets.Second(8430)
  36. assert (result == expected)
  37. freqstr = '1.5min'
  38. result = frequencies.to_offset(freqstr)
  39. expected = offsets.Second(90)
  40. assert (result == expected)
  41. freqstr = '0.5S'
  42. result = frequencies.to_offset(freqstr)
  43. expected = offsets.Milli(500)
  44. assert (result == expected)
  45. freqstr = '15l500u'
  46. result = frequencies.to_offset(freqstr)
  47. expected = offsets.Micro(15500)
  48. assert (result == expected)
  49. freqstr = '10s75L'
  50. result = frequencies.to_offset(freqstr)
  51. expected = offsets.Milli(10075)
  52. assert (result == expected)
  53. freqstr = '1s0.25ms'
  54. result = frequencies.to_offset(freqstr)
  55. expected = offsets.Micro(1000250)
  56. assert (result == expected)
  57. freqstr = '1s0.25L'
  58. result = frequencies.to_offset(freqstr)
  59. expected = offsets.Micro(1000250)
  60. assert (result == expected)
  61. freqstr = '2800N'
  62. result = frequencies.to_offset(freqstr)
  63. expected = offsets.Nano(2800)
  64. assert (result == expected)
  65. freqstr = '2SM'
  66. result = frequencies.to_offset(freqstr)
  67. expected = offsets.SemiMonthEnd(2)
  68. assert (result == expected)
  69. freqstr = '2SM-16'
  70. result = frequencies.to_offset(freqstr)
  71. expected = offsets.SemiMonthEnd(2, day_of_month=16)
  72. assert (result == expected)
  73. freqstr = '2SMS-14'
  74. result = frequencies.to_offset(freqstr)
  75. expected = offsets.SemiMonthBegin(2, day_of_month=14)
  76. assert (result == expected)
  77. freqstr = '2SMS-15'
  78. result = frequencies.to_offset(freqstr)
  79. expected = offsets.SemiMonthBegin(2)
  80. assert (result == expected)
  81. # malformed
  82. with pytest.raises(ValueError, match='Invalid frequency: 2h20m'):
  83. frequencies.to_offset('2h20m')
  84. def test_to_offset_negative(self):
  85. freqstr = '-1S'
  86. result = frequencies.to_offset(freqstr)
  87. assert (result.n == -1)
  88. freqstr = '-5min10s'
  89. result = frequencies.to_offset(freqstr)
  90. assert (result.n == -310)
  91. freqstr = '-2SM'
  92. result = frequencies.to_offset(freqstr)
  93. assert (result.n == -2)
  94. freqstr = '-1SMS'
  95. result = frequencies.to_offset(freqstr)
  96. assert (result.n == -1)
  97. def test_to_offset_invalid(self):
  98. # GH 13930
  99. with pytest.raises(ValueError, match='Invalid frequency: U1'):
  100. frequencies.to_offset('U1')
  101. with pytest.raises(ValueError, match='Invalid frequency: -U'):
  102. frequencies.to_offset('-U')
  103. with pytest.raises(ValueError, match='Invalid frequency: 3U1'):
  104. frequencies.to_offset('3U1')
  105. with pytest.raises(ValueError, match='Invalid frequency: -2-3U'):
  106. frequencies.to_offset('-2-3U')
  107. with pytest.raises(ValueError, match='Invalid frequency: -2D:3H'):
  108. frequencies.to_offset('-2D:3H')
  109. with pytest.raises(ValueError, match='Invalid frequency: 1.5.0S'):
  110. frequencies.to_offset('1.5.0S')
  111. # split offsets with spaces are valid
  112. assert frequencies.to_offset('2D 3H') == offsets.Hour(51)
  113. assert frequencies.to_offset('2 D3 H') == offsets.Hour(51)
  114. assert frequencies.to_offset('2 D 3 H') == offsets.Hour(51)
  115. assert frequencies.to_offset(' 2 D 3 H ') == offsets.Hour(51)
  116. assert frequencies.to_offset(' H ') == offsets.Hour()
  117. assert frequencies.to_offset(' 3 H ') == offsets.Hour(3)
  118. # special cases
  119. assert frequencies.to_offset('2SMS-15') == offsets.SemiMonthBegin(2)
  120. with pytest.raises(ValueError, match='Invalid frequency: 2SMS-15-15'):
  121. frequencies.to_offset('2SMS-15-15')
  122. with pytest.raises(ValueError, match='Invalid frequency: 2SMS-15D'):
  123. frequencies.to_offset('2SMS-15D')
  124. def test_to_offset_leading_zero(self):
  125. freqstr = '00H 00T 01S'
  126. result = frequencies.to_offset(freqstr)
  127. assert (result.n == 1)
  128. freqstr = '-00H 03T 14S'
  129. result = frequencies.to_offset(freqstr)
  130. assert (result.n == -194)
  131. def test_to_offset_leading_plus(self):
  132. freqstr = '+1d'
  133. result = frequencies.to_offset(freqstr)
  134. assert (result.n == 1)
  135. freqstr = '+2h30min'
  136. result = frequencies.to_offset(freqstr)
  137. assert (result.n == 150)
  138. for bad_freq in ['+-1d', '-+1h', '+1', '-7', '+d', '-m']:
  139. with pytest.raises(ValueError, match='Invalid frequency:'):
  140. frequencies.to_offset(bad_freq)
  141. def test_to_offset_pd_timedelta(self):
  142. # Tests for #9064
  143. td = Timedelta(days=1, seconds=1)
  144. result = frequencies.to_offset(td)
  145. expected = offsets.Second(86401)
  146. assert (expected == result)
  147. td = Timedelta(days=-1, seconds=1)
  148. result = frequencies.to_offset(td)
  149. expected = offsets.Second(-86399)
  150. assert (expected == result)
  151. td = Timedelta(hours=1, minutes=10)
  152. result = frequencies.to_offset(td)
  153. expected = offsets.Minute(70)
  154. assert (expected == result)
  155. td = Timedelta(hours=1, minutes=-10)
  156. result = frequencies.to_offset(td)
  157. expected = offsets.Minute(50)
  158. assert (expected == result)
  159. td = Timedelta(weeks=1)
  160. result = frequencies.to_offset(td)
  161. expected = offsets.Day(7)
  162. assert (expected == result)
  163. td1 = Timedelta(hours=1)
  164. result1 = frequencies.to_offset(td1)
  165. result2 = frequencies.to_offset('60min')
  166. assert (result1 == result2)
  167. td = Timedelta(microseconds=1)
  168. result = frequencies.to_offset(td)
  169. expected = offsets.Micro(1)
  170. assert (expected == result)
  171. td = Timedelta(microseconds=0)
  172. pytest.raises(ValueError, lambda: frequencies.to_offset(td))
  173. def test_anchored_shortcuts(self):
  174. result = frequencies.to_offset('W')
  175. expected = frequencies.to_offset('W-SUN')
  176. assert (result == expected)
  177. result1 = frequencies.to_offset('Q')
  178. result2 = frequencies.to_offset('Q-DEC')
  179. expected = offsets.QuarterEnd(startingMonth=12)
  180. assert (result1 == expected)
  181. assert (result2 == expected)
  182. result1 = frequencies.to_offset('Q-MAY')
  183. expected = offsets.QuarterEnd(startingMonth=5)
  184. assert (result1 == expected)
  185. result1 = frequencies.to_offset('SM')
  186. result2 = frequencies.to_offset('SM-15')
  187. expected = offsets.SemiMonthEnd(day_of_month=15)
  188. assert (result1 == expected)
  189. assert (result2 == expected)
  190. result = frequencies.to_offset('SM-1')
  191. expected = offsets.SemiMonthEnd(day_of_month=1)
  192. assert (result == expected)
  193. result = frequencies.to_offset('SM-27')
  194. expected = offsets.SemiMonthEnd(day_of_month=27)
  195. assert (result == expected)
  196. result = frequencies.to_offset('SMS-2')
  197. expected = offsets.SemiMonthBegin(day_of_month=2)
  198. assert (result == expected)
  199. result = frequencies.to_offset('SMS-27')
  200. expected = offsets.SemiMonthBegin(day_of_month=27)
  201. assert (result == expected)
  202. # ensure invalid cases fail as expected
  203. invalid_anchors = ['SM-0', 'SM-28', 'SM-29',
  204. 'SM-FOO', 'BSM', 'SM--1',
  205. 'SMS-1', 'SMS-28', 'SMS-30',
  206. 'SMS-BAR', 'SMS-BYR' 'BSMS',
  207. 'SMS--2']
  208. for invalid_anchor in invalid_anchors:
  209. with pytest.raises(ValueError, match='Invalid frequency: '):
  210. frequencies.to_offset(invalid_anchor)
  211. def test_ms_vs_MS():
  212. left = frequencies.get_offset('ms')
  213. right = frequencies.get_offset('MS')
  214. assert left == offsets.Milli()
  215. assert right == offsets.MonthBegin()
  216. def test_rule_aliases():
  217. rule = frequencies.to_offset('10us')
  218. assert rule == offsets.Micro(10)
  219. class TestFrequencyCode(object):
  220. def test_freq_code(self):
  221. assert get_freq('A') == 1000
  222. assert get_freq('3A') == 1000
  223. assert get_freq('-1A') == 1000
  224. assert get_freq('Y') == 1000
  225. assert get_freq('3Y') == 1000
  226. assert get_freq('-1Y') == 1000
  227. assert get_freq('W') == 4000
  228. assert get_freq('W-MON') == 4001
  229. assert get_freq('W-FRI') == 4005
  230. for freqstr, code in compat.iteritems(_period_code_map):
  231. result = get_freq(freqstr)
  232. assert result == code
  233. result = resolution.get_freq_group(freqstr)
  234. assert result == code // 1000 * 1000
  235. result = resolution.get_freq_group(code)
  236. assert result == code // 1000 * 1000
  237. def test_freq_group(self):
  238. assert resolution.get_freq_group('A') == 1000
  239. assert resolution.get_freq_group('3A') == 1000
  240. assert resolution.get_freq_group('-1A') == 1000
  241. assert resolution.get_freq_group('A-JAN') == 1000
  242. assert resolution.get_freq_group('A-MAY') == 1000
  243. assert resolution.get_freq_group('Y') == 1000
  244. assert resolution.get_freq_group('3Y') == 1000
  245. assert resolution.get_freq_group('-1Y') == 1000
  246. assert resolution.get_freq_group('Y-JAN') == 1000
  247. assert resolution.get_freq_group('Y-MAY') == 1000
  248. assert resolution.get_freq_group(offsets.YearEnd()) == 1000
  249. assert resolution.get_freq_group(offsets.YearEnd(month=1)) == 1000
  250. assert resolution.get_freq_group(offsets.YearEnd(month=5)) == 1000
  251. assert resolution.get_freq_group('W') == 4000
  252. assert resolution.get_freq_group('W-MON') == 4000
  253. assert resolution.get_freq_group('W-FRI') == 4000
  254. assert resolution.get_freq_group(offsets.Week()) == 4000
  255. assert resolution.get_freq_group(offsets.Week(weekday=1)) == 4000
  256. assert resolution.get_freq_group(offsets.Week(weekday=5)) == 4000
  257. def test_get_to_timestamp_base(self):
  258. tsb = libfrequencies.get_to_timestamp_base
  259. assert (tsb(get_freq_code('D')[0]) ==
  260. get_freq_code('D')[0])
  261. assert (tsb(get_freq_code('W')[0]) ==
  262. get_freq_code('D')[0])
  263. assert (tsb(get_freq_code('M')[0]) ==
  264. get_freq_code('D')[0])
  265. assert (tsb(get_freq_code('S')[0]) ==
  266. get_freq_code('S')[0])
  267. assert (tsb(get_freq_code('T')[0]) ==
  268. get_freq_code('S')[0])
  269. assert (tsb(get_freq_code('H')[0]) ==
  270. get_freq_code('S')[0])
  271. def test_freq_to_reso(self):
  272. Reso = resolution.Resolution
  273. assert Reso.get_str_from_freq('A') == 'year'
  274. assert Reso.get_str_from_freq('Q') == 'quarter'
  275. assert Reso.get_str_from_freq('M') == 'month'
  276. assert Reso.get_str_from_freq('D') == 'day'
  277. assert Reso.get_str_from_freq('H') == 'hour'
  278. assert Reso.get_str_from_freq('T') == 'minute'
  279. assert Reso.get_str_from_freq('S') == 'second'
  280. assert Reso.get_str_from_freq('L') == 'millisecond'
  281. assert Reso.get_str_from_freq('U') == 'microsecond'
  282. assert Reso.get_str_from_freq('N') == 'nanosecond'
  283. for freq in ['A', 'Q', 'M', 'D', 'H', 'T', 'S', 'L', 'U', 'N']:
  284. # check roundtrip
  285. result = Reso.get_freq(Reso.get_str_from_freq(freq))
  286. assert freq == result
  287. for freq in ['D', 'H', 'T', 'S', 'L', 'U']:
  288. result = Reso.get_freq(Reso.get_str(Reso.get_reso_from_freq(freq)))
  289. assert freq == result
  290. def test_resolution_bumping(self):
  291. # see gh-14378
  292. Reso = resolution.Resolution
  293. assert Reso.get_stride_from_decimal(1.5, 'T') == (90, 'S')
  294. assert Reso.get_stride_from_decimal(62.4, 'T') == (3744, 'S')
  295. assert Reso.get_stride_from_decimal(1.04, 'H') == (3744, 'S')
  296. assert Reso.get_stride_from_decimal(1, 'D') == (1, 'D')
  297. assert (Reso.get_stride_from_decimal(0.342931, 'H') ==
  298. (1234551600, 'U'))
  299. assert Reso.get_stride_from_decimal(1.2345, 'D') == (106660800, 'L')
  300. with pytest.raises(ValueError):
  301. Reso.get_stride_from_decimal(0.5, 'N')
  302. # too much precision in the input can prevent
  303. with pytest.raises(ValueError):
  304. Reso.get_stride_from_decimal(0.3429324798798269273987982, 'H')
  305. def test_get_freq_code(self):
  306. # frequency str
  307. assert (get_freq_code('A') ==
  308. (get_freq('A'), 1))
  309. assert (get_freq_code('3D') ==
  310. (get_freq('D'), 3))
  311. assert (get_freq_code('-2M') ==
  312. (get_freq('M'), -2))
  313. # tuple
  314. assert (get_freq_code(('D', 1)) ==
  315. (get_freq('D'), 1))
  316. assert (get_freq_code(('A', 3)) ==
  317. (get_freq('A'), 3))
  318. assert (get_freq_code(('M', -2)) ==
  319. (get_freq('M'), -2))
  320. # numeric tuple
  321. assert get_freq_code((1000, 1)) == (1000, 1)
  322. # offsets
  323. assert (get_freq_code(offsets.Day()) ==
  324. (get_freq('D'), 1))
  325. assert (get_freq_code(offsets.Day(3)) ==
  326. (get_freq('D'), 3))
  327. assert (get_freq_code(offsets.Day(-2)) ==
  328. (get_freq('D'), -2))
  329. assert (get_freq_code(offsets.MonthEnd()) ==
  330. (get_freq('M'), 1))
  331. assert (get_freq_code(offsets.MonthEnd(3)) ==
  332. (get_freq('M'), 3))
  333. assert (get_freq_code(offsets.MonthEnd(-2)) ==
  334. (get_freq('M'), -2))
  335. assert (get_freq_code(offsets.Week()) ==
  336. (get_freq('W'), 1))
  337. assert (get_freq_code(offsets.Week(3)) ==
  338. (get_freq('W'), 3))
  339. assert (get_freq_code(offsets.Week(-2)) ==
  340. (get_freq('W'), -2))
  341. # Monday is weekday=0
  342. assert (get_freq_code(offsets.Week(weekday=1)) ==
  343. (get_freq('W-TUE'), 1))
  344. assert (get_freq_code(offsets.Week(3, weekday=0)) ==
  345. (get_freq('W-MON'), 3))
  346. assert (get_freq_code(offsets.Week(-2, weekday=4)) ==
  347. (get_freq('W-FRI'), -2))
  348. def test_frequency_misc(self):
  349. assert (resolution.get_freq_group('T') ==
  350. FreqGroup.FR_MIN)
  351. code, stride = get_freq_code(offsets.Hour())
  352. assert code == FreqGroup.FR_HR
  353. code, stride = get_freq_code((5, 'T'))
  354. assert code == FreqGroup.FR_MIN
  355. assert stride == 5
  356. offset = offsets.Hour()
  357. result = frequencies.to_offset(offset)
  358. assert result == offset
  359. result = frequencies.to_offset((5, 'T'))
  360. expected = offsets.Minute(5)
  361. assert result == expected
  362. with pytest.raises(ValueError, match='Invalid frequency'):
  363. get_freq_code((5, 'baz'))
  364. with pytest.raises(ValueError, match='Invalid frequency'):
  365. frequencies.to_offset('100foo')
  366. with pytest.raises(ValueError, match='Could not evaluate'):
  367. frequencies.to_offset(('', ''))
  368. _dti = DatetimeIndex
  369. class TestFrequencyInference(object):
  370. def test_raise_if_period_index(self):
  371. index = period_range(start="1/1/1990", periods=20, freq="M")
  372. pytest.raises(TypeError, frequencies.infer_freq, index)
  373. def test_raise_if_too_few(self):
  374. index = _dti(['12/31/1998', '1/3/1999'])
  375. pytest.raises(ValueError, frequencies.infer_freq, index)
  376. def test_business_daily(self):
  377. index = _dti(['01/01/1999', '1/4/1999', '1/5/1999'])
  378. assert frequencies.infer_freq(index) == 'B'
  379. def test_business_daily_look_alike(self):
  380. # GH 16624, do not infer 'B' when 'weekend' (2-day gap) in wrong place
  381. index = _dti(['12/31/1998', '1/3/1999', '1/4/1999'])
  382. assert frequencies.infer_freq(index) is None
  383. def test_day(self):
  384. self._check_tick(timedelta(1), 'D')
  385. def test_day_corner(self):
  386. index = _dti(['1/1/2000', '1/2/2000', '1/3/2000'])
  387. assert frequencies.infer_freq(index) == 'D'
  388. def test_non_datetimeindex(self):
  389. dates = to_datetime(['1/1/2000', '1/2/2000', '1/3/2000'])
  390. assert frequencies.infer_freq(dates) == 'D'
  391. def test_hour(self):
  392. self._check_tick(timedelta(hours=1), 'H')
  393. def test_minute(self):
  394. self._check_tick(timedelta(minutes=1), 'T')
  395. def test_second(self):
  396. self._check_tick(timedelta(seconds=1), 'S')
  397. def test_millisecond(self):
  398. self._check_tick(timedelta(microseconds=1000), 'L')
  399. def test_microsecond(self):
  400. self._check_tick(timedelta(microseconds=1), 'U')
  401. def test_nanosecond(self):
  402. self._check_tick(np.timedelta64(1, 'ns'), 'N')
  403. def _check_tick(self, base_delta, code):
  404. b = Timestamp(datetime.now())
  405. for i in range(1, 5):
  406. inc = base_delta * i
  407. index = _dti([b + inc * j for j in range(3)])
  408. if i > 1:
  409. exp_freq = '%d%s' % (i, code)
  410. else:
  411. exp_freq = code
  412. assert frequencies.infer_freq(index) == exp_freq
  413. index = _dti([b + base_delta * 7] + [b + base_delta * j for j in range(
  414. 3)])
  415. assert frequencies.infer_freq(index) is None
  416. index = _dti([b + base_delta * j for j in range(3)] + [b + base_delta *
  417. 7])
  418. assert frequencies.infer_freq(index) is None
  419. def test_weekly(self):
  420. days = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN']
  421. for day in days:
  422. self._check_generated_range('1/1/2000', 'W-%s' % day)
  423. def test_week_of_month(self):
  424. days = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN']
  425. for day in days:
  426. for i in range(1, 5):
  427. self._check_generated_range('1/1/2000', 'WOM-%d%s' % (i, day))
  428. def test_fifth_week_of_month(self):
  429. # Only supports freq up to WOM-4. See #9425
  430. func = lambda: date_range('2014-01-01', freq='WOM-5MON')
  431. pytest.raises(ValueError, func)
  432. def test_fifth_week_of_month_infer(self):
  433. # Only attempts to infer up to WOM-4. See #9425
  434. index = DatetimeIndex(["2014-03-31", "2014-06-30", "2015-03-30"])
  435. assert frequencies.infer_freq(index) is None
  436. def test_week_of_month_fake(self):
  437. # All of these dates are on same day of week and are 4 or 5 weeks apart
  438. index = DatetimeIndex(["2013-08-27", "2013-10-01", "2013-10-29",
  439. "2013-11-26"])
  440. assert frequencies.infer_freq(index) != 'WOM-4TUE'
  441. def test_monthly(self):
  442. self._check_generated_range('1/1/2000', 'M')
  443. def test_monthly_ambiguous(self):
  444. rng = _dti(['1/31/2000', '2/29/2000', '3/31/2000'])
  445. assert rng.inferred_freq == 'M'
  446. def test_business_monthly(self):
  447. self._check_generated_range('1/1/2000', 'BM')
  448. def test_business_start_monthly(self):
  449. self._check_generated_range('1/1/2000', 'BMS')
  450. def test_quarterly(self):
  451. for month in ['JAN', 'FEB', 'MAR']:
  452. self._check_generated_range('1/1/2000', 'Q-%s' % month)
  453. def test_annual(self):
  454. for month in MONTHS:
  455. self._check_generated_range('1/1/2000', 'A-%s' % month)
  456. def test_business_annual(self):
  457. for month in MONTHS:
  458. self._check_generated_range('1/1/2000', 'BA-%s' % month)
  459. def test_annual_ambiguous(self):
  460. rng = _dti(['1/31/2000', '1/31/2001', '1/31/2002'])
  461. assert rng.inferred_freq == 'A-JAN'
  462. def _check_generated_range(self, start, freq):
  463. freq = freq.upper()
  464. gen = date_range(start, periods=7, freq=freq)
  465. index = _dti(gen.values)
  466. if not freq.startswith('Q-'):
  467. assert frequencies.infer_freq(index) == gen.freqstr
  468. else:
  469. inf_freq = frequencies.infer_freq(index)
  470. is_dec_range = inf_freq == 'Q-DEC' and gen.freqstr in (
  471. 'Q', 'Q-DEC', 'Q-SEP', 'Q-JUN', 'Q-MAR')
  472. is_nov_range = inf_freq == 'Q-NOV' and gen.freqstr in (
  473. 'Q-NOV', 'Q-AUG', 'Q-MAY', 'Q-FEB')
  474. is_oct_range = inf_freq == 'Q-OCT' and gen.freqstr in (
  475. 'Q-OCT', 'Q-JUL', 'Q-APR', 'Q-JAN')
  476. assert is_dec_range or is_nov_range or is_oct_range
  477. gen = date_range(start, periods=5, freq=freq)
  478. index = _dti(gen.values)
  479. if not freq.startswith('Q-'):
  480. assert frequencies.infer_freq(index) == gen.freqstr
  481. else:
  482. inf_freq = frequencies.infer_freq(index)
  483. is_dec_range = inf_freq == 'Q-DEC' and gen.freqstr in (
  484. 'Q', 'Q-DEC', 'Q-SEP', 'Q-JUN', 'Q-MAR')
  485. is_nov_range = inf_freq == 'Q-NOV' and gen.freqstr in (
  486. 'Q-NOV', 'Q-AUG', 'Q-MAY', 'Q-FEB')
  487. is_oct_range = inf_freq == 'Q-OCT' and gen.freqstr in (
  488. 'Q-OCT', 'Q-JUL', 'Q-APR', 'Q-JAN')
  489. assert is_dec_range or is_nov_range or is_oct_range
  490. def test_infer_freq(self):
  491. rng = period_range('1959Q2', '2009Q3', freq='Q')
  492. rng = Index(rng.to_timestamp('D', how='e').astype(object))
  493. assert rng.inferred_freq == 'Q-DEC'
  494. rng = period_range('1959Q2', '2009Q3', freq='Q-NOV')
  495. rng = Index(rng.to_timestamp('D', how='e').astype(object))
  496. assert rng.inferred_freq == 'Q-NOV'
  497. rng = period_range('1959Q2', '2009Q3', freq='Q-OCT')
  498. rng = Index(rng.to_timestamp('D', how='e').astype(object))
  499. assert rng.inferred_freq == 'Q-OCT'
  500. def test_infer_freq_tz(self):
  501. freqs = {'AS-JAN':
  502. ['2009-01-01', '2010-01-01', '2011-01-01', '2012-01-01'],
  503. 'Q-OCT':
  504. ['2009-01-31', '2009-04-30', '2009-07-31', '2009-10-31'],
  505. 'M': ['2010-11-30', '2010-12-31', '2011-01-31', '2011-02-28'],
  506. 'W-SAT':
  507. ['2010-12-25', '2011-01-01', '2011-01-08', '2011-01-15'],
  508. 'D': ['2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04'],
  509. 'H': ['2011-12-31 22:00', '2011-12-31 23:00',
  510. '2012-01-01 00:00', '2012-01-01 01:00']}
  511. # GH 7310
  512. for tz in [None, 'Australia/Sydney', 'Asia/Tokyo', 'Europe/Paris',
  513. 'US/Pacific', 'US/Eastern']:
  514. for expected, dates in compat.iteritems(freqs):
  515. idx = DatetimeIndex(dates, tz=tz)
  516. assert idx.inferred_freq == expected
  517. def test_infer_freq_tz_transition(self):
  518. # Tests for #8772
  519. date_pairs = [['2013-11-02', '2013-11-5'], # Fall DST
  520. ['2014-03-08', '2014-03-11'], # Spring DST
  521. ['2014-01-01', '2014-01-03']] # Regular Time
  522. freqs = ['3H', '10T', '3601S', '3600001L', '3600000001U',
  523. '3600000000001N']
  524. for tz in [None, 'Australia/Sydney', 'Asia/Tokyo', 'Europe/Paris',
  525. 'US/Pacific', 'US/Eastern']:
  526. for date_pair in date_pairs:
  527. for freq in freqs:
  528. idx = date_range(date_pair[0], date_pair[
  529. 1], freq=freq, tz=tz)
  530. assert idx.inferred_freq == freq
  531. index = date_range("2013-11-03", periods=5,
  532. freq="3H").tz_localize("America/Chicago")
  533. assert index.inferred_freq is None
  534. def test_infer_freq_businesshour(self):
  535. # GH 7905
  536. idx = DatetimeIndex(
  537. ['2014-07-01 09:00', '2014-07-01 10:00', '2014-07-01 11:00',
  538. '2014-07-01 12:00', '2014-07-01 13:00', '2014-07-01 14:00'])
  539. # hourly freq in a day must result in 'H'
  540. assert idx.inferred_freq == 'H'
  541. idx = DatetimeIndex(
  542. ['2014-07-01 09:00', '2014-07-01 10:00', '2014-07-01 11:00',
  543. '2014-07-01 12:00', '2014-07-01 13:00', '2014-07-01 14:00',
  544. '2014-07-01 15:00', '2014-07-01 16:00', '2014-07-02 09:00',
  545. '2014-07-02 10:00', '2014-07-02 11:00'])
  546. assert idx.inferred_freq == 'BH'
  547. idx = DatetimeIndex(
  548. ['2014-07-04 09:00', '2014-07-04 10:00', '2014-07-04 11:00',
  549. '2014-07-04 12:00', '2014-07-04 13:00', '2014-07-04 14:00',
  550. '2014-07-04 15:00', '2014-07-04 16:00', '2014-07-07 09:00',
  551. '2014-07-07 10:00', '2014-07-07 11:00'])
  552. assert idx.inferred_freq == 'BH'
  553. idx = DatetimeIndex(
  554. ['2014-07-04 09:00', '2014-07-04 10:00', '2014-07-04 11:00',
  555. '2014-07-04 12:00', '2014-07-04 13:00', '2014-07-04 14:00',
  556. '2014-07-04 15:00', '2014-07-04 16:00', '2014-07-07 09:00',
  557. '2014-07-07 10:00', '2014-07-07 11:00', '2014-07-07 12:00',
  558. '2014-07-07 13:00', '2014-07-07 14:00', '2014-07-07 15:00',
  559. '2014-07-07 16:00', '2014-07-08 09:00', '2014-07-08 10:00',
  560. '2014-07-08 11:00', '2014-07-08 12:00', '2014-07-08 13:00',
  561. '2014-07-08 14:00', '2014-07-08 15:00', '2014-07-08 16:00'])
  562. assert idx.inferred_freq == 'BH'
  563. def test_not_monotonic(self):
  564. rng = _dti(['1/31/2000', '1/31/2001', '1/31/2002'])
  565. rng = rng[::-1]
  566. assert rng.inferred_freq == '-1A-JAN'
  567. def test_non_datetimeindex2(self):
  568. rng = _dti(['1/31/2000', '1/31/2001', '1/31/2002'])
  569. vals = rng.to_pydatetime()
  570. result = frequencies.infer_freq(vals)
  571. assert result == rng.inferred_freq
  572. def test_invalid_index_types(self):
  573. # test all index types
  574. for i in [tm.makeIntIndex(10), tm.makeFloatIndex(10),
  575. tm.makePeriodIndex(10)]:
  576. pytest.raises(TypeError, lambda: frequencies.infer_freq(i))
  577. # GH 10822
  578. # odd error message on conversions to datetime for unicode
  579. if not is_platform_windows():
  580. for i in [tm.makeStringIndex(10), tm.makeUnicodeIndex(10)]:
  581. pytest.raises(ValueError, lambda: frequencies.infer_freq(i))
  582. def test_string_datetimelike_compat(self):
  583. # GH 6463
  584. expected = frequencies.infer_freq(['2004-01', '2004-02', '2004-03',
  585. '2004-04'])
  586. result = frequencies.infer_freq(Index(['2004-01', '2004-02', '2004-03',
  587. '2004-04']))
  588. assert result == expected
  589. def test_series(self):
  590. # GH6407
  591. # inferring series
  592. # invalid type of Series
  593. for s in [Series(np.arange(10)), Series(np.arange(10.))]:
  594. pytest.raises(TypeError, lambda: frequencies.infer_freq(s))
  595. # a non-convertible string
  596. pytest.raises(ValueError, lambda: frequencies.infer_freq(
  597. Series(['foo', 'bar'])))
  598. # cannot infer on PeriodIndex
  599. for freq in [None, 'L']:
  600. s = Series(period_range('2013', periods=10, freq=freq))
  601. pytest.raises(TypeError, lambda: frequencies.infer_freq(s))
  602. # DateTimeIndex
  603. for freq in ['M', 'L', 'S']:
  604. s = Series(date_range('20130101', periods=10, freq=freq))
  605. inferred = frequencies.infer_freq(s)
  606. assert inferred == freq
  607. s = Series(date_range('20130101', '20130110'))
  608. inferred = frequencies.infer_freq(s)
  609. assert inferred == 'D'
  610. def test_legacy_offset_warnings(self):
  611. freqs = ['WEEKDAY', 'EOM', 'W@MON', 'W@TUE', 'W@WED', 'W@THU',
  612. 'W@FRI', 'W@SAT', 'W@SUN', 'Q@JAN', 'Q@FEB', 'Q@MAR',
  613. 'A@JAN', 'A@FEB', 'A@MAR', 'A@APR', 'A@MAY', 'A@JUN',
  614. 'A@JUL', 'A@AUG', 'A@SEP', 'A@OCT', 'A@NOV', 'A@DEC',
  615. 'Y@JAN', 'WOM@1MON', 'WOM@2MON', 'WOM@3MON',
  616. 'WOM@4MON', 'WOM@1TUE', 'WOM@2TUE', 'WOM@3TUE',
  617. 'WOM@4TUE', 'WOM@1WED', 'WOM@2WED', 'WOM@3WED',
  618. 'WOM@4WED', 'WOM@1THU', 'WOM@2THU', 'WOM@3THU',
  619. 'WOM@4THU', 'WOM@1FRI', 'WOM@2FRI', 'WOM@3FRI',
  620. 'WOM@4FRI']
  621. msg = INVALID_FREQ_ERR_MSG
  622. for freq in freqs:
  623. with pytest.raises(ValueError, match=msg):
  624. frequencies.get_offset(freq)
  625. with pytest.raises(ValueError, match=msg):
  626. date_range('2011-01-01', periods=5, freq=freq)