test_date_range.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. """
  2. test date_range, bdate_range construction from the convenience range functions
  3. """
  4. from datetime import datetime, time, timedelta
  5. import numpy as np
  6. import pytest
  7. import pytz
  8. from pytz import timezone
  9. import pandas.compat as compat
  10. from pandas.errors import OutOfBoundsDatetime
  11. import pandas.util._test_decorators as td
  12. import pandas as pd
  13. from pandas import DatetimeIndex, Timestamp, bdate_range, date_range, offsets
  14. from pandas.tests.series.common import TestData
  15. import pandas.util.testing as tm
  16. from pandas.tseries.offsets import (
  17. BDay, CDay, DateOffset, MonthEnd, generate_range, prefix_mapping)
  18. START, END = datetime(2009, 1, 1), datetime(2010, 1, 1)
  19. class TestTimestampEquivDateRange(object):
  20. # Older tests in TestTimeSeries constructed their `stamp` objects
  21. # using `date_range` instead of the `Timestamp` constructor.
  22. # TestTimestampEquivDateRange checks that these are equivalent in the
  23. # pertinent cases.
  24. def test_date_range_timestamp_equiv(self):
  25. rng = date_range('20090415', '20090519', tz='US/Eastern')
  26. stamp = rng[0]
  27. ts = Timestamp('20090415', tz='US/Eastern', freq='D')
  28. assert ts == stamp
  29. def test_date_range_timestamp_equiv_dateutil(self):
  30. rng = date_range('20090415', '20090519', tz='dateutil/US/Eastern')
  31. stamp = rng[0]
  32. ts = Timestamp('20090415', tz='dateutil/US/Eastern', freq='D')
  33. assert ts == stamp
  34. def test_date_range_timestamp_equiv_explicit_pytz(self):
  35. rng = date_range('20090415', '20090519',
  36. tz=pytz.timezone('US/Eastern'))
  37. stamp = rng[0]
  38. ts = Timestamp('20090415', tz=pytz.timezone('US/Eastern'), freq='D')
  39. assert ts == stamp
  40. @td.skip_if_windows_python_3
  41. def test_date_range_timestamp_equiv_explicit_dateutil(self):
  42. from pandas._libs.tslibs.timezones import dateutil_gettz as gettz
  43. rng = date_range('20090415', '20090519', tz=gettz('US/Eastern'))
  44. stamp = rng[0]
  45. ts = Timestamp('20090415', tz=gettz('US/Eastern'), freq='D')
  46. assert ts == stamp
  47. def test_date_range_timestamp_equiv_from_datetime_instance(self):
  48. datetime_instance = datetime(2014, 3, 4)
  49. # build a timestamp with a frequency, since then it supports
  50. # addition/subtraction of integers
  51. timestamp_instance = date_range(datetime_instance, periods=1,
  52. freq='D')[0]
  53. ts = Timestamp(datetime_instance, freq='D')
  54. assert ts == timestamp_instance
  55. def test_date_range_timestamp_equiv_preserve_frequency(self):
  56. timestamp_instance = date_range('2014-03-05', periods=1, freq='D')[0]
  57. ts = Timestamp('2014-03-05', freq='D')
  58. assert timestamp_instance == ts
  59. class TestDateRanges(TestData):
  60. def test_date_range_nat(self):
  61. # GH#11587
  62. msg = "Neither `start` nor `end` can be NaT"
  63. with pytest.raises(ValueError, match=msg):
  64. date_range(start='2016-01-01', end=pd.NaT, freq='D')
  65. with pytest.raises(ValueError, match=msg):
  66. date_range(start=pd.NaT, end='2016-01-01', freq='D')
  67. def test_date_range_multiplication_overflow(self):
  68. # GH#24255
  69. # check that overflows in calculating `addend = periods * stride`
  70. # are caught
  71. with tm.assert_produces_warning(None):
  72. # we should _not_ be seeing a overflow RuntimeWarning
  73. dti = date_range(start='1677-09-22', periods=213503, freq='D')
  74. assert dti[0] == Timestamp('1677-09-22')
  75. assert len(dti) == 213503
  76. msg = "Cannot generate range with"
  77. with pytest.raises(OutOfBoundsDatetime, match=msg):
  78. date_range('1969-05-04', periods=200000000, freq='30000D')
  79. def test_date_range_unsigned_overflow_handling(self):
  80. # GH#24255
  81. # case where `addend = periods * stride` overflows int64 bounds
  82. # but not uint64 bounds
  83. dti = date_range(start='1677-09-22', end='2262-04-11', freq='D')
  84. dti2 = date_range(start=dti[0], periods=len(dti), freq='D')
  85. assert dti2.equals(dti)
  86. dti3 = date_range(end=dti[-1], periods=len(dti), freq='D')
  87. assert dti3.equals(dti)
  88. def test_date_range_int64_overflow_non_recoverable(self):
  89. # GH#24255
  90. # case with start later than 1970-01-01, overflow int64 but not uint64
  91. msg = "Cannot generate range with"
  92. with pytest.raises(OutOfBoundsDatetime, match=msg):
  93. date_range(start='1970-02-01', periods=106752 * 24, freq='H')
  94. # case with end before 1970-01-01, overflow int64 but not uint64
  95. with pytest.raises(OutOfBoundsDatetime, match=msg):
  96. date_range(end='1969-11-14', periods=106752 * 24, freq='H')
  97. def test_date_range_int64_overflow_stride_endpoint_different_signs(self):
  98. # cases where stride * periods overflow int64 and stride/endpoint
  99. # have different signs
  100. start = Timestamp('2262-02-23')
  101. end = Timestamp('1969-11-14')
  102. expected = date_range(start=start, end=end, freq='-1H')
  103. assert expected[0] == start
  104. assert expected[-1] == end
  105. dti = date_range(end=end, periods=len(expected), freq='-1H')
  106. tm.assert_index_equal(dti, expected)
  107. start2 = Timestamp('1970-02-01')
  108. end2 = Timestamp('1677-10-22')
  109. expected2 = date_range(start=start2, end=end2, freq='-1H')
  110. assert expected2[0] == start2
  111. assert expected2[-1] == end2
  112. dti2 = date_range(start=start2, periods=len(expected2), freq='-1H')
  113. tm.assert_index_equal(dti2, expected2)
  114. def test_date_range_out_of_bounds(self):
  115. # GH#14187
  116. with pytest.raises(OutOfBoundsDatetime):
  117. date_range('2016-01-01', periods=100000, freq='D')
  118. with pytest.raises(OutOfBoundsDatetime):
  119. date_range(end='1763-10-12', periods=100000, freq='D')
  120. def test_date_range_gen_error(self):
  121. rng = date_range('1/1/2000 00:00', '1/1/2000 00:18', freq='5min')
  122. assert len(rng) == 4
  123. @pytest.mark.parametrize("freq", ["AS", "YS"])
  124. def test_begin_year_alias(self, freq):
  125. # see gh-9313
  126. rng = date_range("1/1/2013", "7/1/2017", freq=freq)
  127. exp = pd.DatetimeIndex(["2013-01-01", "2014-01-01",
  128. "2015-01-01", "2016-01-01",
  129. "2017-01-01"], freq=freq)
  130. tm.assert_index_equal(rng, exp)
  131. @pytest.mark.parametrize("freq", ["A", "Y"])
  132. def test_end_year_alias(self, freq):
  133. # see gh-9313
  134. rng = date_range("1/1/2013", "7/1/2017", freq=freq)
  135. exp = pd.DatetimeIndex(["2013-12-31", "2014-12-31",
  136. "2015-12-31", "2016-12-31"], freq=freq)
  137. tm.assert_index_equal(rng, exp)
  138. @pytest.mark.parametrize("freq", ["BA", "BY"])
  139. def test_business_end_year_alias(self, freq):
  140. # see gh-9313
  141. rng = date_range("1/1/2013", "7/1/2017", freq=freq)
  142. exp = pd.DatetimeIndex(["2013-12-31", "2014-12-31",
  143. "2015-12-31", "2016-12-30"], freq=freq)
  144. tm.assert_index_equal(rng, exp)
  145. def test_date_range_negative_freq(self):
  146. # GH 11018
  147. rng = date_range('2011-12-31', freq='-2A', periods=3)
  148. exp = pd.DatetimeIndex(['2011-12-31', '2009-12-31',
  149. '2007-12-31'], freq='-2A')
  150. tm.assert_index_equal(rng, exp)
  151. assert rng.freq == '-2A'
  152. rng = date_range('2011-01-31', freq='-2M', periods=3)
  153. exp = pd.DatetimeIndex(['2011-01-31', '2010-11-30',
  154. '2010-09-30'], freq='-2M')
  155. tm.assert_index_equal(rng, exp)
  156. assert rng.freq == '-2M'
  157. def test_date_range_bms_bug(self):
  158. # #1645
  159. rng = date_range('1/1/2000', periods=10, freq='BMS')
  160. ex_first = Timestamp('2000-01-03')
  161. assert rng[0] == ex_first
  162. def test_date_range_normalize(self):
  163. snap = datetime.today()
  164. n = 50
  165. rng = date_range(snap, periods=n, normalize=False, freq='2D')
  166. offset = timedelta(2)
  167. values = DatetimeIndex([snap + i * offset for i in range(n)])
  168. tm.assert_index_equal(rng, values)
  169. rng = date_range('1/1/2000 08:15', periods=n, normalize=False,
  170. freq='B')
  171. the_time = time(8, 15)
  172. for val in rng:
  173. assert val.time() == the_time
  174. def test_date_range_fy5252(self):
  175. dr = date_range(start="2013-01-01", periods=2, freq=offsets.FY5253(
  176. startingMonth=1, weekday=3, variation="nearest"))
  177. assert dr[0] == Timestamp('2013-01-31')
  178. assert dr[1] == Timestamp('2014-01-30')
  179. def test_date_range_ambiguous_arguments(self):
  180. # #2538
  181. start = datetime(2011, 1, 1, 5, 3, 40)
  182. end = datetime(2011, 1, 1, 8, 9, 40)
  183. msg = ('Of the four parameters: start, end, periods, and '
  184. 'freq, exactly three must be specified')
  185. with pytest.raises(ValueError, match=msg):
  186. date_range(start, end, periods=10, freq='s')
  187. def test_date_range_convenience_periods(self):
  188. # GH 20808
  189. result = date_range('2018-04-24', '2018-04-27', periods=3)
  190. expected = DatetimeIndex(['2018-04-24 00:00:00',
  191. '2018-04-25 12:00:00',
  192. '2018-04-27 00:00:00'], freq=None)
  193. tm.assert_index_equal(result, expected)
  194. # Test if spacing remains linear if tz changes to dst in range
  195. result = date_range('2018-04-01 01:00:00',
  196. '2018-04-01 04:00:00',
  197. tz='Australia/Sydney',
  198. periods=3)
  199. expected = DatetimeIndex([Timestamp('2018-04-01 01:00:00+1100',
  200. tz='Australia/Sydney'),
  201. Timestamp('2018-04-01 02:00:00+1000',
  202. tz='Australia/Sydney'),
  203. Timestamp('2018-04-01 04:00:00+1000',
  204. tz='Australia/Sydney')])
  205. tm.assert_index_equal(result, expected)
  206. @pytest.mark.parametrize('start,end,result_tz', [
  207. ['20180101', '20180103', 'US/Eastern'],
  208. [datetime(2018, 1, 1), datetime(2018, 1, 3), 'US/Eastern'],
  209. [Timestamp('20180101'), Timestamp('20180103'), 'US/Eastern'],
  210. [Timestamp('20180101', tz='US/Eastern'),
  211. Timestamp('20180103', tz='US/Eastern'), 'US/Eastern'],
  212. [Timestamp('20180101', tz='US/Eastern'),
  213. Timestamp('20180103', tz='US/Eastern'), None]])
  214. def test_date_range_linspacing_tz(self, start, end, result_tz):
  215. # GH 20983
  216. result = date_range(start, end, periods=3, tz=result_tz)
  217. expected = date_range('20180101', periods=3, freq='D', tz='US/Eastern')
  218. tm.assert_index_equal(result, expected)
  219. def test_date_range_businesshour(self):
  220. idx = DatetimeIndex(['2014-07-04 09:00', '2014-07-04 10:00',
  221. '2014-07-04 11:00',
  222. '2014-07-04 12:00', '2014-07-04 13:00',
  223. '2014-07-04 14:00',
  224. '2014-07-04 15:00', '2014-07-04 16:00'],
  225. freq='BH')
  226. rng = date_range('2014-07-04 09:00', '2014-07-04 16:00', freq='BH')
  227. tm.assert_index_equal(idx, rng)
  228. idx = DatetimeIndex(
  229. ['2014-07-04 16:00', '2014-07-07 09:00'], freq='BH')
  230. rng = date_range('2014-07-04 16:00', '2014-07-07 09:00', freq='BH')
  231. tm.assert_index_equal(idx, rng)
  232. idx = DatetimeIndex(['2014-07-04 09:00', '2014-07-04 10:00',
  233. '2014-07-04 11:00',
  234. '2014-07-04 12:00', '2014-07-04 13:00',
  235. '2014-07-04 14:00',
  236. '2014-07-04 15:00', '2014-07-04 16:00',
  237. '2014-07-07 09:00', '2014-07-07 10:00',
  238. '2014-07-07 11:00',
  239. '2014-07-07 12:00', '2014-07-07 13:00',
  240. '2014-07-07 14:00',
  241. '2014-07-07 15:00', '2014-07-07 16:00',
  242. '2014-07-08 09:00', '2014-07-08 10:00',
  243. '2014-07-08 11:00',
  244. '2014-07-08 12:00', '2014-07-08 13:00',
  245. '2014-07-08 14:00',
  246. '2014-07-08 15:00', '2014-07-08 16:00'],
  247. freq='BH')
  248. rng = date_range('2014-07-04 09:00', '2014-07-08 16:00', freq='BH')
  249. tm.assert_index_equal(idx, rng)
  250. def test_range_misspecified(self):
  251. # GH #1095
  252. msg = ('Of the four parameters: start, end, periods, and '
  253. 'freq, exactly three must be specified')
  254. with pytest.raises(ValueError, match=msg):
  255. date_range(start='1/1/2000')
  256. with pytest.raises(ValueError, match=msg):
  257. date_range(end='1/1/2000')
  258. with pytest.raises(ValueError, match=msg):
  259. date_range(periods=10)
  260. with pytest.raises(ValueError, match=msg):
  261. date_range(start='1/1/2000', freq='H')
  262. with pytest.raises(ValueError, match=msg):
  263. date_range(end='1/1/2000', freq='H')
  264. with pytest.raises(ValueError, match=msg):
  265. date_range(periods=10, freq='H')
  266. with pytest.raises(ValueError, match=msg):
  267. date_range()
  268. @pytest.mark.parametrize('f', [compat.long, int])
  269. def test_compat_replace(self, f):
  270. # https://github.com/statsmodels/statsmodels/issues/3349
  271. # replace should take ints/longs for compat
  272. result = date_range(Timestamp('1960-04-01 00:00:00', freq='QS-JAN'),
  273. periods=f(76), freq='QS-JAN')
  274. assert len(result) == 76
  275. def test_catch_infinite_loop(self):
  276. offset = offsets.DateOffset(minute=5)
  277. # blow up, don't loop forever
  278. pytest.raises(Exception, date_range, datetime(2011, 11, 11),
  279. datetime(2011, 11, 12), freq=offset)
  280. @pytest.mark.parametrize('periods', (1, 2))
  281. def test_wom_len(self, periods):
  282. # https://github.com/pandas-dev/pandas/issues/20517
  283. res = date_range(start='20110101', periods=periods, freq='WOM-1MON')
  284. assert len(res) == periods
  285. def test_construct_over_dst(self):
  286. # GH 20854
  287. pre_dst = Timestamp('2010-11-07 01:00:00').tz_localize('US/Pacific',
  288. ambiguous=True)
  289. pst_dst = Timestamp('2010-11-07 01:00:00').tz_localize('US/Pacific',
  290. ambiguous=False)
  291. expect_data = [Timestamp('2010-11-07 00:00:00', tz='US/Pacific'),
  292. pre_dst,
  293. pst_dst]
  294. expected = DatetimeIndex(expect_data)
  295. result = date_range(start='2010-11-7', periods=3,
  296. freq='H', tz='US/Pacific')
  297. tm.assert_index_equal(result, expected)
  298. def test_construct_with_different_start_end_string_format(self):
  299. # GH 12064
  300. result = date_range('2013-01-01 00:00:00+09:00',
  301. '2013/01/01 02:00:00+09:00', freq='H')
  302. expected = DatetimeIndex([Timestamp('2013-01-01 00:00:00+09:00'),
  303. Timestamp('2013-01-01 01:00:00+09:00'),
  304. Timestamp('2013-01-01 02:00:00+09:00')])
  305. tm.assert_index_equal(result, expected)
  306. def test_error_with_zero_monthends(self):
  307. msg = r'Offset <0 \* MonthEnds> did not increment date'
  308. with pytest.raises(ValueError, match=msg):
  309. date_range('1/1/2000', '1/1/2001', freq=MonthEnd(0))
  310. def test_range_bug(self):
  311. # GH #770
  312. offset = DateOffset(months=3)
  313. result = date_range("2011-1-1", "2012-1-31", freq=offset)
  314. start = datetime(2011, 1, 1)
  315. expected = DatetimeIndex([start + i * offset for i in range(5)])
  316. tm.assert_index_equal(result, expected)
  317. def test_range_tz_pytz(self):
  318. # see gh-2906
  319. tz = timezone('US/Eastern')
  320. start = tz.localize(datetime(2011, 1, 1))
  321. end = tz.localize(datetime(2011, 1, 3))
  322. dr = date_range(start=start, periods=3)
  323. assert dr.tz.zone == tz.zone
  324. assert dr[0] == start
  325. assert dr[2] == end
  326. dr = date_range(end=end, periods=3)
  327. assert dr.tz.zone == tz.zone
  328. assert dr[0] == start
  329. assert dr[2] == end
  330. dr = date_range(start=start, end=end)
  331. assert dr.tz.zone == tz.zone
  332. assert dr[0] == start
  333. assert dr[2] == end
  334. @pytest.mark.parametrize('start, end', [
  335. [Timestamp(datetime(2014, 3, 6), tz='US/Eastern'),
  336. Timestamp(datetime(2014, 3, 12), tz='US/Eastern')],
  337. [Timestamp(datetime(2013, 11, 1), tz='US/Eastern'),
  338. Timestamp(datetime(2013, 11, 6), tz='US/Eastern')]
  339. ])
  340. def test_range_tz_dst_straddle_pytz(self, start, end):
  341. dr = date_range(start, end, freq='D')
  342. assert dr[0] == start
  343. assert dr[-1] == end
  344. assert np.all(dr.hour == 0)
  345. dr = date_range(start, end, freq='D', tz='US/Eastern')
  346. assert dr[0] == start
  347. assert dr[-1] == end
  348. assert np.all(dr.hour == 0)
  349. dr = date_range(start.replace(tzinfo=None), end.replace(
  350. tzinfo=None), freq='D', tz='US/Eastern')
  351. assert dr[0] == start
  352. assert dr[-1] == end
  353. assert np.all(dr.hour == 0)
  354. def test_range_tz_dateutil(self):
  355. # see gh-2906
  356. # Use maybe_get_tz to fix filename in tz under dateutil.
  357. from pandas._libs.tslibs.timezones import maybe_get_tz
  358. tz = lambda x: maybe_get_tz('dateutil/' + x)
  359. start = datetime(2011, 1, 1, tzinfo=tz('US/Eastern'))
  360. end = datetime(2011, 1, 3, tzinfo=tz('US/Eastern'))
  361. dr = date_range(start=start, periods=3)
  362. assert dr.tz == tz('US/Eastern')
  363. assert dr[0] == start
  364. assert dr[2] == end
  365. dr = date_range(end=end, periods=3)
  366. assert dr.tz == tz('US/Eastern')
  367. assert dr[0] == start
  368. assert dr[2] == end
  369. dr = date_range(start=start, end=end)
  370. assert dr.tz == tz('US/Eastern')
  371. assert dr[0] == start
  372. assert dr[2] == end
  373. @pytest.mark.parametrize('freq', ["1D", "3D", "2M", "7W", "3H", "A"])
  374. def test_range_closed(self, freq):
  375. begin = datetime(2011, 1, 1)
  376. end = datetime(2014, 1, 1)
  377. closed = date_range(begin, end, closed=None, freq=freq)
  378. left = date_range(begin, end, closed="left", freq=freq)
  379. right = date_range(begin, end, closed="right", freq=freq)
  380. expected_left = left
  381. expected_right = right
  382. if end == closed[-1]:
  383. expected_left = closed[:-1]
  384. if begin == closed[0]:
  385. expected_right = closed[1:]
  386. tm.assert_index_equal(expected_left, left)
  387. tm.assert_index_equal(expected_right, right)
  388. def test_range_closed_with_tz_aware_start_end(self):
  389. # GH12409, GH12684
  390. begin = Timestamp('2011/1/1', tz='US/Eastern')
  391. end = Timestamp('2014/1/1', tz='US/Eastern')
  392. for freq in ["1D", "3D", "2M", "7W", "3H", "A"]:
  393. closed = date_range(begin, end, closed=None, freq=freq)
  394. left = date_range(begin, end, closed="left", freq=freq)
  395. right = date_range(begin, end, closed="right", freq=freq)
  396. expected_left = left
  397. expected_right = right
  398. if end == closed[-1]:
  399. expected_left = closed[:-1]
  400. if begin == closed[0]:
  401. expected_right = closed[1:]
  402. tm.assert_index_equal(expected_left, left)
  403. tm.assert_index_equal(expected_right, right)
  404. begin = Timestamp('2011/1/1')
  405. end = Timestamp('2014/1/1')
  406. begintz = Timestamp('2011/1/1', tz='US/Eastern')
  407. endtz = Timestamp('2014/1/1', tz='US/Eastern')
  408. for freq in ["1D", "3D", "2M", "7W", "3H", "A"]:
  409. closed = date_range(begin, end, closed=None, freq=freq,
  410. tz='US/Eastern')
  411. left = date_range(begin, end, closed="left", freq=freq,
  412. tz='US/Eastern')
  413. right = date_range(begin, end, closed="right", freq=freq,
  414. tz='US/Eastern')
  415. expected_left = left
  416. expected_right = right
  417. if endtz == closed[-1]:
  418. expected_left = closed[:-1]
  419. if begintz == closed[0]:
  420. expected_right = closed[1:]
  421. tm.assert_index_equal(expected_left, left)
  422. tm.assert_index_equal(expected_right, right)
  423. @pytest.mark.parametrize('closed', ['right', 'left', None])
  424. def test_range_closed_boundary(self, closed):
  425. # GH#11804
  426. right_boundary = date_range('2015-09-12', '2015-12-01',
  427. freq='QS-MAR', closed=closed)
  428. left_boundary = date_range('2015-09-01', '2015-09-12',
  429. freq='QS-MAR', closed=closed)
  430. both_boundary = date_range('2015-09-01', '2015-12-01',
  431. freq='QS-MAR', closed=closed)
  432. expected_right = expected_left = expected_both = both_boundary
  433. if closed == 'right':
  434. expected_left = both_boundary[1:]
  435. if closed == 'left':
  436. expected_right = both_boundary[:-1]
  437. if closed is None:
  438. expected_right = both_boundary[1:]
  439. expected_left = both_boundary[:-1]
  440. tm.assert_index_equal(right_boundary, expected_right)
  441. tm.assert_index_equal(left_boundary, expected_left)
  442. tm.assert_index_equal(both_boundary, expected_both)
  443. def test_years_only(self):
  444. # GH 6961
  445. dr = date_range('2014', '2015', freq='M')
  446. assert dr[0] == datetime(2014, 1, 31)
  447. assert dr[-1] == datetime(2014, 12, 31)
  448. def test_freq_divides_end_in_nanos(self):
  449. # GH 10885
  450. result_1 = date_range('2005-01-12 10:00', '2005-01-12 16:00',
  451. freq='345min')
  452. result_2 = date_range('2005-01-13 10:00', '2005-01-13 16:00',
  453. freq='345min')
  454. expected_1 = DatetimeIndex(['2005-01-12 10:00:00',
  455. '2005-01-12 15:45:00'],
  456. dtype='datetime64[ns]', freq='345T',
  457. tz=None)
  458. expected_2 = DatetimeIndex(['2005-01-13 10:00:00',
  459. '2005-01-13 15:45:00'],
  460. dtype='datetime64[ns]', freq='345T',
  461. tz=None)
  462. tm.assert_index_equal(result_1, expected_1)
  463. tm.assert_index_equal(result_2, expected_2)
  464. def test_cached_range_bug(self):
  465. rng = date_range('2010-09-01 05:00:00', periods=50,
  466. freq=DateOffset(hours=6))
  467. assert len(rng) == 50
  468. assert rng[0] == datetime(2010, 9, 1, 5)
  469. def test_timezone_comparaison_bug(self):
  470. # smoke test
  471. start = Timestamp('20130220 10:00', tz='US/Eastern')
  472. result = date_range(start, periods=2, tz='US/Eastern')
  473. assert len(result) == 2
  474. def test_timezone_comparaison_assert(self):
  475. start = Timestamp('20130220 10:00', tz='US/Eastern')
  476. msg = 'Inferred time zone not equal to passed time zone'
  477. with pytest.raises(AssertionError, match=msg):
  478. date_range(start, periods=2, tz='Europe/Berlin')
  479. def test_negative_non_tick_frequency_descending_dates(self,
  480. tz_aware_fixture):
  481. # GH 23270
  482. tz = tz_aware_fixture
  483. result = pd.date_range(start='2011-06-01', end='2011-01-01',
  484. freq='-1MS', tz=tz)
  485. expected = pd.date_range(end='2011-06-01', start='2011-01-01',
  486. freq='1MS', tz=tz)[::-1]
  487. tm.assert_index_equal(result, expected)
  488. class TestGenRangeGeneration(object):
  489. def test_generate(self):
  490. rng1 = list(generate_range(START, END, offset=BDay()))
  491. rng2 = list(generate_range(START, END, offset='B'))
  492. assert rng1 == rng2
  493. def test_generate_cday(self):
  494. rng1 = list(generate_range(START, END, offset=CDay()))
  495. rng2 = list(generate_range(START, END, offset='C'))
  496. assert rng1 == rng2
  497. def test_1(self):
  498. rng = list(generate_range(start=datetime(2009, 3, 25), periods=2))
  499. expected = [datetime(2009, 3, 25), datetime(2009, 3, 26)]
  500. assert rng == expected
  501. def test_2(self):
  502. rng = list(generate_range(start=datetime(2008, 1, 1),
  503. end=datetime(2008, 1, 3)))
  504. expected = [datetime(2008, 1, 1),
  505. datetime(2008, 1, 2),
  506. datetime(2008, 1, 3)]
  507. assert rng == expected
  508. def test_3(self):
  509. rng = list(generate_range(start=datetime(2008, 1, 5),
  510. end=datetime(2008, 1, 6)))
  511. expected = []
  512. assert rng == expected
  513. def test_precision_finer_than_offset(self):
  514. # GH#9907
  515. result1 = pd.date_range(start='2015-04-15 00:00:03',
  516. end='2016-04-22 00:00:00', freq='Q')
  517. result2 = pd.date_range(start='2015-04-15 00:00:03',
  518. end='2015-06-22 00:00:04', freq='W')
  519. expected1_list = ['2015-06-30 00:00:03', '2015-09-30 00:00:03',
  520. '2015-12-31 00:00:03', '2016-03-31 00:00:03']
  521. expected2_list = ['2015-04-19 00:00:03', '2015-04-26 00:00:03',
  522. '2015-05-03 00:00:03', '2015-05-10 00:00:03',
  523. '2015-05-17 00:00:03', '2015-05-24 00:00:03',
  524. '2015-05-31 00:00:03', '2015-06-07 00:00:03',
  525. '2015-06-14 00:00:03', '2015-06-21 00:00:03']
  526. expected1 = DatetimeIndex(expected1_list, dtype='datetime64[ns]',
  527. freq='Q-DEC', tz=None)
  528. expected2 = DatetimeIndex(expected2_list, dtype='datetime64[ns]',
  529. freq='W-SUN', tz=None)
  530. tm.assert_index_equal(result1, expected1)
  531. tm.assert_index_equal(result2, expected2)
  532. dt1, dt2 = '2017-01-01', '2017-01-01'
  533. tz1, tz2 = 'US/Eastern', 'Europe/London'
  534. @pytest.mark.parametrize("start,end", [
  535. (pd.Timestamp(dt1, tz=tz1), pd.Timestamp(dt2)),
  536. (pd.Timestamp(dt1), pd.Timestamp(dt2, tz=tz2)),
  537. (pd.Timestamp(dt1, tz=tz1), pd.Timestamp(dt2, tz=tz2)),
  538. (pd.Timestamp(dt1, tz=tz2), pd.Timestamp(dt2, tz=tz1))
  539. ])
  540. def test_mismatching_tz_raises_err(self, start, end):
  541. # issue 18488
  542. with pytest.raises(TypeError):
  543. pd.date_range(start, end)
  544. with pytest.raises(TypeError):
  545. pd.date_range(start, end, freq=BDay())
  546. class TestBusinessDateRange(object):
  547. def test_constructor(self):
  548. bdate_range(START, END, freq=BDay())
  549. bdate_range(START, periods=20, freq=BDay())
  550. bdate_range(end=START, periods=20, freq=BDay())
  551. msg = 'periods must be a number, got B'
  552. with pytest.raises(TypeError, match=msg):
  553. date_range('2011-1-1', '2012-1-1', 'B')
  554. with pytest.raises(TypeError, match=msg):
  555. bdate_range('2011-1-1', '2012-1-1', 'B')
  556. msg = 'freq must be specified for bdate_range; use date_range instead'
  557. with pytest.raises(TypeError, match=msg):
  558. bdate_range(START, END, periods=10, freq=None)
  559. def test_naive_aware_conflicts(self):
  560. naive = bdate_range(START, END, freq=BDay(), tz=None)
  561. aware = bdate_range(START, END, freq=BDay(), tz="Asia/Hong_Kong")
  562. msg = 'tz-naive.*tz-aware'
  563. with pytest.raises(TypeError, match=msg):
  564. naive.join(aware)
  565. with pytest.raises(TypeError, match=msg):
  566. aware.join(naive)
  567. def test_misc(self):
  568. end = datetime(2009, 5, 13)
  569. dr = bdate_range(end=end, periods=20)
  570. firstDate = end - 19 * BDay()
  571. assert len(dr) == 20
  572. assert dr[0] == firstDate
  573. assert dr[-1] == end
  574. def test_date_parse_failure(self):
  575. badly_formed_date = '2007/100/1'
  576. with pytest.raises(ValueError):
  577. Timestamp(badly_formed_date)
  578. with pytest.raises(ValueError):
  579. bdate_range(start=badly_formed_date, periods=10)
  580. with pytest.raises(ValueError):
  581. bdate_range(end=badly_formed_date, periods=10)
  582. with pytest.raises(ValueError):
  583. bdate_range(badly_formed_date, badly_formed_date)
  584. def test_daterange_bug_456(self):
  585. # GH #456
  586. rng1 = bdate_range('12/5/2011', '12/5/2011')
  587. rng2 = bdate_range('12/2/2011', '12/5/2011')
  588. rng2.freq = BDay()
  589. result = rng1.union(rng2)
  590. assert isinstance(result, DatetimeIndex)
  591. @pytest.mark.parametrize('closed', ['left', 'right'])
  592. def test_bdays_and_open_boundaries(self, closed):
  593. # GH 6673
  594. start = '2018-07-21' # Saturday
  595. end = '2018-07-29' # Sunday
  596. result = pd.date_range(start, end, freq='B', closed=closed)
  597. bday_start = '2018-07-23' # Monday
  598. bday_end = '2018-07-27' # Friday
  599. expected = pd.date_range(bday_start, bday_end, freq='D')
  600. tm.assert_index_equal(result, expected)
  601. class TestCustomDateRange(object):
  602. def test_constructor(self):
  603. bdate_range(START, END, freq=CDay())
  604. bdate_range(START, periods=20, freq=CDay())
  605. bdate_range(end=START, periods=20, freq=CDay())
  606. msg = 'periods must be a number, got C'
  607. with pytest.raises(TypeError, match=msg):
  608. date_range('2011-1-1', '2012-1-1', 'C')
  609. with pytest.raises(TypeError, match=msg):
  610. bdate_range('2011-1-1', '2012-1-1', 'C')
  611. def test_misc(self):
  612. end = datetime(2009, 5, 13)
  613. dr = bdate_range(end=end, periods=20, freq='C')
  614. firstDate = end - 19 * CDay()
  615. assert len(dr) == 20
  616. assert dr[0] == firstDate
  617. assert dr[-1] == end
  618. def test_daterange_bug_456(self):
  619. # GH #456
  620. rng1 = bdate_range('12/5/2011', '12/5/2011', freq='C')
  621. rng2 = bdate_range('12/2/2011', '12/5/2011', freq='C')
  622. rng2.freq = CDay()
  623. result = rng1.union(rng2)
  624. assert isinstance(result, DatetimeIndex)
  625. def test_cdaterange(self):
  626. result = bdate_range('2013-05-01', periods=3, freq='C')
  627. expected = DatetimeIndex(['2013-05-01', '2013-05-02', '2013-05-03'])
  628. tm.assert_index_equal(result, expected)
  629. def test_cdaterange_weekmask(self):
  630. result = bdate_range('2013-05-01', periods=3, freq='C',
  631. weekmask='Sun Mon Tue Wed Thu')
  632. expected = DatetimeIndex(['2013-05-01', '2013-05-02', '2013-05-05'])
  633. tm.assert_index_equal(result, expected)
  634. # raise with non-custom freq
  635. msg = ('a custom frequency string is required when holidays or '
  636. 'weekmask are passed, got frequency B')
  637. with pytest.raises(ValueError, match=msg):
  638. bdate_range('2013-05-01', periods=3,
  639. weekmask='Sun Mon Tue Wed Thu')
  640. def test_cdaterange_holidays(self):
  641. result = bdate_range('2013-05-01', periods=3, freq='C',
  642. holidays=['2013-05-01'])
  643. expected = DatetimeIndex(['2013-05-02', '2013-05-03', '2013-05-06'])
  644. tm.assert_index_equal(result, expected)
  645. # raise with non-custom freq
  646. msg = ('a custom frequency string is required when holidays or '
  647. 'weekmask are passed, got frequency B')
  648. with pytest.raises(ValueError, match=msg):
  649. bdate_range('2013-05-01', periods=3, holidays=['2013-05-01'])
  650. def test_cdaterange_weekmask_and_holidays(self):
  651. result = bdate_range('2013-05-01', periods=3, freq='C',
  652. weekmask='Sun Mon Tue Wed Thu',
  653. holidays=['2013-05-01'])
  654. expected = DatetimeIndex(['2013-05-02', '2013-05-05', '2013-05-06'])
  655. tm.assert_index_equal(result, expected)
  656. # raise with non-custom freq
  657. msg = ('a custom frequency string is required when holidays or '
  658. 'weekmask are passed, got frequency B')
  659. with pytest.raises(ValueError, match=msg):
  660. bdate_range('2013-05-01', periods=3,
  661. weekmask='Sun Mon Tue Wed Thu',
  662. holidays=['2013-05-01'])
  663. @pytest.mark.parametrize('freq', [freq for freq in prefix_mapping
  664. if freq.startswith('C')])
  665. def test_all_custom_freq(self, freq):
  666. # should not raise
  667. bdate_range(START, END, freq=freq, weekmask='Mon Wed Fri',
  668. holidays=['2009-03-14'])
  669. bad_freq = freq + 'FOO'
  670. msg = 'invalid custom frequency string: {freq}'
  671. with pytest.raises(ValueError, match=msg.format(freq=bad_freq)):
  672. bdate_range(START, END, freq=bad_freq)
  673. @pytest.mark.parametrize('start_end', [
  674. ('2018-01-01T00:00:01.000Z', '2018-01-03T00:00:01.000Z'),
  675. ('2018-01-01T00:00:00.010Z', '2018-01-03T00:00:00.010Z'),
  676. ('2001-01-01T00:00:00.010Z', '2001-01-03T00:00:00.010Z')])
  677. def test_range_with_millisecond_resolution(self, start_end):
  678. # https://github.com/pandas-dev/pandas/issues/24110
  679. start, end = start_end
  680. result = pd.date_range(start=start, end=end, periods=2, closed='left')
  681. expected = DatetimeIndex([start])
  682. tm.assert_index_equal(result, expected)