test_time.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  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 DatetimeTuple, DateTuple, TimeTuple, TimezoneTuple
  10. from aniso8601.exceptions import ISOFormatError
  11. from aniso8601.resolution import TimeResolution
  12. from aniso8601.tests.compat import mock
  13. from aniso8601.time import (
  14. _get_time_resolution,
  15. get_datetime_resolution,
  16. get_time_resolution,
  17. parse_datetime,
  18. parse_time,
  19. )
  20. class TestTimeResolutionFunctions(unittest.TestCase):
  21. def test_get_time_resolution(self):
  22. self.assertEqual(get_time_resolution("01:23:45"), TimeResolution.Seconds)
  23. self.assertEqual(get_time_resolution("24:00:00"), TimeResolution.Seconds)
  24. self.assertEqual(get_time_resolution("23:21:28,512400"), TimeResolution.Seconds)
  25. self.assertEqual(get_time_resolution("23:21:28.512400"), TimeResolution.Seconds)
  26. self.assertEqual(get_time_resolution("01:23"), TimeResolution.Minutes)
  27. self.assertEqual(get_time_resolution("24:00"), TimeResolution.Minutes)
  28. self.assertEqual(get_time_resolution("01:23,4567"), TimeResolution.Minutes)
  29. self.assertEqual(get_time_resolution("01:23.4567"), TimeResolution.Minutes)
  30. self.assertEqual(get_time_resolution("012345"), TimeResolution.Seconds)
  31. self.assertEqual(get_time_resolution("240000"), TimeResolution.Seconds)
  32. self.assertEqual(get_time_resolution("0123"), TimeResolution.Minutes)
  33. self.assertEqual(get_time_resolution("2400"), TimeResolution.Minutes)
  34. self.assertEqual(get_time_resolution("01"), TimeResolution.Hours)
  35. self.assertEqual(get_time_resolution("24"), TimeResolution.Hours)
  36. self.assertEqual(get_time_resolution("12,5"), TimeResolution.Hours)
  37. self.assertEqual(get_time_resolution("12.5"), TimeResolution.Hours)
  38. self.assertEqual(
  39. get_time_resolution("232128.512400+00:00"), TimeResolution.Seconds
  40. )
  41. self.assertEqual(get_time_resolution("0123.4567+00:00"), TimeResolution.Minutes)
  42. self.assertEqual(get_time_resolution("01.4567+00:00"), TimeResolution.Hours)
  43. self.assertEqual(get_time_resolution("01:23:45+00:00"), TimeResolution.Seconds)
  44. self.assertEqual(get_time_resolution("24:00:00+00:00"), TimeResolution.Seconds)
  45. self.assertEqual(
  46. get_time_resolution("23:21:28.512400+00:00"), TimeResolution.Seconds
  47. )
  48. self.assertEqual(get_time_resolution("01:23+00:00"), TimeResolution.Minutes)
  49. self.assertEqual(get_time_resolution("24:00+00:00"), TimeResolution.Minutes)
  50. self.assertEqual(
  51. get_time_resolution("01:23.4567+00:00"), TimeResolution.Minutes
  52. )
  53. self.assertEqual(
  54. get_time_resolution("23:21:28.512400+11:15"), TimeResolution.Seconds
  55. )
  56. self.assertEqual(
  57. get_time_resolution("23:21:28.512400-12:34"), TimeResolution.Seconds
  58. )
  59. self.assertEqual(
  60. get_time_resolution("23:21:28.512400Z"), TimeResolution.Seconds
  61. )
  62. self.assertEqual(
  63. get_time_resolution("06:14:00.000123Z"), TimeResolution.Seconds
  64. )
  65. def test_get_datetime_resolution(self):
  66. self.assertEqual(
  67. get_datetime_resolution("2019-06-05T01:03:11.858714"),
  68. TimeResolution.Seconds,
  69. )
  70. self.assertEqual(
  71. get_datetime_resolution("2019-06-05T01:03:11"), TimeResolution.Seconds
  72. )
  73. self.assertEqual(
  74. get_datetime_resolution("2019-06-05T01:03"), TimeResolution.Minutes
  75. )
  76. self.assertEqual(get_datetime_resolution("2019-06-05T01"), TimeResolution.Hours)
  77. def test_get_time_resolution_badtype(self):
  78. testtuples = (None, 1, False, 1.234)
  79. for testtuple in testtuples:
  80. with self.assertRaises(ValueError):
  81. get_time_resolution(testtuple)
  82. def test_get_time_resolution_badstr(self):
  83. testtuples = ("A6:14:00.000123Z", "06:14:0B", "bad", "")
  84. for testtuple in testtuples:
  85. with self.assertRaises(ISOFormatError):
  86. get_time_resolution(testtuple)
  87. def test_get_time_resolution_internal(self):
  88. self.assertEqual(
  89. _get_time_resolution(TimeTuple(hh="01", mm="02", ss="03", tz=None)),
  90. TimeResolution.Seconds,
  91. )
  92. self.assertEqual(
  93. _get_time_resolution(TimeTuple(hh="01", mm="02", ss=None, tz=None)),
  94. TimeResolution.Minutes,
  95. )
  96. self.assertEqual(
  97. _get_time_resolution(TimeTuple(hh="01", mm=None, ss=None, tz=None)),
  98. TimeResolution.Hours,
  99. )
  100. class TestTimeParserFunctions(unittest.TestCase):
  101. def test_parse_time(self):
  102. testtuples = (
  103. ("01:23:45", {"hh": "01", "mm": "23", "ss": "45", "tz": None}),
  104. ("24:00:00", {"hh": "24", "mm": "00", "ss": "00", "tz": None}),
  105. (
  106. "23:21:28,512400",
  107. {"hh": "23", "mm": "21", "ss": "28.512400", "tz": None},
  108. ),
  109. (
  110. "23:21:28.512400",
  111. {"hh": "23", "mm": "21", "ss": "28.512400", "tz": None},
  112. ),
  113. (
  114. "01:03:11.858714",
  115. {"hh": "01", "mm": "03", "ss": "11.858714", "tz": None},
  116. ),
  117. (
  118. "14:43:59.9999997",
  119. {"hh": "14", "mm": "43", "ss": "59.9999997", "tz": None},
  120. ),
  121. ("01:23", {"hh": "01", "mm": "23", "ss": None, "tz": None}),
  122. ("24:00", {"hh": "24", "mm": "00", "ss": None, "tz": None}),
  123. ("01:23,4567", {"hh": "01", "mm": "23.4567", "ss": None, "tz": None}),
  124. ("01:23.4567", {"hh": "01", "mm": "23.4567", "ss": None, "tz": None}),
  125. ("012345", {"hh": "01", "mm": "23", "ss": "45", "tz": None}),
  126. ("240000", {"hh": "24", "mm": "00", "ss": "00", "tz": None}),
  127. ("232128,512400", {"hh": "23", "mm": "21", "ss": "28.512400", "tz": None}),
  128. ("232128.512400", {"hh": "23", "mm": "21", "ss": "28.512400", "tz": None}),
  129. ("010311.858714", {"hh": "01", "mm": "03", "ss": "11.858714", "tz": None}),
  130. (
  131. "144359.9999997",
  132. {"hh": "14", "mm": "43", "ss": "59.9999997", "tz": None},
  133. ),
  134. ("0123", {"hh": "01", "mm": "23", "ss": None, "tz": None}),
  135. ("2400", {"hh": "24", "mm": "00", "ss": None, "tz": None}),
  136. ("01", {"hh": "01", "mm": None, "ss": None, "tz": None}),
  137. ("24", {"hh": "24", "mm": None, "ss": None, "tz": None}),
  138. ("12,5", {"hh": "12.5", "mm": None, "ss": None, "tz": None}),
  139. ("12.5", {"hh": "12.5", "mm": None, "ss": None, "tz": None}),
  140. (
  141. "232128,512400+00:00",
  142. {
  143. "hh": "23",
  144. "mm": "21",
  145. "ss": "28.512400",
  146. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  147. },
  148. ),
  149. (
  150. "232128.512400+00:00",
  151. {
  152. "hh": "23",
  153. "mm": "21",
  154. "ss": "28.512400",
  155. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  156. },
  157. ),
  158. (
  159. "0123,4567+00:00",
  160. {
  161. "hh": "01",
  162. "mm": "23.4567",
  163. "ss": None,
  164. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  165. },
  166. ),
  167. (
  168. "0123.4567+00:00",
  169. {
  170. "hh": "01",
  171. "mm": "23.4567",
  172. "ss": None,
  173. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  174. },
  175. ),
  176. (
  177. "01,4567+00:00",
  178. {
  179. "hh": "01.4567",
  180. "mm": None,
  181. "ss": None,
  182. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  183. },
  184. ),
  185. (
  186. "01.4567+00:00",
  187. {
  188. "hh": "01.4567",
  189. "mm": None,
  190. "ss": None,
  191. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  192. },
  193. ),
  194. (
  195. "01:23:45+00:00",
  196. {
  197. "hh": "01",
  198. "mm": "23",
  199. "ss": "45",
  200. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  201. },
  202. ),
  203. (
  204. "24:00:00+00:00",
  205. {
  206. "hh": "24",
  207. "mm": "00",
  208. "ss": "00",
  209. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  210. },
  211. ),
  212. (
  213. "23:21:28.512400+00:00",
  214. {
  215. "hh": "23",
  216. "mm": "21",
  217. "ss": "28.512400",
  218. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  219. },
  220. ),
  221. (
  222. "01:23+00:00",
  223. {
  224. "hh": "01",
  225. "mm": "23",
  226. "ss": None,
  227. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  228. },
  229. ),
  230. (
  231. "24:00+00:00",
  232. {
  233. "hh": "24",
  234. "mm": "00",
  235. "ss": None,
  236. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  237. },
  238. ),
  239. (
  240. "01:23.4567+00:00",
  241. {
  242. "hh": "01",
  243. "mm": "23.4567",
  244. "ss": None,
  245. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  246. },
  247. ),
  248. (
  249. "23:21:28.512400+11:15",
  250. {
  251. "hh": "23",
  252. "mm": "21",
  253. "ss": "28.512400",
  254. "tz": TimezoneTuple(False, None, "11", "15", "+11:15"),
  255. },
  256. ),
  257. (
  258. "23:21:28.512400-12:34",
  259. {
  260. "hh": "23",
  261. "mm": "21",
  262. "ss": "28.512400",
  263. "tz": TimezoneTuple(True, None, "12", "34", "-12:34"),
  264. },
  265. ),
  266. (
  267. "23:21:28.512400Z",
  268. {
  269. "hh": "23",
  270. "mm": "21",
  271. "ss": "28.512400",
  272. "tz": TimezoneTuple(False, True, None, None, "Z"),
  273. },
  274. ),
  275. (
  276. "06:14:00.000123Z",
  277. {
  278. "hh": "06",
  279. "mm": "14",
  280. "ss": "00.000123",
  281. "tz": TimezoneTuple(False, True, None, None, "Z"),
  282. },
  283. ),
  284. )
  285. for testtuple in testtuples:
  286. with mock.patch.object(
  287. aniso8601.time.PythonTimeBuilder, "build_time"
  288. ) as mockBuildTime:
  289. mockBuildTime.return_value = testtuple[1]
  290. result = parse_time(testtuple[0])
  291. self.assertEqual(result, testtuple[1])
  292. mockBuildTime.assert_called_once_with(**testtuple[1])
  293. def test_parse_time_badtype(self):
  294. testtuples = (None, 1, False, 1.234)
  295. for testtuple in testtuples:
  296. with self.assertRaises(ValueError):
  297. parse_time(testtuple, builder=None)
  298. def test_parse_time_badstr(self):
  299. testtuples = (
  300. "A6:14:00.000123Z",
  301. "06:14:0B",
  302. "06:1 :02",
  303. "0000,70:24,9",
  304. "00.27:5332",
  305. "bad",
  306. "",
  307. )
  308. for testtuple in testtuples:
  309. with self.assertRaises(ISOFormatError):
  310. parse_time(testtuple, builder=None)
  311. def test_parse_time_mockbuilder(self):
  312. mockBuilder = mock.Mock()
  313. expectedargs = {"hh": "01", "mm": "23", "ss": "45", "tz": None}
  314. mockBuilder.build_time.return_value = expectedargs
  315. result = parse_time("01:23:45", builder=mockBuilder)
  316. self.assertEqual(result, expectedargs)
  317. mockBuilder.build_time.assert_called_once_with(**expectedargs)
  318. mockBuilder = mock.Mock()
  319. expectedargs = {
  320. "hh": "23",
  321. "mm": "21",
  322. "ss": "28.512400",
  323. "tz": TimezoneTuple(False, None, "00", "00", "+00:00"),
  324. }
  325. mockBuilder.build_time.return_value = expectedargs
  326. result = parse_time("232128.512400+00:00", builder=mockBuilder)
  327. self.assertEqual(result, expectedargs)
  328. mockBuilder.build_time.assert_called_once_with(**expectedargs)
  329. mockBuilder = mock.Mock()
  330. expectedargs = {
  331. "hh": "23",
  332. "mm": "21",
  333. "ss": "28.512400",
  334. "tz": TimezoneTuple(False, None, "11", "15", "+11:15"),
  335. }
  336. mockBuilder.build_time.return_value = expectedargs
  337. result = parse_time("23:21:28.512400+11:15", builder=mockBuilder)
  338. self.assertEqual(result, expectedargs)
  339. mockBuilder.build_time.assert_called_once_with(**expectedargs)
  340. def test_parse_datetime(self):
  341. testtuples = (
  342. (
  343. "2019-06-05T01:03:11,858714",
  344. (
  345. DateTuple("2019", "06", "05", None, None, None),
  346. TimeTuple("01", "03", "11.858714", None),
  347. ),
  348. ),
  349. (
  350. "2019-06-05T01:03:11.858714",
  351. (
  352. DateTuple("2019", "06", "05", None, None, None),
  353. TimeTuple("01", "03", "11.858714", None),
  354. ),
  355. ),
  356. (
  357. "1981-04-05T23:21:28.512400Z",
  358. (
  359. DateTuple("1981", "04", "05", None, None, None),
  360. TimeTuple(
  361. "23",
  362. "21",
  363. "28.512400",
  364. TimezoneTuple(False, True, None, None, "Z"),
  365. ),
  366. ),
  367. ),
  368. (
  369. "1981095T23:21:28.512400-12:34",
  370. (
  371. DateTuple("1981", None, None, None, None, "095"),
  372. TimeTuple(
  373. "23",
  374. "21",
  375. "28.512400",
  376. TimezoneTuple(True, None, "12", "34", "-12:34"),
  377. ),
  378. ),
  379. ),
  380. (
  381. "19810405T23:21:28+00",
  382. (
  383. DateTuple("1981", "04", "05", None, None, None),
  384. TimeTuple(
  385. "23", "21", "28", TimezoneTuple(False, None, "00", None, "+00")
  386. ),
  387. ),
  388. ),
  389. (
  390. "19810405T23:21:28+00:00",
  391. (
  392. DateTuple("1981", "04", "05", None, None, None),
  393. TimeTuple(
  394. "23",
  395. "21",
  396. "28",
  397. TimezoneTuple(False, None, "00", "00", "+00:00"),
  398. ),
  399. ),
  400. ),
  401. )
  402. for testtuple in testtuples:
  403. with mock.patch.object(
  404. aniso8601.time.PythonTimeBuilder, "build_datetime"
  405. ) as mockBuildDateTime:
  406. mockBuildDateTime.return_value = testtuple[1]
  407. result = parse_datetime(testtuple[0])
  408. self.assertEqual(result, testtuple[1])
  409. mockBuildDateTime.assert_called_once_with(*testtuple[1])
  410. def test_parse_datetime_spacedelimited(self):
  411. expectedargs = (
  412. DateTuple("2004", None, None, "53", "6", None),
  413. TimeTuple(
  414. "23", "21", "28.512400", TimezoneTuple(True, None, "12", "34", "-12:34")
  415. ),
  416. )
  417. with mock.patch.object(
  418. aniso8601.time.PythonTimeBuilder, "build_datetime"
  419. ) as mockBuildDateTime:
  420. mockBuildDateTime.return_value = expectedargs
  421. result = parse_datetime("2004-W53-6 23:21:28.512400-12:34", delimiter=" ")
  422. self.assertEqual(result, expectedargs)
  423. mockBuildDateTime.assert_called_once_with(*expectedargs)
  424. def test_parse_datetime_commadelimited(self):
  425. expectedargs = (
  426. DateTuple("1981", "04", "05", None, None, None),
  427. TimeTuple(
  428. "23", "21", "28.512400", TimezoneTuple(False, True, None, None, "Z")
  429. ),
  430. )
  431. with mock.patch.object(
  432. aniso8601.time.PythonTimeBuilder, "build_datetime"
  433. ) as mockBuildDateTime:
  434. mockBuildDateTime.return_value = expectedargs
  435. result = parse_datetime("1981-04-05,23:21:28,512400Z", delimiter=",")
  436. self.assertEqual(result, expectedargs)
  437. mockBuildDateTime.assert_called_once_with(*expectedargs)
  438. def test_parse_datetime_baddelimiter(self):
  439. testtuples = (
  440. "1981-04-05,23:21:28,512400Z",
  441. "2004-W53-6 23:21:28.512400-12:3",
  442. "1981040523:21:28",
  443. )
  444. for testtuple in testtuples:
  445. with self.assertRaises(ISOFormatError):
  446. parse_datetime(testtuple, builder=None)
  447. def test_parse_datetime_badtype(self):
  448. testtuples = (None, 1, False, 1.234)
  449. for testtuple in testtuples:
  450. with self.assertRaises(ValueError):
  451. parse_datetime(testtuple, builder=None)
  452. def test_parse_datetime_badstr(self):
  453. testtuples = (
  454. "1981-04-05TA6:14:00.000123Z",
  455. "2004-W53-6T06:14:0B",
  456. "2014-01-230T23:21:28+00",
  457. "201401230T01:03:11.858714",
  458. "9999 W53T49",
  459. "9T0000,70:24,9",
  460. "bad",
  461. "",
  462. )
  463. for testtuple in testtuples:
  464. with self.assertRaises(ISOFormatError):
  465. parse_datetime(testtuple, builder=None)
  466. def test_parse_datetime_mockbuilder(self):
  467. mockBuilder = mock.Mock()
  468. expectedargs = (
  469. DateTuple("1981", None, None, None, None, "095"),
  470. TimeTuple(
  471. "23", "21", "28.512400", TimezoneTuple(True, None, "12", "34", "-12:34")
  472. ),
  473. )
  474. mockBuilder.build_datetime.return_value = expectedargs
  475. result = parse_datetime("1981095T23:21:28.512400-12:34", builder=mockBuilder)
  476. self.assertEqual(result, expectedargs)
  477. mockBuilder.build_datetime.assert_called_once_with(*expectedargs)