test_interval.py 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2021, Brandon Nielsen
  3. # All rights reserved.
  4. #
  5. # This software may be modified and distributed under the terms
  6. # of the BSD license. See the LICENSE file for details.
  7. import unittest
  8. import aniso8601
  9. from aniso8601.builders import (
  10. DatetimeTuple,
  11. DateTuple,
  12. DurationTuple,
  13. IntervalTuple,
  14. TimeTuple,
  15. TimezoneTuple,
  16. )
  17. from aniso8601.exceptions import ISOFormatError
  18. from aniso8601.interval import (
  19. _get_interval_component_resolution,
  20. _get_interval_resolution,
  21. _parse_interval,
  22. _parse_interval_end,
  23. get_interval_resolution,
  24. get_repeating_interval_resolution,
  25. parse_interval,
  26. parse_repeating_interval,
  27. )
  28. from aniso8601.resolution import IntervalResolution
  29. from aniso8601.tests.compat import mock
  30. class TestIntervalParser_UtilityFunctions(unittest.TestCase):
  31. def test_get_interval_resolution(self):
  32. self.assertEqual(
  33. _get_interval_resolution(
  34. IntervalTuple(
  35. start=DateTuple(
  36. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  37. ),
  38. end=DatetimeTuple(
  39. DateTuple(
  40. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  41. ),
  42. TimeTuple(hh="04", mm="05", ss="06", tz=None),
  43. ),
  44. duration=None,
  45. )
  46. ),
  47. IntervalResolution.Seconds,
  48. )
  49. self.assertEqual(
  50. _get_interval_resolution(
  51. IntervalTuple(
  52. start=DatetimeTuple(
  53. DateTuple(
  54. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  55. ),
  56. TimeTuple(hh="04", mm="05", ss="06", tz=None),
  57. ),
  58. end=DateTuple(
  59. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  60. ),
  61. duration=None,
  62. )
  63. ),
  64. IntervalResolution.Seconds,
  65. )
  66. self.assertEqual(
  67. _get_interval_resolution(
  68. IntervalTuple(
  69. start=DateTuple(
  70. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  71. ),
  72. end=None,
  73. duration=DurationTuple(
  74. PnY="1", PnM="2", PnW=None, PnD="3", TnH="4", TnM="5", TnS="6"
  75. ),
  76. )
  77. ),
  78. IntervalResolution.Seconds,
  79. )
  80. self.assertEqual(
  81. _get_interval_resolution(
  82. IntervalTuple(
  83. start=DatetimeTuple(
  84. DateTuple(
  85. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  86. ),
  87. TimeTuple(hh="04", mm="05", ss="06", tz=None),
  88. ),
  89. end=None,
  90. duration=DurationTuple(
  91. PnY="1",
  92. PnM="2",
  93. PnW=None,
  94. PnD="3",
  95. TnH=None,
  96. TnM=None,
  97. TnS=None,
  98. ),
  99. )
  100. ),
  101. IntervalResolution.Seconds,
  102. )
  103. self.assertEqual(
  104. _get_interval_resolution(
  105. IntervalTuple(
  106. start=None,
  107. end=DateTuple(
  108. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  109. ),
  110. duration=DurationTuple(
  111. PnY="1", PnM="2", PnW=None, PnD="3", TnH="4", TnM="5", TnS="6"
  112. ),
  113. )
  114. ),
  115. IntervalResolution.Seconds,
  116. )
  117. self.assertEqual(
  118. _get_interval_resolution(
  119. IntervalTuple(
  120. start=None,
  121. end=DatetimeTuple(
  122. DateTuple(
  123. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  124. ),
  125. TimeTuple(hh="04", mm="05", ss="06", tz=None),
  126. ),
  127. duration=DurationTuple(
  128. PnY="1",
  129. PnM="2",
  130. PnW=None,
  131. PnD="3",
  132. TnH=None,
  133. TnM=None,
  134. TnS=None,
  135. ),
  136. )
  137. ),
  138. IntervalResolution.Seconds,
  139. )
  140. def test_get_interval_component_resolution(self):
  141. self.assertEqual(
  142. _get_interval_component_resolution(
  143. DateTuple(YYYY="2001", MM=None, DD=None, Www=None, D=None, DDD="123")
  144. ),
  145. IntervalResolution.Ordinal,
  146. )
  147. self.assertEqual(
  148. _get_interval_component_resolution(
  149. DateTuple(YYYY="2001", MM=None, DD=None, Www="12", D="3", DDD=None)
  150. ),
  151. IntervalResolution.Weekday,
  152. )
  153. self.assertEqual(
  154. _get_interval_component_resolution(
  155. DateTuple(YYYY="2001", MM=None, DD=None, Www="12", D=None, DDD=None)
  156. ),
  157. IntervalResolution.Week,
  158. )
  159. self.assertEqual(
  160. _get_interval_component_resolution(
  161. DateTuple(YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None)
  162. ),
  163. IntervalResolution.Day,
  164. )
  165. self.assertEqual(
  166. _get_interval_component_resolution(
  167. DateTuple(YYYY="2001", MM="02", DD=None, Www=None, D=None, DDD=None)
  168. ),
  169. IntervalResolution.Month,
  170. )
  171. self.assertEqual(
  172. _get_interval_component_resolution(
  173. DateTuple(YYYY="2001", MM=None, DD=None, Www=None, D=None, DDD=None)
  174. ),
  175. IntervalResolution.Year,
  176. )
  177. self.assertEqual(
  178. _get_interval_component_resolution(
  179. DatetimeTuple(
  180. DateTuple(
  181. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  182. ),
  183. TimeTuple(hh="04", mm="05", ss="06", tz=None),
  184. )
  185. ),
  186. IntervalResolution.Seconds,
  187. )
  188. self.assertEqual(
  189. _get_interval_component_resolution(
  190. DatetimeTuple(
  191. DateTuple(
  192. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  193. ),
  194. TimeTuple(hh="04", mm="05", ss=None, tz=None),
  195. )
  196. ),
  197. IntervalResolution.Minutes,
  198. )
  199. self.assertEqual(
  200. _get_interval_component_resolution(
  201. DatetimeTuple(
  202. DateTuple(
  203. YYYY="2001", MM="02", DD="03", Www=None, D=None, DDD=None
  204. ),
  205. TimeTuple(hh="04", mm=None, ss=None, tz=None),
  206. )
  207. ),
  208. IntervalResolution.Hours,
  209. )
  210. self.assertEqual(
  211. _get_interval_component_resolution(
  212. DurationTuple(
  213. PnY="1", PnM="2", PnW=None, PnD="3", TnH="4", TnM="5", TnS="6"
  214. )
  215. ),
  216. IntervalResolution.Seconds,
  217. )
  218. self.assertEqual(
  219. _get_interval_component_resolution(
  220. DurationTuple(
  221. PnY="1", PnM="2", PnW=None, PnD="3", TnH="4", TnM="5", TnS=None
  222. )
  223. ),
  224. IntervalResolution.Minutes,
  225. )
  226. self.assertEqual(
  227. _get_interval_component_resolution(
  228. DurationTuple(
  229. PnY="1", PnM="2", PnW=None, PnD="3", TnH="4", TnM=None, TnS=None
  230. )
  231. ),
  232. IntervalResolution.Hours,
  233. )
  234. self.assertEqual(
  235. _get_interval_component_resolution(
  236. DurationTuple(
  237. PnY="1", PnM="2", PnW=None, PnD="3", TnH=None, TnM=None, TnS=None
  238. )
  239. ),
  240. IntervalResolution.Day,
  241. )
  242. self.assertEqual(
  243. _get_interval_component_resolution(
  244. DurationTuple(
  245. PnY="1", PnM="2", PnW=None, PnD=None, TnH=None, TnM=None, TnS=None
  246. )
  247. ),
  248. IntervalResolution.Month,
  249. )
  250. self.assertEqual(
  251. _get_interval_component_resolution(
  252. DurationTuple(
  253. PnY="1", PnM=None, PnW=None, PnD=None, TnH=None, TnM=None, TnS=None
  254. )
  255. ),
  256. IntervalResolution.Year,
  257. )
  258. self.assertEqual(
  259. _get_interval_component_resolution(
  260. DurationTuple(
  261. PnY=None, PnM=None, PnW="3", PnD=None, TnH=None, TnM=None, TnS=None
  262. )
  263. ),
  264. IntervalResolution.Week,
  265. )
  266. class TestIntervalParserFunctions(unittest.TestCase):
  267. def test_get_interval_resolution_date(self):
  268. self.assertEqual(get_interval_resolution("P1.5Y/2018"), IntervalResolution.Year)
  269. self.assertEqual(
  270. get_interval_resolution("P1.5Y/2018-03"), IntervalResolution.Month
  271. )
  272. self.assertEqual(
  273. get_interval_resolution("P1.5Y/2018-03-06"), IntervalResolution.Day
  274. )
  275. self.assertEqual(
  276. get_interval_resolution("P1.5Y/2018W01"), IntervalResolution.Week
  277. )
  278. self.assertEqual(
  279. get_interval_resolution("P1.5Y/2018-306"), IntervalResolution.Ordinal
  280. )
  281. self.assertEqual(
  282. get_interval_resolution("P1.5Y/2018W012"), IntervalResolution.Weekday
  283. )
  284. self.assertEqual(get_interval_resolution("2018/P1.5Y"), IntervalResolution.Year)
  285. self.assertEqual(
  286. get_interval_resolution("2018-03/P1.5Y"), IntervalResolution.Month
  287. )
  288. self.assertEqual(
  289. get_interval_resolution("2018-03-06/P1.5Y"), IntervalResolution.Day
  290. )
  291. self.assertEqual(
  292. get_interval_resolution("2018W01/P1.5Y"), IntervalResolution.Week
  293. )
  294. self.assertEqual(
  295. get_interval_resolution("2018-306/P1.5Y"), IntervalResolution.Ordinal
  296. )
  297. self.assertEqual(
  298. get_interval_resolution("2018W012/P1.5Y"), IntervalResolution.Weekday
  299. )
  300. def test_get_interval_resolution_time(self):
  301. self.assertEqual(
  302. get_interval_resolution("P1M/1981-04-05T01"), IntervalResolution.Hours
  303. )
  304. self.assertEqual(
  305. get_interval_resolution("P1M/1981-04-05T01:01"), IntervalResolution.Minutes
  306. )
  307. self.assertEqual(
  308. get_interval_resolution("P1M/1981-04-05T01:01:00"),
  309. IntervalResolution.Seconds,
  310. )
  311. self.assertEqual(
  312. get_interval_resolution("1981-04-05T01/P1M"), IntervalResolution.Hours
  313. )
  314. self.assertEqual(
  315. get_interval_resolution("1981-04-05T01:01/P1M"), IntervalResolution.Minutes
  316. )
  317. self.assertEqual(
  318. get_interval_resolution("1981-04-05T01:01:00/P1M"),
  319. IntervalResolution.Seconds,
  320. )
  321. def test_get_interval_resolution_duration(self):
  322. self.assertEqual(
  323. get_interval_resolution("2014-11-12/P1Y2M3D"), IntervalResolution.Day
  324. )
  325. self.assertEqual(
  326. get_interval_resolution("2014-11-12/P1Y2M"), IntervalResolution.Day
  327. )
  328. self.assertEqual(
  329. get_interval_resolution("2014-11-12/P1Y"), IntervalResolution.Day
  330. )
  331. self.assertEqual(
  332. get_interval_resolution("2014-11-12/P1W"), IntervalResolution.Day
  333. )
  334. self.assertEqual(
  335. get_interval_resolution("2014-11-12/P1Y2M3DT4H"), IntervalResolution.Hours
  336. )
  337. self.assertEqual(
  338. get_interval_resolution("2014-11-12/P1Y2M3DT4H54M"),
  339. IntervalResolution.Minutes,
  340. )
  341. self.assertEqual(
  342. get_interval_resolution("2014-11-12/P1Y2M3DT4H54M6S"),
  343. IntervalResolution.Seconds,
  344. )
  345. self.assertEqual(
  346. get_interval_resolution("P1Y2M3D/2014-11-12"), IntervalResolution.Day
  347. )
  348. self.assertEqual(
  349. get_interval_resolution("P1Y2M/2014-11-12"), IntervalResolution.Day
  350. )
  351. self.assertEqual(
  352. get_interval_resolution("P1Y/2014-11-12"), IntervalResolution.Day
  353. )
  354. self.assertEqual(
  355. get_interval_resolution("P1W/2014-11-12"), IntervalResolution.Day
  356. )
  357. self.assertEqual(
  358. get_interval_resolution("P1Y2M3DT4H/2014-11-12"), IntervalResolution.Hours
  359. )
  360. self.assertEqual(
  361. get_interval_resolution("P1Y2M3DT4H54M/2014-11-12"),
  362. IntervalResolution.Minutes,
  363. )
  364. self.assertEqual(
  365. get_interval_resolution("P1Y2M3DT4H54M6S/2014-11-12"),
  366. IntervalResolution.Seconds,
  367. )
  368. def test_parse_interval(self):
  369. testtuples = (
  370. (
  371. "P1M/1981-04-05T01:01:00",
  372. {
  373. "end": DatetimeTuple(
  374. DateTuple("1981", "04", "05", None, None, None),
  375. TimeTuple("01", "01", "00", None),
  376. ),
  377. "duration": DurationTuple(None, "1", None, None, None, None, None),
  378. },
  379. ),
  380. (
  381. "P1M/1981-04-05",
  382. {
  383. "end": DateTuple("1981", "04", "05", None, None, None),
  384. "duration": DurationTuple(None, "1", None, None, None, None, None),
  385. },
  386. ),
  387. (
  388. "P1,5Y/2018-03-06",
  389. {
  390. "end": DateTuple("2018", "03", "06", None, None, None),
  391. "duration": DurationTuple(
  392. "1.5", None, None, None, None, None, None
  393. ),
  394. },
  395. ),
  396. (
  397. "P1.5Y/2018-03-06",
  398. {
  399. "end": DateTuple("2018", "03", "06", None, None, None),
  400. "duration": DurationTuple(
  401. "1.5", None, None, None, None, None, None
  402. ),
  403. },
  404. ),
  405. (
  406. "PT1H/2014-11-12",
  407. {
  408. "end": DateTuple("2014", "11", "12", None, None, None),
  409. "duration": DurationTuple(None, None, None, None, "1", None, None),
  410. },
  411. ),
  412. (
  413. "PT4H54M6.5S/2014-11-12",
  414. {
  415. "end": DateTuple("2014", "11", "12", None, None, None),
  416. "duration": DurationTuple(None, None, None, None, "4", "54", "6.5"),
  417. },
  418. ),
  419. (
  420. "PT10H/2050-03-01T13:00:00Z",
  421. {
  422. "end": DatetimeTuple(
  423. DateTuple("2050", "03", "01", None, None, None),
  424. TimeTuple(
  425. "13",
  426. "00",
  427. "00",
  428. TimezoneTuple(False, True, None, None, "Z"),
  429. ),
  430. ),
  431. "duration": DurationTuple(None, None, None, None, "10", None, None),
  432. },
  433. ),
  434. # Make sure we truncate, not round
  435. # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
  436. (
  437. "PT0.0000001S/2018-03-06",
  438. {
  439. "end": DateTuple("2018", "03", "06", None, None, None),
  440. "duration": DurationTuple(
  441. None, None, None, None, None, None, "0.0000001"
  442. ),
  443. },
  444. ),
  445. (
  446. "PT2.0000048S/2018-03-06",
  447. {
  448. "end": DateTuple("2018", "03", "06", None, None, None),
  449. "duration": DurationTuple(
  450. None, None, None, None, None, None, "2.0000048"
  451. ),
  452. },
  453. ),
  454. (
  455. "1981-04-05T01:01:00/P1M1DT1M",
  456. {
  457. "start": DatetimeTuple(
  458. DateTuple("1981", "04", "05", None, None, None),
  459. TimeTuple("01", "01", "00", None),
  460. ),
  461. "duration": DurationTuple(None, "1", None, "1", None, "1", None),
  462. },
  463. ),
  464. (
  465. "1981-04-05/P1M1D",
  466. {
  467. "start": DateTuple("1981", "04", "05", None, None, None),
  468. "duration": DurationTuple(None, "1", None, "1", None, None, None),
  469. },
  470. ),
  471. (
  472. "2018-03-06/P2,5M",
  473. {
  474. "start": DateTuple("2018", "03", "06", None, None, None),
  475. "duration": DurationTuple(
  476. None, "2.5", None, None, None, None, None
  477. ),
  478. },
  479. ),
  480. (
  481. "2018-03-06/P2.5M",
  482. {
  483. "start": DateTuple("2018", "03", "06", None, None, None),
  484. "duration": DurationTuple(
  485. None, "2.5", None, None, None, None, None
  486. ),
  487. },
  488. ),
  489. (
  490. "2014-11-12/PT1H",
  491. {
  492. "start": DateTuple("2014", "11", "12", None, None, None),
  493. "duration": DurationTuple(None, None, None, None, "1", None, None),
  494. },
  495. ),
  496. (
  497. "2014-11-12/PT4H54M6.5S",
  498. {
  499. "start": DateTuple("2014", "11", "12", None, None, None),
  500. "duration": DurationTuple(None, None, None, None, "4", "54", "6.5"),
  501. },
  502. ),
  503. (
  504. "2050-03-01T13:00:00Z/PT10H",
  505. {
  506. "start": DatetimeTuple(
  507. DateTuple("2050", "03", "01", None, None, None),
  508. TimeTuple(
  509. "13",
  510. "00",
  511. "00",
  512. TimezoneTuple(False, True, None, None, "Z"),
  513. ),
  514. ),
  515. "duration": DurationTuple(None, None, None, None, "10", None, None),
  516. },
  517. ),
  518. # Make sure we truncate, not round
  519. # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
  520. (
  521. "2018-03-06/PT0.0000001S",
  522. {
  523. "start": DateTuple("2018", "03", "06", None, None, None),
  524. "duration": DurationTuple(
  525. None, None, None, None, None, None, "0.0000001"
  526. ),
  527. },
  528. ),
  529. (
  530. "2018-03-06/PT2.0000048S",
  531. {
  532. "start": DateTuple("2018", "03", "06", None, None, None),
  533. "duration": DurationTuple(
  534. None, None, None, None, None, None, "2.0000048"
  535. ),
  536. },
  537. ),
  538. (
  539. "1980-03-05T01:01:00/1981-04-05T01:01:00",
  540. {
  541. "start": DatetimeTuple(
  542. DateTuple("1980", "03", "05", None, None, None),
  543. TimeTuple("01", "01", "00", None),
  544. ),
  545. "end": DatetimeTuple(
  546. DateTuple("1981", "04", "05", None, None, None),
  547. TimeTuple("01", "01", "00", None),
  548. ),
  549. },
  550. ),
  551. (
  552. "1980-03-05T01:01:00/1981-04-05",
  553. {
  554. "start": DatetimeTuple(
  555. DateTuple("1980", "03", "05", None, None, None),
  556. TimeTuple("01", "01", "00", None),
  557. ),
  558. "end": DateTuple("1981", "04", "05", None, None, None),
  559. },
  560. ),
  561. (
  562. "1980-03-05/1981-04-05T01:01:00",
  563. {
  564. "start": DateTuple("1980", "03", "05", None, None, None),
  565. "end": DatetimeTuple(
  566. DateTuple("1981", "04", "05", None, None, None),
  567. TimeTuple("01", "01", "00", None),
  568. ),
  569. },
  570. ),
  571. (
  572. "1980-03-05/1981-04-05",
  573. {
  574. "start": DateTuple("1980", "03", "05", None, None, None),
  575. "end": DateTuple("1981", "04", "05", None, None, None),
  576. },
  577. ),
  578. (
  579. "1981-04-05/1980-03-05",
  580. {
  581. "start": DateTuple("1981", "04", "05", None, None, None),
  582. "end": DateTuple("1980", "03", "05", None, None, None),
  583. },
  584. ),
  585. (
  586. "2050-03-01T13:00:00Z/2050-05-11T15:30:00Z",
  587. {
  588. "start": DatetimeTuple(
  589. DateTuple("2050", "03", "01", None, None, None),
  590. TimeTuple(
  591. "13",
  592. "00",
  593. "00",
  594. TimezoneTuple(False, True, None, None, "Z"),
  595. ),
  596. ),
  597. "end": DatetimeTuple(
  598. DateTuple("2050", "05", "11", None, None, None),
  599. TimeTuple(
  600. "15",
  601. "30",
  602. "00",
  603. TimezoneTuple(False, True, None, None, "Z"),
  604. ),
  605. ),
  606. },
  607. ),
  608. # Test concise interval
  609. (
  610. "2020-01-01/02",
  611. {
  612. "start": DateTuple("2020", "01", "01", None, None, None),
  613. "end": DateTuple(None, None, "02", None, None, None),
  614. },
  615. ),
  616. (
  617. "2008-02-15/03-14",
  618. {
  619. "start": DateTuple("2008", "02", "15", None, None, None),
  620. "end": DateTuple(None, "03", "14", None, None, None),
  621. },
  622. ),
  623. (
  624. "2007-12-14T13:30/15:30",
  625. {
  626. "start": DatetimeTuple(
  627. DateTuple("2007", "12", "14", None, None, None),
  628. TimeTuple("13", "30", None, None),
  629. ),
  630. "end": TimeTuple("15", "30", None, None),
  631. },
  632. ),
  633. (
  634. "2007-11-13T09:00/15T17:00",
  635. {
  636. "start": DatetimeTuple(
  637. DateTuple("2007", "11", "13", None, None, None),
  638. TimeTuple("09", "00", None, None),
  639. ),
  640. "end": DatetimeTuple(
  641. DateTuple(None, None, "15", None, None, None),
  642. TimeTuple("17", "00", None, None),
  643. ),
  644. },
  645. ),
  646. (
  647. "2007-11-13T00:00/16T00:00",
  648. {
  649. "start": DatetimeTuple(
  650. DateTuple("2007", "11", "13", None, None, None),
  651. TimeTuple("00", "00", None, None),
  652. ),
  653. "end": DatetimeTuple(
  654. DateTuple(None, None, "16", None, None, None),
  655. TimeTuple("00", "00", None, None),
  656. ),
  657. },
  658. ),
  659. (
  660. "2007-11-13T09:00Z/15T17:00",
  661. {
  662. "start": DatetimeTuple(
  663. DateTuple("2007", "11", "13", None, None, None),
  664. TimeTuple(
  665. "09",
  666. "00",
  667. None,
  668. TimezoneTuple(False, True, None, None, "Z"),
  669. ),
  670. ),
  671. "end": DatetimeTuple(
  672. DateTuple(None, None, "15", None, None, None),
  673. TimeTuple("17", "00", None, None),
  674. ),
  675. },
  676. ),
  677. (
  678. "2007-11-13T00:00/12:34.567",
  679. {
  680. "start": DatetimeTuple(
  681. DateTuple("2007", "11", "13", None, None, None),
  682. TimeTuple("00", "00", None, None),
  683. ),
  684. "end": TimeTuple("12", "34.567", None, None),
  685. },
  686. ),
  687. # Make sure we truncate, not round
  688. # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
  689. (
  690. "1980-03-05T01:01:00.0000001/" "1981-04-05T14:43:59.9999997",
  691. {
  692. "start": DatetimeTuple(
  693. DateTuple("1980", "03", "05", None, None, None),
  694. TimeTuple("01", "01", "00.0000001", None),
  695. ),
  696. "end": DatetimeTuple(
  697. DateTuple("1981", "04", "05", None, None, None),
  698. TimeTuple("14", "43", "59.9999997", None),
  699. ),
  700. },
  701. ),
  702. )
  703. for testtuple in testtuples:
  704. with mock.patch.object(
  705. aniso8601.interval.PythonTimeBuilder, "build_interval"
  706. ) as mockBuildInterval:
  707. mockBuildInterval.return_value = testtuple[1]
  708. result = parse_interval(testtuple[0])
  709. self.assertEqual(result, testtuple[1])
  710. mockBuildInterval.assert_called_once_with(**testtuple[1])
  711. # Test different separators
  712. with mock.patch.object(
  713. aniso8601.interval.PythonTimeBuilder, "build_interval"
  714. ) as mockBuildInterval:
  715. expectedargs = {
  716. "start": DatetimeTuple(
  717. DateTuple("1980", "03", "05", None, None, None),
  718. TimeTuple("01", "01", "00", None),
  719. ),
  720. "end": DatetimeTuple(
  721. DateTuple("1981", "04", "05", None, None, None),
  722. TimeTuple("01", "01", "00", None),
  723. ),
  724. }
  725. mockBuildInterval.return_value = expectedargs
  726. result = parse_interval(
  727. "1980-03-05T01:01:00--1981-04-05T01:01:00", intervaldelimiter="--"
  728. )
  729. self.assertEqual(result, expectedargs)
  730. mockBuildInterval.assert_called_once_with(**expectedargs)
  731. with mock.patch.object(
  732. aniso8601.interval.PythonTimeBuilder, "build_interval"
  733. ) as mockBuildInterval:
  734. expectedargs = {
  735. "start": DatetimeTuple(
  736. DateTuple("1980", "03", "05", None, None, None),
  737. TimeTuple("01", "01", "00", None),
  738. ),
  739. "end": DatetimeTuple(
  740. DateTuple("1981", "04", "05", None, None, None),
  741. TimeTuple("01", "01", "00", None),
  742. ),
  743. }
  744. mockBuildInterval.return_value = expectedargs
  745. result = parse_interval(
  746. "1980-03-05 01:01:00/1981-04-05 01:01:00", datetimedelimiter=" "
  747. )
  748. self.assertEqual(result, expectedargs)
  749. mockBuildInterval.assert_called_once_with(**expectedargs)
  750. def test_parse_interval_mockbuilder(self):
  751. mockBuilder = mock.Mock()
  752. expectedargs = {
  753. "end": DatetimeTuple(
  754. DateTuple("1981", "04", "05", None, None, None),
  755. TimeTuple("01", "01", "00", None),
  756. ),
  757. "duration": DurationTuple(None, "1", None, None, None, None, None),
  758. }
  759. mockBuilder.build_interval.return_value = expectedargs
  760. result = parse_interval("P1M/1981-04-05T01:01:00", builder=mockBuilder)
  761. self.assertEqual(result, expectedargs)
  762. mockBuilder.build_interval.assert_called_once_with(**expectedargs)
  763. mockBuilder = mock.Mock()
  764. expectedargs = {
  765. "start": DateTuple("2014", "11", "12", None, None, None),
  766. "duration": DurationTuple(None, None, None, None, "1", None, None),
  767. }
  768. mockBuilder.build_interval.return_value = expectedargs
  769. result = parse_interval("2014-11-12/PT1H", builder=mockBuilder)
  770. self.assertEqual(result, expectedargs)
  771. mockBuilder.build_interval.assert_called_once_with(**expectedargs)
  772. mockBuilder = mock.Mock()
  773. expectedargs = {
  774. "start": DatetimeTuple(
  775. DateTuple("1980", "03", "05", None, None, None),
  776. TimeTuple("01", "01", "00", None),
  777. ),
  778. "end": DatetimeTuple(
  779. DateTuple("1981", "04", "05", None, None, None),
  780. TimeTuple("01", "01", "00", None),
  781. ),
  782. }
  783. mockBuilder.build_interval.return_value = expectedargs
  784. result = parse_interval(
  785. "1980-03-05T01:01:00/1981-04-05T01:01:00", builder=mockBuilder
  786. )
  787. self.assertEqual(result, expectedargs)
  788. mockBuilder.build_interval.assert_called_once_with(**expectedargs)
  789. def test_parse_interval_badtype(self):
  790. testtuples = (None, 1, False, 1.234)
  791. for testtuple in testtuples:
  792. with self.assertRaises(ValueError):
  793. parse_interval(testtuple, builder=None)
  794. def test_parse_interval_baddelimiter(self):
  795. testtuples = (
  796. "1980-03-05T01:01:00,1981-04-05T01:01:00",
  797. "P1M 1981-04-05T01:01:00",
  798. )
  799. for testtuple in testtuples:
  800. with self.assertRaises(ISOFormatError):
  801. parse_interval(testtuple, builder=None)
  802. def test_parse_interval_badstr(self):
  803. testtuples = ("/", "0/0/0", "20.50230/0", "5/%", "1/21", "bad", "")
  804. for testtuple in testtuples:
  805. with self.assertRaises(ISOFormatError):
  806. parse_interval(testtuple, builder=None)
  807. def test_parse_interval_repeating(self):
  808. # Parse interval can't parse repeating intervals
  809. with self.assertRaises(ISOFormatError):
  810. parse_interval("R3/1981-04-05/P1D")
  811. with self.assertRaises(ISOFormatError):
  812. parse_interval("R3/1981-04-05/P0003-06-04T12:30:05.5")
  813. with self.assertRaises(ISOFormatError):
  814. parse_interval("R/PT1H2M/1980-03-05T01:01:00")
  815. def test_parse_interval_suffixgarbage(self):
  816. # Don't allow garbage after the duration
  817. # https://bitbucket.org/nielsenb/aniso8601/issues/9/durations-with-trailing-garbage-are-parsed
  818. with self.assertRaises(ISOFormatError):
  819. parse_interval("2001/P1Dasdf", builder=None)
  820. with self.assertRaises(ISOFormatError):
  821. parse_interval("P1Dasdf/2001", builder=None)
  822. with self.assertRaises(ISOFormatError):
  823. parse_interval("2001/P0003-06-04T12:30:05.5asdfasdf", builder=None)
  824. with self.assertRaises(ISOFormatError):
  825. parse_interval("P0003-06-04T12:30:05.5asdfasdf/2001", builder=None)
  826. def test_parse_interval_internal(self):
  827. # Test the internal _parse_interval function
  828. testtuples = (
  829. (
  830. "P1M/1981-04-05T01:01:00",
  831. {
  832. "end": DatetimeTuple(
  833. DateTuple("1981", "04", "05", None, None, None),
  834. TimeTuple("01", "01", "00", None),
  835. ),
  836. "duration": DurationTuple(None, "1", None, None, None, None, None),
  837. },
  838. ),
  839. (
  840. "P1M/1981-04-05",
  841. {
  842. "end": DateTuple("1981", "04", "05", None, None, None),
  843. "duration": DurationTuple(None, "1", None, None, None, None, None),
  844. },
  845. ),
  846. (
  847. "P1,5Y/2018-03-06",
  848. {
  849. "end": DateTuple("2018", "03", "06", None, None, None),
  850. "duration": DurationTuple(
  851. "1.5", None, None, None, None, None, None
  852. ),
  853. },
  854. ),
  855. (
  856. "P1.5Y/2018-03-06",
  857. {
  858. "end": DateTuple("2018", "03", "06", None, None, None),
  859. "duration": DurationTuple(
  860. "1.5", None, None, None, None, None, None
  861. ),
  862. },
  863. ),
  864. (
  865. "PT1H/2014-11-12",
  866. {
  867. "end": DateTuple("2014", "11", "12", None, None, None),
  868. "duration": DurationTuple(None, None, None, None, "1", None, None),
  869. },
  870. ),
  871. (
  872. "PT4H54M6.5S/2014-11-12",
  873. {
  874. "end": DateTuple("2014", "11", "12", None, None, None),
  875. "duration": DurationTuple(None, None, None, None, "4", "54", "6.5"),
  876. },
  877. ),
  878. # Make sure we truncate, not round
  879. # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
  880. (
  881. "PT0.0000001S/2018-03-06",
  882. {
  883. "end": DateTuple("2018", "03", "06", None, None, None),
  884. "duration": DurationTuple(
  885. None, None, None, None, None, None, "0.0000001"
  886. ),
  887. },
  888. ),
  889. (
  890. "PT2.0000048S/2018-03-06",
  891. {
  892. "end": DateTuple("2018", "03", "06", None, None, None),
  893. "duration": DurationTuple(
  894. None, None, None, None, None, None, "2.0000048"
  895. ),
  896. },
  897. ),
  898. (
  899. "1981-04-05T01:01:00/P1M1DT1M",
  900. {
  901. "start": DatetimeTuple(
  902. DateTuple("1981", "04", "05", None, None, None),
  903. TimeTuple("01", "01", "00", None),
  904. ),
  905. "duration": DurationTuple(None, "1", None, "1", None, "1", None),
  906. },
  907. ),
  908. (
  909. "1981-04-05/P1M1D",
  910. {
  911. "start": DateTuple("1981", "04", "05", None, None, None),
  912. "duration": DurationTuple(None, "1", None, "1", None, None, None),
  913. },
  914. ),
  915. (
  916. "2018-03-06/P2,5M",
  917. {
  918. "start": DateTuple("2018", "03", "06", None, None, None),
  919. "duration": DurationTuple(
  920. None, "2.5", None, None, None, None, None
  921. ),
  922. },
  923. ),
  924. (
  925. "2018-03-06/P2.5M",
  926. {
  927. "start": DateTuple("2018", "03", "06", None, None, None),
  928. "duration": DurationTuple(
  929. None, "2.5", None, None, None, None, None
  930. ),
  931. },
  932. ),
  933. (
  934. "2014-11-12/PT1H",
  935. {
  936. "start": DateTuple("2014", "11", "12", None, None, None),
  937. "duration": DurationTuple(None, None, None, None, "1", None, None),
  938. },
  939. ),
  940. (
  941. "2014-11-12/PT4H54M6.5S",
  942. {
  943. "start": DateTuple("2014", "11", "12", None, None, None),
  944. "duration": DurationTuple(None, None, None, None, "4", "54", "6.5"),
  945. },
  946. ),
  947. # Make sure we truncate, not round
  948. # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
  949. (
  950. "2018-03-06/PT0.0000001S",
  951. {
  952. "start": DateTuple("2018", "03", "06", None, None, None),
  953. "duration": DurationTuple(
  954. None, None, None, None, None, None, "0.0000001"
  955. ),
  956. },
  957. ),
  958. (
  959. "2018-03-06/PT2.0000048S",
  960. {
  961. "start": DateTuple("2018", "03", "06", None, None, None),
  962. "duration": DurationTuple(
  963. None, None, None, None, None, None, "2.0000048"
  964. ),
  965. },
  966. ),
  967. (
  968. "1980-03-05T01:01:00/1981-04-05T01:01:00",
  969. {
  970. "start": DatetimeTuple(
  971. DateTuple("1980", "03", "05", None, None, None),
  972. TimeTuple("01", "01", "00", None),
  973. ),
  974. "end": DatetimeTuple(
  975. DateTuple("1981", "04", "05", None, None, None),
  976. TimeTuple("01", "01", "00", None),
  977. ),
  978. },
  979. ),
  980. (
  981. "1980-03-05T01:01:00/1981-04-05",
  982. {
  983. "start": DatetimeTuple(
  984. DateTuple("1980", "03", "05", None, None, None),
  985. TimeTuple("01", "01", "00", None),
  986. ),
  987. "end": DateTuple("1981", "04", "05", None, None, None),
  988. },
  989. ),
  990. (
  991. "1980-03-05/1981-04-05T01:01:00",
  992. {
  993. "start": DateTuple("1980", "03", "05", None, None, None),
  994. "end": DatetimeTuple(
  995. DateTuple("1981", "04", "05", None, None, None),
  996. TimeTuple("01", "01", "00", None),
  997. ),
  998. },
  999. ),
  1000. (
  1001. "1980-03-05/1981-04-05",
  1002. {
  1003. "start": DateTuple("1980", "03", "05", None, None, None),
  1004. "end": DateTuple("1981", "04", "05", None, None, None),
  1005. },
  1006. ),
  1007. (
  1008. "1981-04-05/1980-03-05",
  1009. {
  1010. "start": DateTuple("1981", "04", "05", None, None, None),
  1011. "end": DateTuple("1980", "03", "05", None, None, None),
  1012. },
  1013. ),
  1014. # Test concise interval
  1015. (
  1016. "2020-01-01/02",
  1017. {
  1018. "start": DateTuple("2020", "01", "01", None, None, None),
  1019. "end": DateTuple(None, None, "02", None, None, None),
  1020. },
  1021. ),
  1022. (
  1023. "2008-02-15/03-14",
  1024. {
  1025. "start": DateTuple("2008", "02", "15", None, None, None),
  1026. "end": DateTuple(None, "03", "14", None, None, None),
  1027. },
  1028. ),
  1029. (
  1030. "2007-12-14T13:30/15:30",
  1031. {
  1032. "start": DatetimeTuple(
  1033. DateTuple("2007", "12", "14", None, None, None),
  1034. TimeTuple("13", "30", None, None),
  1035. ),
  1036. "end": TimeTuple("15", "30", None, None),
  1037. },
  1038. ),
  1039. (
  1040. "2007-11-13T09:00/15T17:00",
  1041. {
  1042. "start": DatetimeTuple(
  1043. DateTuple("2007", "11", "13", None, None, None),
  1044. TimeTuple("09", "00", None, None),
  1045. ),
  1046. "end": DatetimeTuple(
  1047. DateTuple(None, None, "15", None, None, None),
  1048. TimeTuple("17", "00", None, None),
  1049. ),
  1050. },
  1051. ),
  1052. (
  1053. "2007-11-13T00:00/16T00:00",
  1054. {
  1055. "start": DatetimeTuple(
  1056. DateTuple("2007", "11", "13", None, None, None),
  1057. TimeTuple("00", "00", None, None),
  1058. ),
  1059. "end": DatetimeTuple(
  1060. DateTuple(None, None, "16", None, None, None),
  1061. TimeTuple("00", "00", None, None),
  1062. ),
  1063. },
  1064. ),
  1065. (
  1066. "2007-11-13T09:00Z/15T17:00",
  1067. {
  1068. "start": DatetimeTuple(
  1069. DateTuple("2007", "11", "13", None, None, None),
  1070. TimeTuple(
  1071. "09",
  1072. "00",
  1073. None,
  1074. TimezoneTuple(False, True, None, None, "Z"),
  1075. ),
  1076. ),
  1077. "end": DatetimeTuple(
  1078. DateTuple(None, None, "15", None, None, None),
  1079. TimeTuple("17", "00", None, None),
  1080. ),
  1081. },
  1082. ),
  1083. (
  1084. "2007-11-13T00:00/12:34.567",
  1085. {
  1086. "start": DatetimeTuple(
  1087. DateTuple("2007", "11", "13", None, None, None),
  1088. TimeTuple("00", "00", None, None),
  1089. ),
  1090. "end": TimeTuple("12", "34.567", None, None),
  1091. },
  1092. ),
  1093. # Make sure we truncate, not round
  1094. # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is
  1095. (
  1096. "1980-03-05T01:01:00.0000001/" "1981-04-05T14:43:59.9999997",
  1097. {
  1098. "start": DatetimeTuple(
  1099. DateTuple("1980", "03", "05", None, None, None),
  1100. TimeTuple("01", "01", "00.0000001", None),
  1101. ),
  1102. "end": DatetimeTuple(
  1103. DateTuple("1981", "04", "05", None, None, None),
  1104. TimeTuple("14", "43", "59.9999997", None),
  1105. ),
  1106. },
  1107. ),
  1108. )
  1109. for testtuple in testtuples:
  1110. mockBuilder = mock.Mock()
  1111. mockBuilder.build_interval.return_value = testtuple[1]
  1112. result = _parse_interval(testtuple[0], mockBuilder)
  1113. self.assertEqual(result, testtuple[1])
  1114. mockBuilder.build_interval.assert_called_once_with(**testtuple[1])
  1115. # Test different separators
  1116. expectedargs = {
  1117. "start": DatetimeTuple(
  1118. DateTuple("1980", "03", "05", None, None, None),
  1119. TimeTuple("01", "01", "00", None),
  1120. ),
  1121. "end": DatetimeTuple(
  1122. DateTuple("1981", "04", "05", None, None, None),
  1123. TimeTuple("01", "01", "00", None),
  1124. ),
  1125. }
  1126. mockBuilder = mock.Mock()
  1127. mockBuilder.build_interval.return_value = expectedargs
  1128. result = _parse_interval(
  1129. "1980-03-05T01:01:00--1981-04-05T01:01:00",
  1130. mockBuilder,
  1131. intervaldelimiter="--",
  1132. )
  1133. self.assertEqual(result, expectedargs)
  1134. mockBuilder.build_interval.assert_called_once_with(**expectedargs)
  1135. expectedargs = {
  1136. "start": DatetimeTuple(
  1137. DateTuple("1980", "03", "05", None, None, None),
  1138. TimeTuple("01", "01", "00", None),
  1139. ),
  1140. "end": DatetimeTuple(
  1141. DateTuple("1981", "04", "05", None, None, None),
  1142. TimeTuple("01", "01", "00", None),
  1143. ),
  1144. }
  1145. mockBuilder = mock.Mock()
  1146. mockBuilder.build_interval.return_value = expectedargs
  1147. _parse_interval(
  1148. "1980-03-05 01:01:00/1981-04-05 01:01:00",
  1149. mockBuilder,
  1150. datetimedelimiter=" ",
  1151. )
  1152. self.assertEqual(result, expectedargs)
  1153. mockBuilder.build_interval.assert_called_once_with(**expectedargs)
  1154. def test_parse_interval_end(self):
  1155. self.assertEqual(
  1156. _parse_interval_end(
  1157. "02", DateTuple("2020", "01", "01", None, None, None), "T"
  1158. ),
  1159. DateTuple(None, None, "02", None, None, None),
  1160. )
  1161. self.assertEqual(
  1162. _parse_interval_end(
  1163. "03-14", DateTuple("2008", "02", "15", None, None, None), "T"
  1164. ),
  1165. DateTuple(None, "03", "14", None, None, None),
  1166. )
  1167. self.assertEqual(
  1168. _parse_interval_end(
  1169. "0314", DateTuple("2008", "02", "15", None, None, None), "T"
  1170. ),
  1171. DateTuple(None, "03", "14", None, None, None),
  1172. )
  1173. self.assertEqual(
  1174. _parse_interval_end(
  1175. "15:30",
  1176. DatetimeTuple(
  1177. DateTuple("2007", "12", "14", None, None, None),
  1178. TimeTuple("13", "30", None, None),
  1179. ),
  1180. "T",
  1181. ),
  1182. TimeTuple("15", "30", None, None),
  1183. )
  1184. self.assertEqual(
  1185. _parse_interval_end(
  1186. "15T17:00",
  1187. DatetimeTuple(
  1188. DateTuple("2007", "11", "13", None, None, None),
  1189. TimeTuple("09", "00", None, None),
  1190. ),
  1191. "T",
  1192. ),
  1193. DatetimeTuple(
  1194. DateTuple(None, None, "15", None, None, None),
  1195. TimeTuple("17", "00", None, None),
  1196. ),
  1197. )
  1198. self.assertEqual(
  1199. _parse_interval_end(
  1200. "16T00:00",
  1201. DatetimeTuple(
  1202. DateTuple("2007", "11", "13", None, None, None),
  1203. TimeTuple("00", "00", None, None),
  1204. ),
  1205. "T",
  1206. ),
  1207. DatetimeTuple(
  1208. DateTuple(None, None, "16", None, None, None),
  1209. TimeTuple("00", "00", None, None),
  1210. ),
  1211. )
  1212. self.assertEqual(
  1213. _parse_interval_end(
  1214. "15 17:00",
  1215. DatetimeTuple(
  1216. DateTuple("2007", "11", "13", None, None, None),
  1217. TimeTuple("09", "00", None, None),
  1218. ),
  1219. " ",
  1220. ),
  1221. DatetimeTuple(
  1222. DateTuple(None, None, "15", None, None, None),
  1223. TimeTuple("17", "00", None, None),
  1224. ),
  1225. )
  1226. self.assertEqual(
  1227. _parse_interval_end(
  1228. "12:34.567",
  1229. DatetimeTuple(
  1230. DateTuple("2007", "11", "13", None, None, None),
  1231. TimeTuple("00", "00", None, None),
  1232. ),
  1233. "T",
  1234. ),
  1235. TimeTuple("12", "34.567", None, None),
  1236. )
  1237. class TestRepeatingIntervalParserFunctions(unittest.TestCase):
  1238. def test_get_interval_resolution_date(self):
  1239. self.assertEqual(
  1240. get_repeating_interval_resolution("R/P1.5Y/2018"), IntervalResolution.Year
  1241. )
  1242. self.assertEqual(
  1243. get_repeating_interval_resolution("R1/P1.5Y/2018-03"),
  1244. IntervalResolution.Month,
  1245. )
  1246. self.assertEqual(
  1247. get_repeating_interval_resolution("R2/P1.5Y/2018-03-06"),
  1248. IntervalResolution.Day,
  1249. )
  1250. self.assertEqual(
  1251. get_repeating_interval_resolution("R3/P1.5Y/2018W01"),
  1252. IntervalResolution.Week,
  1253. )
  1254. self.assertEqual(
  1255. get_repeating_interval_resolution("R4/P1.5Y/2018-306"),
  1256. IntervalResolution.Ordinal,
  1257. )
  1258. self.assertEqual(
  1259. get_repeating_interval_resolution("R5/P1.5Y/2018W012"),
  1260. IntervalResolution.Weekday,
  1261. )
  1262. self.assertEqual(
  1263. get_repeating_interval_resolution("R/2018/P1.5Y"), IntervalResolution.Year
  1264. )
  1265. self.assertEqual(
  1266. get_repeating_interval_resolution("R1/2018-03/P1.5Y"),
  1267. IntervalResolution.Month,
  1268. )
  1269. self.assertEqual(
  1270. get_repeating_interval_resolution("R2/2018-03-06/P1.5Y"),
  1271. IntervalResolution.Day,
  1272. )
  1273. self.assertEqual(
  1274. get_repeating_interval_resolution("R3/2018W01/P1.5Y"),
  1275. IntervalResolution.Week,
  1276. )
  1277. self.assertEqual(
  1278. get_repeating_interval_resolution("R4/2018-306/P1.5Y"),
  1279. IntervalResolution.Ordinal,
  1280. )
  1281. self.assertEqual(
  1282. get_repeating_interval_resolution("R5/2018W012/P1.5Y"),
  1283. IntervalResolution.Weekday,
  1284. )
  1285. def test_get_interval_resolution_time(self):
  1286. self.assertEqual(
  1287. get_repeating_interval_resolution("R/P1M/1981-04-05T01"),
  1288. IntervalResolution.Hours,
  1289. )
  1290. self.assertEqual(
  1291. get_repeating_interval_resolution("R1/P1M/1981-04-05T01:01"),
  1292. IntervalResolution.Minutes,
  1293. )
  1294. self.assertEqual(
  1295. get_repeating_interval_resolution("R2/P1M/1981-04-05T01:01:00"),
  1296. IntervalResolution.Seconds,
  1297. )
  1298. self.assertEqual(
  1299. get_repeating_interval_resolution("R/1981-04-05T01/P1M"),
  1300. IntervalResolution.Hours,
  1301. )
  1302. self.assertEqual(
  1303. get_repeating_interval_resolution("R1/1981-04-05T01:01/P1M"),
  1304. IntervalResolution.Minutes,
  1305. )
  1306. self.assertEqual(
  1307. get_repeating_interval_resolution("R2/1981-04-05T01:01:00/P1M"),
  1308. IntervalResolution.Seconds,
  1309. )
  1310. def test_get_interval_resolution_duration(self):
  1311. self.assertEqual(
  1312. get_repeating_interval_resolution("R/2014-11-12/P1Y2M3D"),
  1313. IntervalResolution.Day,
  1314. )
  1315. self.assertEqual(
  1316. get_repeating_interval_resolution("R1/2014-11-12/P1Y2M"),
  1317. IntervalResolution.Day,
  1318. )
  1319. self.assertEqual(
  1320. get_repeating_interval_resolution("R2/2014-11-12/P1Y"),
  1321. IntervalResolution.Day,
  1322. )
  1323. self.assertEqual(
  1324. get_repeating_interval_resolution("R3/2014-11-12/P1W"),
  1325. IntervalResolution.Day,
  1326. )
  1327. self.assertEqual(
  1328. get_repeating_interval_resolution("R4/2014-11-12/P1Y2M3DT4H"),
  1329. IntervalResolution.Hours,
  1330. )
  1331. self.assertEqual(
  1332. get_repeating_interval_resolution("R5/2014-11-12/P1Y2M3DT4H54M"),
  1333. IntervalResolution.Minutes,
  1334. )
  1335. self.assertEqual(
  1336. get_repeating_interval_resolution("R6/2014-11-12/P1Y2M3DT4H54M6S"),
  1337. IntervalResolution.Seconds,
  1338. )
  1339. self.assertEqual(
  1340. get_repeating_interval_resolution("R/P1Y2M3D/2014-11-12"),
  1341. IntervalResolution.Day,
  1342. )
  1343. self.assertEqual(
  1344. get_repeating_interval_resolution("R1/P1Y2M/2014-11-12"),
  1345. IntervalResolution.Day,
  1346. )
  1347. self.assertEqual(
  1348. get_repeating_interval_resolution("R2/P1Y/2014-11-12"),
  1349. IntervalResolution.Day,
  1350. )
  1351. self.assertEqual(
  1352. get_repeating_interval_resolution("R3/P1W/2014-11-12"),
  1353. IntervalResolution.Day,
  1354. )
  1355. self.assertEqual(
  1356. get_repeating_interval_resolution("R4/P1Y2M3DT4H/2014-11-12"),
  1357. IntervalResolution.Hours,
  1358. )
  1359. self.assertEqual(
  1360. get_repeating_interval_resolution("R5/P1Y2M3DT4H54M/2014-11-12"),
  1361. IntervalResolution.Minutes,
  1362. )
  1363. self.assertEqual(
  1364. get_repeating_interval_resolution("R6/P1Y2M3DT4H54M6S/2014-11-12"),
  1365. IntervalResolution.Seconds,
  1366. )
  1367. def test_parse_repeating_interval(self):
  1368. with mock.patch.object(
  1369. aniso8601.interval.PythonTimeBuilder, "build_repeating_interval"
  1370. ) as mockBuilder:
  1371. expectedargs = {
  1372. "R": False,
  1373. "Rnn": "3",
  1374. "interval": IntervalTuple(
  1375. DateTuple("1981", "04", "05", None, None, None),
  1376. None,
  1377. DurationTuple(None, None, None, "1", None, None, None),
  1378. ),
  1379. }
  1380. mockBuilder.return_value = expectedargs
  1381. result = parse_repeating_interval("R3/1981-04-05/P1D")
  1382. self.assertEqual(result, expectedargs)
  1383. mockBuilder.assert_called_once_with(**expectedargs)
  1384. with mock.patch.object(
  1385. aniso8601.interval.PythonTimeBuilder, "build_repeating_interval"
  1386. ) as mockBuilder:
  1387. expectedargs = {
  1388. "R": False,
  1389. "Rnn": "11",
  1390. "interval": IntervalTuple(
  1391. None,
  1392. DatetimeTuple(
  1393. DateTuple("1980", "03", "05", None, None, None),
  1394. TimeTuple("01", "01", "00", None),
  1395. ),
  1396. DurationTuple(None, None, None, None, "1", "2", None),
  1397. ),
  1398. }
  1399. mockBuilder.return_value = expectedargs
  1400. result = parse_repeating_interval("R11/PT1H2M/1980-03-05T01:01:00")
  1401. self.assertEqual(result, expectedargs)
  1402. mockBuilder.assert_called_once_with(**expectedargs)
  1403. with mock.patch.object(
  1404. aniso8601.interval.PythonTimeBuilder, "build_repeating_interval"
  1405. ) as mockBuilder:
  1406. expectedargs = {
  1407. "R": False,
  1408. "Rnn": "2",
  1409. "interval": IntervalTuple(
  1410. DatetimeTuple(
  1411. DateTuple("1980", "03", "05", None, None, None),
  1412. TimeTuple("01", "01", "00", None),
  1413. ),
  1414. DatetimeTuple(
  1415. DateTuple("1981", "04", "05", None, None, None),
  1416. TimeTuple("01", "01", "00", None),
  1417. ),
  1418. None,
  1419. ),
  1420. }
  1421. mockBuilder.return_value = expectedargs
  1422. result = parse_repeating_interval(
  1423. "R2--1980-03-05T01:01:00--" "1981-04-05T01:01:00",
  1424. intervaldelimiter="--",
  1425. )
  1426. self.assertEqual(result, expectedargs)
  1427. mockBuilder.assert_called_once_with(**expectedargs)
  1428. with mock.patch.object(
  1429. aniso8601.interval.PythonTimeBuilder, "build_repeating_interval"
  1430. ) as mockBuilder:
  1431. expectedargs = {
  1432. "R": False,
  1433. "Rnn": "2",
  1434. "interval": IntervalTuple(
  1435. DatetimeTuple(
  1436. DateTuple("1980", "03", "05", None, None, None),
  1437. TimeTuple("01", "01", "00", None),
  1438. ),
  1439. DatetimeTuple(
  1440. DateTuple("1981", "04", "05", None, None, None),
  1441. TimeTuple("01", "01", "00", None),
  1442. ),
  1443. None,
  1444. ),
  1445. }
  1446. mockBuilder.return_value = expectedargs
  1447. result = parse_repeating_interval(
  1448. "R2/" "1980-03-05 01:01:00/" "1981-04-05 01:01:00",
  1449. datetimedelimiter=" ",
  1450. )
  1451. self.assertEqual(result, expectedargs)
  1452. mockBuilder.assert_called_once_with(**expectedargs)
  1453. with mock.patch.object(
  1454. aniso8601.interval.PythonTimeBuilder, "build_repeating_interval"
  1455. ) as mockBuilder:
  1456. expectedargs = {
  1457. "R": True,
  1458. "Rnn": None,
  1459. "interval": IntervalTuple(
  1460. None,
  1461. DatetimeTuple(
  1462. DateTuple("1980", "03", "05", None, None, None),
  1463. TimeTuple("01", "01", "00", None),
  1464. ),
  1465. DurationTuple(None, None, None, None, "1", "2", None),
  1466. ),
  1467. }
  1468. mockBuilder.return_value = expectedargs
  1469. result = parse_repeating_interval("R/PT1H2M/1980-03-05T01:01:00")
  1470. self.assertEqual(result, expectedargs)
  1471. mockBuilder.assert_called_once_with(**expectedargs)
  1472. def test_parse_repeating_interval_mockbuilder(self):
  1473. mockBuilder = mock.Mock()
  1474. args = {
  1475. "R": False,
  1476. "Rnn": "3",
  1477. "interval": IntervalTuple(
  1478. DateTuple("1981", "04", "05", None, None, None),
  1479. None,
  1480. DurationTuple(None, None, None, "1", None, None, None),
  1481. ),
  1482. }
  1483. mockBuilder.build_repeating_interval.return_value = args
  1484. result = parse_repeating_interval("R3/1981-04-05/P1D", builder=mockBuilder)
  1485. self.assertEqual(result, args)
  1486. mockBuilder.build_repeating_interval.assert_called_once_with(**args)
  1487. mockBuilder = mock.Mock()
  1488. args = {
  1489. "R": False,
  1490. "Rnn": "11",
  1491. "interval": IntervalTuple(
  1492. None,
  1493. DatetimeTuple(
  1494. DateTuple("1980", "03", "05", None, None, None),
  1495. TimeTuple("01", "01", "00", None),
  1496. ),
  1497. DurationTuple(None, None, None, None, "1", "2", None),
  1498. ),
  1499. }
  1500. mockBuilder.build_repeating_interval.return_value = args
  1501. result = parse_repeating_interval(
  1502. "R11/PT1H2M/1980-03-05T01:01:00", builder=mockBuilder
  1503. )
  1504. self.assertEqual(result, args)
  1505. mockBuilder.build_repeating_interval.assert_called_once_with(**args)
  1506. mockBuilder = mock.Mock()
  1507. args = {
  1508. "R": True,
  1509. "Rnn": None,
  1510. "interval": IntervalTuple(
  1511. None,
  1512. DatetimeTuple(
  1513. DateTuple("1980", "03", "05", None, None, None),
  1514. TimeTuple("01", "01", "00", None),
  1515. ),
  1516. DurationTuple(None, None, None, None, "1", "2", None),
  1517. ),
  1518. }
  1519. mockBuilder.build_repeating_interval.return_value = args
  1520. result = parse_repeating_interval(
  1521. "R/PT1H2M/1980-03-05T01:01:00", builder=mockBuilder
  1522. )
  1523. self.assertEqual(result, args)
  1524. mockBuilder.build_repeating_interval.assert_called_once_with(**args)
  1525. def test_parse_repeating_interval_badtype(self):
  1526. testtuples = (None, 1, False, 1.234)
  1527. for testtuple in testtuples:
  1528. with self.assertRaises(ValueError):
  1529. parse_repeating_interval(testtuple, builder=None)
  1530. def test_parse_repeating_interval_baddelimiter(self):
  1531. testtuples = ("R,PT1H2M,1980-03-05T01:01:00", "R3 1981-04-05 P1D")
  1532. for testtuple in testtuples:
  1533. with self.assertRaises(ISOFormatError):
  1534. parse_repeating_interval(testtuple, builder=None)
  1535. def test_parse_repeating_interval_suffixgarbage(self):
  1536. # Don't allow garbage after the duration
  1537. # https://bitbucket.org/nielsenb/aniso8601/issues/9/durations-with-trailing-garbage-are-parsed
  1538. with self.assertRaises(ISOFormatError):
  1539. parse_repeating_interval("R3/1981-04-05/P1Dasdf", builder=None)
  1540. with self.assertRaises(ISOFormatError):
  1541. parse_repeating_interval(
  1542. "R3/" "1981-04-05/" "P0003-06-04T12:30:05.5asdfasdf", builder=None
  1543. )
  1544. def test_parse_repeating_interval_badstr(self):
  1545. testtuples = ("bad", "")
  1546. for testtuple in testtuples:
  1547. with self.assertRaises(ISOFormatError):
  1548. parse_repeating_interval(testtuple, builder=None)