test_dtr.py 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  1. """
  2. .. codeauthor:: Tsuyoshi Hombashi <tsuyoshi.hombashi@gmail.com>
  3. """
  4. from copy import deepcopy
  5. from datetime import date, datetime, timedelta
  6. import pytest
  7. import pytz
  8. from dateutil.parser import parse
  9. from dateutil.relativedelta import relativedelta
  10. from datetimerange import DateTimeRange
  11. TIMEZONE = "+0900"
  12. START_DATETIME_TEXT = "2015-03-22T10:00:00" + TIMEZONE
  13. END_DATETIME_TEXT = "2015-03-22T10:10:00" + TIMEZONE
  14. TEST_START_DATETIME = parse(START_DATETIME_TEXT)
  15. TEST_END_DATETIME = parse(END_DATETIME_TEXT)
  16. ISO_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S%z"
  17. def setup_module(module):
  18. import locale
  19. locale.setlocale(locale.LC_ALL, ("C", "ascii"))
  20. @pytest.fixture
  21. def datetimerange_normal():
  22. value = DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME)
  23. value.start_time_format = ISO_TIME_FORMAT
  24. value.end_time_format = ISO_TIME_FORMAT
  25. return value
  26. @pytest.fixture
  27. def datetimerange_inversion():
  28. value = DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME)
  29. value.start_time_format = ISO_TIME_FORMAT
  30. value.end_time_format = ISO_TIME_FORMAT
  31. return value
  32. @pytest.fixture
  33. def datetimerange_null():
  34. value = DateTimeRange(None, None)
  35. value.time_format = None
  36. value.end_time_format = None
  37. return value
  38. @pytest.fixture
  39. def datetimerange_null_start():
  40. value = DateTimeRange(None, TEST_END_DATETIME)
  41. value.time_format = None
  42. value.end_time_format = ISO_TIME_FORMAT
  43. return value
  44. class TestDateTimeRange_repr:
  45. @pytest.mark.parametrize(
  46. ["start", "start_format", "end", "end_format", "separator", "is_output_elapse", "expected"],
  47. [
  48. [
  49. TEST_START_DATETIME,
  50. ISO_TIME_FORMAT,
  51. TEST_END_DATETIME,
  52. ISO_TIME_FORMAT,
  53. " - ",
  54. False,
  55. "2015-03-22T10:00:00+0900 - 2015-03-22T10:10:00+0900",
  56. ],
  57. [
  58. "2015-03-22T09:00:00+0900",
  59. ISO_TIME_FORMAT,
  60. "2015-03-22T10:10:00+0900",
  61. ISO_TIME_FORMAT,
  62. " - ",
  63. False,
  64. "2015-03-22T09:00:00+0900 - 2015-03-22T10:10:00+0900",
  65. ],
  66. [
  67. "2015-03-22T09:00:00",
  68. ISO_TIME_FORMAT,
  69. "2015-03-22T10:10:00",
  70. ISO_TIME_FORMAT,
  71. " - ",
  72. False,
  73. "2015-03-22T09:00:00 - 2015-03-22T10:10:00",
  74. ],
  75. [
  76. TEST_START_DATETIME,
  77. ISO_TIME_FORMAT,
  78. TEST_END_DATETIME,
  79. ISO_TIME_FORMAT,
  80. " - ",
  81. True,
  82. "2015-03-22T10:00:00+0900 - 2015-03-22T10:10:00+0900 (0:10:00)",
  83. ],
  84. [
  85. TEST_END_DATETIME,
  86. ISO_TIME_FORMAT,
  87. TEST_START_DATETIME,
  88. ISO_TIME_FORMAT,
  89. " - ",
  90. True,
  91. "2015-03-22T10:10:00+0900 - 2015-03-22T10:00:00+0900 (-1 day, 23:50:00)",
  92. ],
  93. [
  94. TEST_START_DATETIME,
  95. "%Y%m%d%H%M%S",
  96. TEST_END_DATETIME,
  97. "%Y/%m/%d %H:%M:%S%z",
  98. " to ",
  99. False,
  100. "20150322100000 to 2015/03/22 10:10:00+0900",
  101. ],
  102. [
  103. None,
  104. ISO_TIME_FORMAT,
  105. TEST_END_DATETIME,
  106. ISO_TIME_FORMAT,
  107. " - ",
  108. False,
  109. "NaT - 2015-03-22T10:10:00+0900",
  110. ],
  111. [
  112. TEST_START_DATETIME,
  113. ISO_TIME_FORMAT,
  114. None,
  115. ISO_TIME_FORMAT,
  116. " - ",
  117. False,
  118. "2015-03-22T10:00:00+0900 - NaT",
  119. ],
  120. [
  121. "2015-03-22",
  122. "%Y-%m-%d",
  123. "2015-04-22",
  124. "%Y-%m-%d",
  125. " - ",
  126. False,
  127. "2015-03-22 - 2015-04-22",
  128. ],
  129. [
  130. date(2015, 3, 22),
  131. "%Y-%m-%d",
  132. date(2015, 4, 22),
  133. "%Y-%m-%d",
  134. " - ",
  135. False,
  136. "2015-03-22 - 2015-04-22",
  137. ],
  138. ["01:23:45", "%H:%M:%S", "11:23:45", "%H:%M:%S", " - ", False, "01:23:45 - 11:23:45"],
  139. [None, ISO_TIME_FORMAT, None, ISO_TIME_FORMAT, " - ", False, "NaT - NaT"],
  140. ],
  141. )
  142. def test_normal(
  143. self, start, start_format, end, end_format, separator, is_output_elapse, expected
  144. ):
  145. dtr = DateTimeRange(start, end, start_format, end_format)
  146. dtr.separator = separator
  147. dtr.is_output_elapse = is_output_elapse
  148. assert str(dtr) == expected
  149. @pytest.mark.parametrize(
  150. ["start", "start_format", "end", "end_format", "expected"],
  151. [
  152. [
  153. "2015-03-08T00:00:00-0400",
  154. ISO_TIME_FORMAT,
  155. "2015-03-08T12:00:00-0400",
  156. ISO_TIME_FORMAT,
  157. "2015-03-08T00:00:00-0400 - 2015-03-08T12:00:00-0300",
  158. ],
  159. [
  160. "2015-11-01T00:00:00-0400",
  161. ISO_TIME_FORMAT,
  162. "2015-11-01T12:00:00-0400",
  163. ISO_TIME_FORMAT,
  164. "2015-11-01T00:00:00-0300 - 2015-11-01T12:00:00-0400",
  165. ],
  166. ],
  167. )
  168. def test_daylight_saving_time(self, start, start_format, end, end_format, expected):
  169. dtr = DateTimeRange(start, end, start_format, end_format)
  170. assert str(dtr) == expected
  171. @pytest.mark.parametrize(
  172. ["start", "start_format", "end", "end_format", "separator", "is_output_elapse", "expected"],
  173. [
  174. [
  175. TEST_START_DATETIME,
  176. None,
  177. TEST_END_DATETIME,
  178. ISO_TIME_FORMAT,
  179. " - ",
  180. False,
  181. TypeError,
  182. ],
  183. [
  184. TEST_START_DATETIME,
  185. ISO_TIME_FORMAT,
  186. TEST_END_DATETIME,
  187. None,
  188. " - ",
  189. False,
  190. TypeError,
  191. ],
  192. [
  193. TEST_START_DATETIME,
  194. ISO_TIME_FORMAT,
  195. TEST_END_DATETIME,
  196. ISO_TIME_FORMAT,
  197. None,
  198. False,
  199. AttributeError,
  200. ],
  201. ],
  202. )
  203. def test_exception(
  204. self, start, start_format, end, end_format, separator, is_output_elapse, expected
  205. ):
  206. dtr = DateTimeRange(start, end, start_format, end_format)
  207. dtr.separator = separator
  208. dtr.is_output_elapse = is_output_elapse
  209. with pytest.raises(expected):
  210. str(dtr)
  211. class TestDateTimeRange_eq:
  212. @pytest.mark.parametrize(
  213. ["lhs", "rhs", "expected"],
  214. [
  215. [DateTimeRange(None, None), DateTimeRange(None, None), True],
  216. [
  217. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  218. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  219. True,
  220. ],
  221. [
  222. DateTimeRange("2015-03-22T10:00:00", "2015-03-22T10:10:00"),
  223. DateTimeRange("2015-03-22T10:00:00", "2015-03-22T10:10:00"),
  224. True,
  225. ],
  226. [
  227. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  228. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:20:00+0900"),
  229. False,
  230. ],
  231. [
  232. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  233. DateTimeRange("2015-03-22T10:02:00+0900", "2015-03-22T10:10:00+0900"),
  234. False,
  235. ],
  236. [
  237. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  238. DateTimeRange("2015-03-22T11:00:00+0900", "2015-03-22T12:10:00+0900"),
  239. False,
  240. ],
  241. [DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME), None, False],
  242. [None, DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME), False],
  243. ],
  244. )
  245. def test_normal(self, lhs, rhs, expected):
  246. assert (lhs == rhs) == expected
  247. class TestDateTimeRange_neq:
  248. @pytest.mark.parametrize(
  249. ["lhs", "rhs", "expected"],
  250. [
  251. [DateTimeRange(None, None), DateTimeRange(None, None), False],
  252. [
  253. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  254. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  255. False,
  256. ],
  257. [
  258. DateTimeRange("2015-03-22T10:00:00", "2015-03-22T10:10:00"),
  259. DateTimeRange("2015-03-22T10:00:00", "2015-03-22T10:10:00"),
  260. False,
  261. ],
  262. [
  263. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  264. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:20:00+0900"),
  265. True,
  266. ],
  267. [
  268. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  269. DateTimeRange("2015-03-22T10:02:00+0900", "2015-03-22T10:10:00+0900"),
  270. True,
  271. ],
  272. [
  273. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  274. DateTimeRange("2015-03-22T11:00:00+0900", "2015-03-22T12:10:00+0900"),
  275. True,
  276. ],
  277. [DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME), None, True],
  278. [None, DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME), True],
  279. ],
  280. )
  281. def test_normal(self, lhs, rhs, expected):
  282. assert (lhs != rhs) == expected
  283. class TestDateTimeRange_add:
  284. @pytest.mark.parametrize(
  285. ["value", "add_value", "expected"],
  286. [
  287. [
  288. DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900"),
  289. timedelta(seconds=10 * 60),
  290. DateTimeRange("2015-03-22T10:10:00+0900", "2015-03-22T10:20:00+0900"),
  291. ],
  292. [
  293. DateTimeRange("2015-03-22T10:00:00", "2015-03-22T10:10:00"),
  294. timedelta(seconds=-10 * 60),
  295. DateTimeRange("2015-03-22T09:50:00", "2015-03-22T10:00:00"),
  296. ],
  297. ],
  298. )
  299. def test_normal(self, value, add_value, expected):
  300. new_datetimerange = value + add_value
  301. assert new_datetimerange == expected
  302. @pytest.mark.parametrize(
  303. ["value", "expected"],
  304. [["2015-03-22T10:10:00+0900", TypeError], [1, TypeError], [None, TypeError]],
  305. )
  306. def test_exception(self, datetimerange_normal, value, expected):
  307. with pytest.raises(TypeError):
  308. datetimerange_normal + value
  309. def test_null(self, datetimerange_null):
  310. with pytest.raises(TypeError):
  311. datetimerange_null + timedelta(seconds=10 * 60)
  312. class TestDateTimeRange_iadd:
  313. def test_normal(self):
  314. value = DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900")
  315. expected = DateTimeRange("2015-03-22T10:10:00+0900", "2015-03-22T10:20:00+0900")
  316. value += timedelta(seconds=10 * 60)
  317. assert value == expected
  318. @pytest.mark.parametrize(
  319. ["value", "expected"],
  320. [["2015-03-22T10:10:00+0900", TypeError], [1, TypeError], [None, TypeError]],
  321. )
  322. def test_exception(self, datetimerange_normal, value, expected):
  323. with pytest.raises(TypeError):
  324. datetimerange_normal += value
  325. def test_null(self, datetimerange_null):
  326. with pytest.raises(TypeError):
  327. datetimerange_null += timedelta(seconds=10 * 60)
  328. class TestDateTimeRange_sub:
  329. def test_normal(self):
  330. value = DateTimeRange("2015-03-22T10:10:00+0900", "2015-03-22T10:20:00+0900")
  331. expected = DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900")
  332. new_datetimerange = value - timedelta(seconds=10 * 60)
  333. assert new_datetimerange == expected
  334. @pytest.mark.parametrize(
  335. ["value", "expected"],
  336. [["2015-03-22T10:10:00+0900", TypeError], [1, TypeError], [None, TypeError]],
  337. )
  338. def test_exception(self, datetimerange_normal, value, expected):
  339. with pytest.raises(TypeError):
  340. datetimerange_normal - value
  341. def test_null(self, datetimerange_null):
  342. with pytest.raises(TypeError):
  343. datetimerange_null - timedelta(seconds=10 * 60)
  344. class TestDateTimeRange_isub:
  345. def test_normal(self):
  346. value = DateTimeRange("2015-03-22T10:10:00+0900", "2015-03-22T10:20:00+0900")
  347. expected = DateTimeRange("2015-03-22T10:00:00+0900", "2015-03-22T10:10:00+0900")
  348. value -= timedelta(seconds=10 * 60)
  349. assert value == expected
  350. @pytest.mark.parametrize(
  351. ["value", "expected"],
  352. [["2015-03-22T10:10:00+0900", TypeError], [1, TypeError], [None, TypeError]],
  353. )
  354. def test_exception(self, datetimerange_normal, value, expected):
  355. with pytest.raises(TypeError):
  356. datetimerange_normal -= value
  357. def test_null(self, datetimerange_null):
  358. with pytest.raises(TypeError):
  359. datetimerange_null -= timedelta(seconds=10 * 60)
  360. class TestDateTimeRange_contains:
  361. @pytest.mark.parametrize(
  362. ["value", "expected"],
  363. [
  364. [START_DATETIME_TEXT, True],
  365. [END_DATETIME_TEXT, True],
  366. [TEST_START_DATETIME, True],
  367. [TEST_END_DATETIME, True],
  368. [
  369. DateTimeRange("2015-03-22 10:05:00" + TIMEZONE, "2015-03-22 10:06:00" + TIMEZONE),
  370. True,
  371. ],
  372. [
  373. DateTimeRange("2015-03-22 10:10:01" + TIMEZONE, "2015-03-22 10:11:01" + TIMEZONE),
  374. False,
  375. ],
  376. ["2015-03-22 09:59:59" + TIMEZONE, False],
  377. ["2015-03-22 10:10:01" + TIMEZONE, False],
  378. ],
  379. )
  380. def test_normal(self, datetimerange_normal, value, expected):
  381. assert (value in datetimerange_normal) == expected
  382. @pytest.mark.parametrize(
  383. ["value", "expected"], [[None, TypeError], [False, TypeError], [20140513221937, TypeError]]
  384. )
  385. def test_exception(self, datetimerange_normal, value, expected):
  386. with pytest.raises(expected):
  387. value in datetimerange_normal
  388. @pytest.mark.parametrize(
  389. ["value", "expected"],
  390. [[TEST_START_DATETIME, TypeError], ["aaa", TypeError], [None, TypeError]],
  391. )
  392. def test_null_start(self, datetimerange_null_start, value, expected):
  393. with pytest.raises(expected):
  394. value in datetimerange_null_start
  395. class TestDateTimeRange_timedelta:
  396. def test_normal(self, datetimerange_normal):
  397. assert datetimerange_normal.timedelta == timedelta(seconds=10 * 60)
  398. @pytest.mark.parametrize(
  399. ["start", "end", "expected"],
  400. [
  401. [
  402. "2015-03-08T00:00:00-0400",
  403. "2015-03-08T12:00:00-0400",
  404. timedelta(0, 39600), # 11 hours
  405. ],
  406. [
  407. "2015-11-01T00:00:00-0400",
  408. "2015-11-01T12:00:00-0400",
  409. timedelta(0, 46800), # 13 hours
  410. ],
  411. ],
  412. )
  413. def test_daylight_saving_time(self, start, end, expected):
  414. dtr = DateTimeRange(start, end)
  415. assert dtr.timedelta == expected
  416. def test_inversion(self, datetimerange_inversion):
  417. assert datetimerange_inversion.timedelta == timedelta(-1, 85800)
  418. def test_null(self, datetimerange_null):
  419. with pytest.raises(TypeError):
  420. datetimerange_null.timedelta
  421. def test_exception(self, datetimerange_null_start):
  422. with pytest.raises(TypeError):
  423. datetimerange_null_start.timedelta
  424. class TestDateTimeRange_is_set:
  425. @pytest.mark.parametrize(
  426. ["value", "expected"],
  427. [
  428. [DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME), True],
  429. [DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME), True],
  430. [DateTimeRange(TEST_START_DATETIME, None), False],
  431. [DateTimeRange(None, TEST_START_DATETIME), False],
  432. [DateTimeRange(None, None), False],
  433. ],
  434. )
  435. def test_normal(self, value, expected):
  436. assert value.is_set() == expected
  437. class TestDateTimeRange_validate_time_inversion:
  438. @pytest.mark.parametrize(
  439. ["value"],
  440. [
  441. [DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME)],
  442. [DateTimeRange(TEST_START_DATETIME, TEST_START_DATETIME)],
  443. ],
  444. )
  445. def test_normal(self, value):
  446. value.validate_time_inversion()
  447. def test_inversion(self, datetimerange_inversion):
  448. with pytest.raises(ValueError):
  449. datetimerange_inversion.validate_time_inversion()
  450. @pytest.mark.parametrize(
  451. ["value"],
  452. [
  453. [DateTimeRange(None, None)],
  454. [DateTimeRange(None, TEST_END_DATETIME)],
  455. [DateTimeRange(TEST_START_DATETIME, None)],
  456. ],
  457. )
  458. def test_exception(self, value):
  459. with pytest.raises(TypeError):
  460. value.validate_time_inversion()
  461. class TestDateTimeRange_is_valid_timerange:
  462. @pytest.mark.parametrize(
  463. ["value", "expected"],
  464. [
  465. [DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME), True],
  466. [DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME), False],
  467. [DateTimeRange(TEST_START_DATETIME, None), False],
  468. [DateTimeRange(None, TEST_START_DATETIME), False],
  469. [DateTimeRange(None, None), False],
  470. ],
  471. )
  472. def test_normal(self, value, expected):
  473. assert value.is_valid_timerange() == expected
  474. class TestDateTimeRange_range:
  475. @pytest.mark.parametrize(
  476. ["value", "step", "expected"],
  477. [
  478. [
  479. DateTimeRange(datetime(2015, 3, 22, 0, 0, 0), datetime(2015, 3, 22, 0, 1, 0)),
  480. timedelta(seconds=20),
  481. [
  482. datetime(2015, 3, 22, 0, 0, 0),
  483. datetime(2015, 3, 22, 0, 0, 20),
  484. datetime(2015, 3, 22, 0, 0, 40),
  485. datetime(2015, 3, 22, 0, 1, 00),
  486. ],
  487. ],
  488. [
  489. DateTimeRange(datetime(2015, 3, 22, 0, 0, 0), datetime(2015, 3, 23, 0, 0, 0)),
  490. relativedelta(hours=+6),
  491. [
  492. datetime(2015, 3, 22, 0, 0, 0),
  493. datetime(2015, 3, 22, 6, 0, 0),
  494. datetime(2015, 3, 22, 12, 0, 0),
  495. datetime(2015, 3, 22, 18, 0, 0),
  496. datetime(2015, 3, 23, 0, 0, 0),
  497. ],
  498. ],
  499. [
  500. DateTimeRange(datetime(2015, 3, 22, 0, 0, 0), datetime(2015, 3, 23, 0, 0, 0)),
  501. relativedelta(months=+6),
  502. [datetime(2015, 3, 22, 0, 0, 0)],
  503. ],
  504. [
  505. DateTimeRange("2015-01-01T00:00:00+0900", "2016-01-01T00:00:00+0900"),
  506. relativedelta(months=+4),
  507. [
  508. parse("2015-01-01T00:00:00+0900"),
  509. parse("2015-05-01T00:00:00+0900"),
  510. parse("2015-09-01T00:00:00+0900"),
  511. parse("2016-01-01T00:00:00+0900"),
  512. ],
  513. ],
  514. [
  515. DateTimeRange(datetime(2015, 3, 23, 0, 0, 0), datetime(2015, 3, 22, 0, 0, 0)),
  516. relativedelta(hours=-6),
  517. [
  518. datetime(2015, 3, 23, 0, 0, 0),
  519. datetime(2015, 3, 22, 18, 0, 0),
  520. datetime(2015, 3, 22, 12, 0, 0),
  521. datetime(2015, 3, 22, 6, 0, 0),
  522. datetime(2015, 3, 22, 0, 0, 0),
  523. ],
  524. ],
  525. [
  526. DateTimeRange(date(2015, 3, 23), date(2015, 3, 26)),
  527. relativedelta(days=+1),
  528. [
  529. datetime(2015, 3, 23, 0, 0, 0),
  530. datetime(2015, 3, 24, 0, 0, 0),
  531. datetime(2015, 3, 25, 0, 0, 0),
  532. datetime(2015, 3, 26, 0, 0, 0),
  533. ],
  534. ],
  535. ],
  536. )
  537. def test_normal(self, value, step, expected):
  538. for value_item, expected_item in zip(value.range(step), expected):
  539. assert value_item == expected_item
  540. @pytest.mark.parametrize(
  541. ["value", "step", "expected"],
  542. [
  543. [
  544. DateTimeRange(datetime(2015, 3, 22, 0, 0, 0), datetime(2015, 3, 22, 0, 1, 0)),
  545. relativedelta(seconds=-60),
  546. ValueError,
  547. ],
  548. [
  549. DateTimeRange(datetime(2015, 3, 22, 0, 1, 0), datetime(2015, 3, 22, 0, 0, 0)),
  550. relativedelta(seconds=+60),
  551. ValueError,
  552. ],
  553. [
  554. DateTimeRange(datetime(2015, 3, 22, 0, 0, 0), datetime(2015, 3, 22, 0, 1, 0)),
  555. None,
  556. AttributeError,
  557. ],
  558. [
  559. DateTimeRange(datetime(2015, 3, 22, 0, 0, 0), datetime(2015, 3, 22, 0, 1, 0)),
  560. 1,
  561. AttributeError,
  562. ],
  563. [
  564. DateTimeRange(datetime(2015, 3, 22, 0, 0, 0), datetime(2015, 3, 22, 0, 1, 0)),
  565. timedelta(seconds=0),
  566. ValueError,
  567. ],
  568. [
  569. DateTimeRange(datetime(2015, 3, 22, 0, 0, 0), datetime(2015, 3, 22, 0, 1, 0)),
  570. relativedelta(months=+0),
  571. ValueError,
  572. ],
  573. [None, relativedelta(months=+4), AttributeError],
  574. [10, relativedelta(months=+4), AttributeError],
  575. ],
  576. )
  577. def test_exception(self, value, step, expected):
  578. with pytest.raises(expected):
  579. for i in value.range(step):
  580. pass
  581. class TestDateTimeRange_is_intersection:
  582. @pytest.mark.parametrize(
  583. ["lhs", "rhs", "expected"],
  584. [
  585. [
  586. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  587. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  588. True,
  589. ],
  590. [
  591. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:00:00+0900"),
  592. DateTimeRange("2015-01-22T10:10:00+0900", "2015-03-22T10:20:00+0900"),
  593. False,
  594. ],
  595. [
  596. DateTimeRange("2015-01-22T09:50:00", "2015-01-22T10:00:00"),
  597. DateTimeRange("2015-01-22T10:10:00", "2015-03-22T10:20:00"),
  598. False,
  599. ],
  600. [
  601. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:00:00+0900"),
  602. DateTimeRange("2015-01-22T10:00:00+0900", "2015-03-22T10:20:00+0900"),
  603. True,
  604. ],
  605. [
  606. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:05:00+0900"),
  607. DateTimeRange("2015-01-22T10:00:00+0900", "2015-03-22T10:20:00+0900"),
  608. True,
  609. ],
  610. [
  611. DateTimeRange("2015-01-22T10:00:00+0900", "2015-03-22T10:20:00+0900"),
  612. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:05:00+0900"),
  613. True,
  614. ],
  615. [
  616. DateTimeRange("2014-01-22T10:00:00 JST", "2016-03-22T10:20:00 JST"),
  617. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:05:00 JST"),
  618. True,
  619. ],
  620. [
  621. DateTimeRange("2015-01-12T10:00:00 JST", "2015-02-22T10:10:00 JST"),
  622. DateTimeRange("2015-01-22T10:00:00 JST", "2015-03-22T10:10:00 JST"),
  623. True,
  624. ],
  625. ],
  626. )
  627. def test_normal(self, lhs, rhs, expected):
  628. assert lhs.is_intersection(rhs) == expected
  629. @pytest.mark.parametrize(
  630. ["lhs", "rhs", "expected"],
  631. [
  632. [DateTimeRange(None, None), DateTimeRange(None, None), TypeError],
  633. [
  634. DateTimeRange(None, TEST_END_DATETIME),
  635. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  636. TypeError,
  637. ],
  638. [
  639. DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME),
  640. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  641. ValueError,
  642. ],
  643. [
  644. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  645. DateTimeRange(None, TEST_END_DATETIME),
  646. TypeError,
  647. ],
  648. [
  649. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  650. DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME),
  651. ValueError,
  652. ],
  653. ],
  654. )
  655. def test_exception(self, lhs, rhs, expected):
  656. with pytest.raises(expected):
  657. lhs.is_intersection(rhs)
  658. class TestDateTimeRange_subtract:
  659. @pytest.mark.parametrize(
  660. ["lhs", "rhs", "expected"],
  661. [
  662. [
  663. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  664. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  665. [],
  666. ],
  667. [
  668. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:00:00+0900"),
  669. DateTimeRange("2015-01-22T09:30:00+0900", "2015-01-22T10:30:00+0900"),
  670. [],
  671. ],
  672. [
  673. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:30:00+0900"),
  674. DateTimeRange("2015-01-22T10:40:00+0900", "2015-01-22T10:50:00+0900"),
  675. [DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:30:00+0900")],
  676. ],
  677. [
  678. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:30:00+0900"),
  679. DateTimeRange("2015-01-22T09:55:00+0900", "2015-01-22T09:55:00+0900"),
  680. [DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:30:00+0900")],
  681. ],
  682. [
  683. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:30:00+0900"),
  684. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:00:00+0900"),
  685. [DateTimeRange("2015-01-22T10:00:00+0900", "2015-01-22T10:30:00+0900")],
  686. ],
  687. [
  688. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:30:00+0900"),
  689. DateTimeRange("2015-01-22T09:30:00+0900", "2015-01-22T10:00:00+0900"),
  690. [DateTimeRange("2015-01-22T10:00:00+0900", "2015-01-22T10:30:00+0900")],
  691. ],
  692. [
  693. DateTimeRange("2015-01-22T09:30:00+0900", "2015-01-22T10:00:00+0900"),
  694. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:00:00+0900"),
  695. [DateTimeRange("2015-01-22T09:30:00+0900", "2015-01-22T09:50:00+0900")],
  696. ],
  697. [
  698. DateTimeRange("2015-01-22T09:30:00+0900", "2015-01-22T10:00:00+0900"),
  699. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:10:00+0900"),
  700. [DateTimeRange("2015-01-22T09:30:00+0900", "2015-01-22T09:50:00+0900")],
  701. ],
  702. [
  703. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T10:00:00+0900"),
  704. DateTimeRange("2015-01-22T09:55:00+0900", "2015-01-22T09:56:00+0900"),
  705. [
  706. DateTimeRange("2015-01-22T09:50:00+0900", "2015-01-22T09:55:00+0900"),
  707. DateTimeRange("2015-01-22T09:56:00+0900", "2015-01-22T10:00:00+0900"),
  708. ],
  709. ],
  710. ],
  711. )
  712. def test_normal(self, lhs, rhs, expected):
  713. assert lhs.subtract(rhs) == expected
  714. @pytest.mark.parametrize(
  715. ["lhs", "rhs", "expected"],
  716. [
  717. [DateTimeRange(None, None), DateTimeRange(None, None), TypeError],
  718. [
  719. DateTimeRange(None, TEST_END_DATETIME),
  720. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  721. TypeError,
  722. ],
  723. [
  724. DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME),
  725. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  726. ValueError,
  727. ],
  728. [
  729. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  730. DateTimeRange(None, TEST_END_DATETIME),
  731. TypeError,
  732. ],
  733. [
  734. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  735. DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME),
  736. ValueError,
  737. ],
  738. ],
  739. )
  740. def test_exception(self, lhs, rhs, expected):
  741. with pytest.raises(expected):
  742. lhs.subtract(rhs)
  743. class TestDateTimeRange_get_start_time_str:
  744. @pytest.mark.parametrize(
  745. ["time_format", "expected"],
  746. [
  747. [ISO_TIME_FORMAT, START_DATETIME_TEXT],
  748. ["%Y/%m/%d %H:%M:%S%z", "2015/03/22 10:00:00+0900"],
  749. ],
  750. )
  751. def test_normal(self, datetimerange_normal, time_format, expected):
  752. datetimerange_normal.start_time_format = time_format
  753. assert datetimerange_normal.get_start_time_str() == expected
  754. def test_abnormal_1(self, datetimerange_null):
  755. assert datetimerange_null.get_start_time_str() == DateTimeRange.NOT_A_TIME_STR
  756. def test_abnormal_2(self, datetimerange_normal):
  757. datetimerange_normal.start_time_format = "aaa"
  758. assert datetimerange_normal.get_start_time_str() == "aaa"
  759. @pytest.mark.parametrize(["time_format", "expected"], [[None, TypeError]])
  760. def test_exception(self, datetimerange_normal, time_format, expected):
  761. datetimerange_normal.start_time_format = time_format
  762. with pytest.raises(expected):
  763. datetimerange_normal.get_start_time_str()
  764. class TestDateTimeRange_get_end_time_str:
  765. @pytest.mark.parametrize(
  766. ["time_format", "expected"],
  767. [[ISO_TIME_FORMAT, END_DATETIME_TEXT], ["%Y/%m/%d %H:%M:%S%z", "2015/03/22 10:10:00+0900"]],
  768. )
  769. def test_normal(self, datetimerange_normal, time_format, expected):
  770. datetimerange_normal.end_time_format = time_format
  771. assert datetimerange_normal.get_end_time_str() == expected
  772. def test_abnormal_1(self, datetimerange_null):
  773. assert datetimerange_null.get_end_time_str() == DateTimeRange.NOT_A_TIME_STR
  774. def test_abnormal_2(self, datetimerange_normal):
  775. datetimerange_normal.end_time_format = "aaa"
  776. assert datetimerange_normal.get_end_time_str() == "aaa"
  777. @pytest.mark.parametrize(["time_format", "expected"], [[None, TypeError]])
  778. def test_exception(self, datetimerange_normal, time_format, expected):
  779. datetimerange_normal.end_time_format = time_format
  780. with pytest.raises(expected):
  781. datetimerange_normal.get_end_time_str()
  782. class TestDateTimeRange_get_timedelta_second:
  783. def test_normal(self, datetimerange_normal):
  784. assert datetimerange_normal.get_timedelta_second() == 600
  785. def test_inversion(self, datetimerange_inversion):
  786. assert datetimerange_inversion.get_timedelta_second() == -600
  787. def test_null(self, datetimerange_null):
  788. with pytest.raises(TypeError):
  789. datetimerange_null.get_timedelta_second()
  790. def test_exception(self, datetimerange_null_start):
  791. with pytest.raises(TypeError):
  792. datetimerange_null_start.get_timedelta_second()
  793. class TestDateTimeRange_set_start_datetime:
  794. @pytest.mark.parametrize(
  795. ["value", "timezone", "expected"],
  796. [
  797. [START_DATETIME_TEXT, None, TEST_START_DATETIME],
  798. [TEST_START_DATETIME, None, TEST_START_DATETIME],
  799. [1485685623, pytz.utc, pytz.utc.localize(datetime(2017, 1, 29, 10, 27, 3))],
  800. ["1485685623", pytz.utc, pytz.utc.localize(datetime(2017, 1, 29, 10, 27, 3))],
  801. [
  802. 1485685623,
  803. pytz.timezone("Asia/Tokyo"),
  804. pytz.timezone("Asia/Tokyo").localize(datetime(2017, 1, 29, 19, 27, 3)),
  805. ],
  806. [None, None, None],
  807. ],
  808. )
  809. def test_normal(self, value, timezone, expected):
  810. dtr = DateTimeRange(TEST_END_DATETIME, TEST_END_DATETIME)
  811. dtr.set_start_datetime(value, timezone=timezone)
  812. assert dtr.start_datetime == expected
  813. @pytest.mark.parametrize(
  814. ["value", "expected"], [["invalid time string", ValueError], ["3.3.5", ValueError]]
  815. )
  816. def test_null_start(self, datetimerange_null_start, value, expected):
  817. with pytest.raises(expected):
  818. datetimerange_null_start.set_start_datetime(value)
  819. class TestDateTimeRange_set_end_datetime:
  820. @pytest.mark.parametrize(
  821. ["value", "timezone", "expected"],
  822. [
  823. [START_DATETIME_TEXT, None, TEST_START_DATETIME],
  824. [TEST_START_DATETIME, None, TEST_START_DATETIME],
  825. [1485685623, pytz.utc, pytz.utc.localize(datetime(2017, 1, 29, 10, 27, 3))],
  826. ["1485685623", pytz.utc, pytz.utc.localize(datetime(2017, 1, 29, 10, 27, 3))],
  827. [
  828. 1485685623,
  829. pytz.timezone("Asia/Tokyo"),
  830. pytz.timezone("Asia/Tokyo").localize(datetime(2017, 1, 29, 19, 27, 3)),
  831. ],
  832. [None, None, None],
  833. ],
  834. )
  835. def test_normal(self, value, timezone, expected):
  836. dtr = DateTimeRange(TEST_END_DATETIME, TEST_END_DATETIME)
  837. dtr.set_end_datetime(value, timezone=timezone)
  838. assert dtr.end_datetime == expected
  839. @pytest.mark.parametrize(
  840. ["value", "expected"], [["invalid time string", ValueError], ["3.3.5", ValueError]]
  841. )
  842. def test_null_start(self, datetimerange_null_start, value, expected):
  843. with pytest.raises(expected):
  844. datetimerange_null_start.set_end_datetime(value)
  845. class TestDateTimeRange_set_time_range:
  846. @pytest.mark.parametrize(
  847. ["start", "end", "expected"],
  848. [
  849. [
  850. START_DATETIME_TEXT,
  851. END_DATETIME_TEXT,
  852. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  853. ],
  854. [None, None, DateTimeRange(None, None)],
  855. ],
  856. )
  857. def test_normal(self, start, end, expected):
  858. dtr = DateTimeRange()
  859. dtr.set_time_range(start, end)
  860. assert dtr == expected
  861. @pytest.mark.parametrize(
  862. ["start", "end", "expected"],
  863. [
  864. ["invalid time string", END_DATETIME_TEXT, ValueError],
  865. [START_DATETIME_TEXT, "invalid time string", ValueError],
  866. ["invalid time string", "invalid time string", ValueError],
  867. ],
  868. )
  869. def test_exception(self, start, end, expected):
  870. dtr = DateTimeRange()
  871. with pytest.raises(expected):
  872. dtr.set_time_range(start, end)
  873. class TestDateTimeRange_intersection:
  874. @pytest.mark.parametrize(
  875. ["lhs", "rhs", "expected"],
  876. [
  877. [
  878. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  879. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  880. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  881. ],
  882. [
  883. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:00:00 JST"),
  884. DateTimeRange("2015-01-22T10:10:00 JST", "2015-03-22T10:20:00 JST"),
  885. DateTimeRange(None, None),
  886. ],
  887. [
  888. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:00:00 JST"),
  889. DateTimeRange("2015-01-22T10:00:00 JST", "2015-03-22T10:20:00 JST"),
  890. DateTimeRange("2015-01-22T10:00:00 JST", "2015-01-22T10:00:00 JST"),
  891. ],
  892. [
  893. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:05:00 JST"),
  894. DateTimeRange("2015-01-22T10:00:00 JST", "2015-03-22T10:20:00 JST"),
  895. DateTimeRange("2015-01-22T10:00:00 JST", "2015-01-22T10:05:00 JST"),
  896. ],
  897. [
  898. DateTimeRange("2015-01-22T10:00:00 JST", "2015-03-22T10:20:00 JST"),
  899. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:05:00 JST"),
  900. DateTimeRange("2015-01-22T10:00:00 JST", "2015-01-22T10:05:00 JST"),
  901. ],
  902. [
  903. DateTimeRange("2014-01-22T10:00:00 JST", "2016-03-22T10:20:00 JST"),
  904. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:05:00 JST"),
  905. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:05:00 JST"),
  906. ],
  907. [
  908. DateTimeRange("2015-01-12T10:00:00 JST", "2015-02-22T10:10:00 JST"),
  909. DateTimeRange("2015-01-22T10:00:00 JST", "2015-03-22T10:10:00 JST"),
  910. DateTimeRange("2015-01-22T10:00:00 JST", "2015-02-22T10:10:00 JST"),
  911. ],
  912. ],
  913. )
  914. def test_normal(self, lhs, rhs, expected):
  915. lhs_org = deepcopy(lhs)
  916. assert lhs.intersection(rhs) == expected
  917. assert lhs == lhs_org
  918. @pytest.mark.parametrize(
  919. ["lhs", "rhs", "expected"],
  920. [
  921. [DateTimeRange(None, None), DateTimeRange(None, None), TypeError],
  922. [
  923. DateTimeRange(None, TEST_END_DATETIME),
  924. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  925. TypeError,
  926. ],
  927. [
  928. DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME),
  929. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  930. ValueError,
  931. ],
  932. [
  933. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  934. DateTimeRange(None, TEST_END_DATETIME),
  935. TypeError,
  936. ],
  937. [
  938. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  939. DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME),
  940. ValueError,
  941. ],
  942. ],
  943. )
  944. def test_exception(self, lhs, rhs, expected):
  945. with pytest.raises(expected):
  946. lhs.intersection(rhs)
  947. class TestDateTimeRange_encompass:
  948. @pytest.mark.parametrize(
  949. ["lhs", "rhs", "expected"],
  950. [
  951. [
  952. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  953. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  954. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  955. ],
  956. [
  957. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:00:00 JST"),
  958. DateTimeRange("2015-01-22T10:10:00 JST", "2015-01-22T10:20:00 JST"),
  959. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:20:00 JST"),
  960. ],
  961. [
  962. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:00:00 JST"),
  963. DateTimeRange("2015-01-22T10:00:00 JST", "2015-01-22T10:20:00 JST"),
  964. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:20:00 JST"),
  965. ],
  966. [
  967. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:05:00 JST"),
  968. DateTimeRange("2015-01-22T10:00:00 JST", "2015-01-22T10:20:00 JST"),
  969. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:20:00 JST"),
  970. ],
  971. [
  972. DateTimeRange("2015-01-22T10:00:00 JST", "2015-03-22T10:20:00 JST"),
  973. DateTimeRange("2015-01-22T09:50:00 JST", "2015-01-22T10:05:00 JST"),
  974. DateTimeRange("2015-01-22T09:50:00 JST", "2015-03-22T10:20:00 JST"),
  975. ],
  976. ],
  977. )
  978. def test_normal(self, lhs, rhs, expected):
  979. lhs_org = deepcopy(lhs)
  980. assert lhs.encompass(rhs) == expected
  981. assert lhs == lhs_org
  982. @pytest.mark.parametrize(
  983. ["lhs", "rhs", "expected"],
  984. [
  985. [DateTimeRange(None, None), DateTimeRange(None, None), TypeError],
  986. [
  987. DateTimeRange(None, TEST_END_DATETIME),
  988. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  989. TypeError,
  990. ],
  991. [
  992. DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME),
  993. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  994. ValueError,
  995. ],
  996. [
  997. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  998. DateTimeRange(None, TEST_END_DATETIME),
  999. TypeError,
  1000. ],
  1001. [
  1002. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  1003. DateTimeRange(TEST_END_DATETIME, TEST_START_DATETIME),
  1004. ValueError,
  1005. ],
  1006. ],
  1007. )
  1008. def test_exception(self, lhs, rhs, expected):
  1009. with pytest.raises(expected):
  1010. lhs.encompass(rhs)
  1011. class TestDateTimeRange_truncate:
  1012. @pytest.mark.parametrize(
  1013. ["value", "expected"],
  1014. [
  1015. [0, DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME)],
  1016. [10, DateTimeRange("2015-03-22 10:00:30" + TIMEZONE, "2015-03-22 10:09:30" + TIMEZONE)],
  1017. ],
  1018. )
  1019. def test_normal(self, datetimerange_normal, value, expected):
  1020. datetimerange_normal.truncate(value)
  1021. assert datetimerange_normal == expected
  1022. @pytest.mark.parametrize(["value", "expected"], [[-10, ValueError]])
  1023. def test_exception(self, datetimerange_normal, value, expected):
  1024. with pytest.raises(expected):
  1025. datetimerange_normal.truncate(value)
  1026. @pytest.mark.parametrize(["value"], [[10]])
  1027. def test_null(self, datetimerange_null_start, value):
  1028. with pytest.raises(TypeError):
  1029. datetimerange_null_start.truncate(value)
  1030. class TestDateTimeRange_split:
  1031. @pytest.mark.parametrize(
  1032. ["dtr", "separator", "expected"],
  1033. [
  1034. [
  1035. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  1036. "2015-03-22 10:05:00" + TIMEZONE,
  1037. [
  1038. DateTimeRange(TEST_START_DATETIME, "2015-03-22 10:05:00" + TIMEZONE),
  1039. DateTimeRange("2015-03-22 10:05:00" + TIMEZONE, TEST_END_DATETIME),
  1040. ],
  1041. ],
  1042. [
  1043. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  1044. "2015-03-22 09:59:59" + TIMEZONE,
  1045. [DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME)],
  1046. ],
  1047. [
  1048. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  1049. TEST_START_DATETIME,
  1050. [DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME)],
  1051. ],
  1052. [
  1053. DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME),
  1054. END_DATETIME_TEXT,
  1055. [DateTimeRange(TEST_START_DATETIME, TEST_END_DATETIME)],
  1056. ],
  1057. ],
  1058. )
  1059. def test_normal(self, dtr, separator, expected):
  1060. assert dtr.split(separator) == expected
  1061. class TestDateTimeRange_from_range_text:
  1062. @pytest.mark.parametrize(
  1063. ["value", "separator", "expected"],
  1064. [
  1065. [
  1066. "{} - {}".format(START_DATETIME_TEXT, END_DATETIME_TEXT),
  1067. "-",
  1068. DateTimeRange(START_DATETIME_TEXT, END_DATETIME_TEXT),
  1069. ],
  1070. [
  1071. "{} to {}".format(START_DATETIME_TEXT, END_DATETIME_TEXT),
  1072. "to",
  1073. DateTimeRange(START_DATETIME_TEXT, END_DATETIME_TEXT),
  1074. ],
  1075. [
  1076. "{} - {}".format(START_DATETIME_TEXT, END_DATETIME_TEXT),
  1077. "-",
  1078. DateTimeRange(START_DATETIME_TEXT, END_DATETIME_TEXT),
  1079. ],
  1080. ],
  1081. )
  1082. def test_normal(self, value, separator, expected):
  1083. dtr = DateTimeRange.from_range_text(value, separator=separator)
  1084. assert dtr == expected
  1085. assert dtr.start_time_format == r"%Y-%m-%dT%H:%M:%S%z"
  1086. assert dtr.end_time_format == r"%Y-%m-%dT%H:%M:%S%z"
  1087. @pytest.mark.parametrize(
  1088. ["value", "time_format", "expected"],
  1089. [
  1090. [
  1091. "{} - {}".format(START_DATETIME_TEXT, END_DATETIME_TEXT),
  1092. r"%Y-%m-%d",
  1093. DateTimeRange(
  1094. START_DATETIME_TEXT,
  1095. END_DATETIME_TEXT,
  1096. start_time_format=r"%Y-%m-%d",
  1097. end_time_format=r"%Y-%m-%d",
  1098. ),
  1099. ],
  1100. ],
  1101. )
  1102. def test_normal_time_format(self, value, time_format, expected):
  1103. dtr = DateTimeRange.from_range_text(
  1104. value, start_time_format=time_format, end_time_format=time_format
  1105. )
  1106. assert dtr == expected
  1107. assert dtr.start_time_format == time_format
  1108. assert dtr.end_time_format == time_format