METADATA 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. Metadata-Version: 2.1
  2. Name: aniso8601
  3. Version: 9.0.1
  4. Summary: A library for parsing ISO 8601 strings.
  5. Home-page: https://bitbucket.org/nielsenb/aniso8601
  6. Author: Brandon Nielsen
  7. Author-email: nielsenb@jetfuse.net
  8. License: UNKNOWN
  9. Project-URL: Documentation, https://aniso8601.readthedocs.io/
  10. Project-URL: Source, https://bitbucket.org/nielsenb/aniso8601
  11. Project-URL: Tracker, https://bitbucket.org/nielsenb/aniso8601/issues
  12. Keywords: iso8601 parser
  13. Platform: UNKNOWN
  14. Classifier: Development Status :: 5 - Production/Stable
  15. Classifier: Intended Audience :: Developers
  16. Classifier: License :: OSI Approved :: BSD License
  17. Classifier: Operating System :: OS Independent
  18. Classifier: Programming Language :: Python
  19. Classifier: Programming Language :: Python :: 2
  20. Classifier: Programming Language :: Python :: 2.7
  21. Classifier: Programming Language :: Python :: 3
  22. Classifier: Programming Language :: Python :: 3.4
  23. Classifier: Programming Language :: Python :: 3.5
  24. Classifier: Programming Language :: Python :: 3.6
  25. Classifier: Programming Language :: Python :: 3.7
  26. Classifier: Programming Language :: Python :: 3.8
  27. Classifier: Programming Language :: Python :: 3.9
  28. Classifier: Topic :: Software Development :: Libraries :: Python Modules
  29. Description-Content-Type: text/x-rst
  30. Provides-Extra: dev
  31. Requires-Dist: black ; extra == 'dev'
  32. Requires-Dist: coverage ; extra == 'dev'
  33. Requires-Dist: isort ; extra == 'dev'
  34. Requires-Dist: pre-commit ; extra == 'dev'
  35. Requires-Dist: pyenchant ; extra == 'dev'
  36. Requires-Dist: pylint ; extra == 'dev'
  37. aniso8601
  38. =========
  39. Another ISO 8601 parser for Python
  40. ----------------------------------
  41. Features
  42. ========
  43. * Pure Python implementation
  44. * Logical behavior
  45. - Parse a time, get a `datetime.time <http://docs.python.org/3/library/datetime.html#datetime.time>`_
  46. - Parse a date, get a `datetime.date <http://docs.python.org/3/library/datetime.html#datetime.date>`_
  47. - Parse a datetime, get a `datetime.datetime <http://docs.python.org/3/library/datetime.html#datetime.datetime>`_
  48. - Parse a duration, get a `datetime.timedelta <http://docs.python.org/3/library/datetime.html#datetime.timedelta>`_
  49. - Parse an interval, get a tuple of dates or datetimes
  50. - Parse a repeating interval, get a date or datetime `generator <https://wiki.python.org/moin/Generators>`_
  51. * UTC offset represented as fixed-offset tzinfo
  52. * Parser separate from representation, allowing parsing to different datetime representations (see `Builders`_)
  53. * No regular expressions
  54. Installation
  55. ============
  56. The recommended installation method is to use pip::
  57. $ pip install aniso8601
  58. Alternatively, you can download the source (git repository hosted at `Bitbucket <https://bitbucket.org/nielsenb/aniso8601>`_) and install directly::
  59. $ python setup.py install
  60. Use
  61. ===
  62. Parsing datetimes
  63. -----------------
  64. *Consider* `datetime.datetime.fromisoformat <https://docs.python.org/3/library/datetime.html#datetime.datetime.fromisoformat>`_ *for basic ISO 8601 datetime parsing*
  65. To parse a typical ISO 8601 datetime string::
  66. >>> import aniso8601
  67. >>> aniso8601.parse_datetime('1977-06-10T12:00:00Z')
  68. datetime.datetime(1977, 6, 10, 12, 0, tzinfo=+0:00:00 UTC)
  69. Alternative delimiters can be specified, for example, a space::
  70. >>> aniso8601.parse_datetime('1977-06-10 12:00:00Z', delimiter=' ')
  71. datetime.datetime(1977, 6, 10, 12, 0, tzinfo=+0:00:00 UTC)
  72. UTC offsets are supported::
  73. >>> aniso8601.parse_datetime('1979-06-05T08:00:00-08:00')
  74. datetime.datetime(1979, 6, 5, 8, 0, tzinfo=-8:00:00 UTC)
  75. If a UTC offset is not specified, the returned datetime will be naive::
  76. >>> aniso8601.parse_datetime('1983-01-22T08:00:00')
  77. datetime.datetime(1983, 1, 22, 8, 0)
  78. Leap seconds are currently not supported and attempting to parse one raises a :code:`LeapSecondError`::
  79. >>> aniso8601.parse_datetime('2018-03-06T23:59:60')
  80. Traceback (most recent call last):
  81. File "<stdin>", line 1, in <module>
  82. File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/time.py", line 196, in parse_datetime
  83. return builder.build_datetime(datepart, timepart)
  84. File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/python.py", line 237, in build_datetime
  85. cls._build_object(time))
  86. File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/__init__.py", line 336, in _build_object
  87. return cls.build_time(hh=parsetuple.hh, mm=parsetuple.mm,
  88. File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/python.py", line 191, in build_time
  89. hh, mm, ss, tz = cls.range_check_time(hh, mm, ss, tz)
  90. File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/__init__.py", line 266, in range_check_time
  91. raise LeapSecondError('Leap seconds are not supported.')
  92. aniso8601.exceptions.LeapSecondError: Leap seconds are not supported.
  93. To get the resolution of an ISO 8601 datetime string::
  94. >>> aniso8601.get_datetime_resolution('1977-06-10T12:00:00Z') == aniso8601.resolution.TimeResolution.Seconds
  95. True
  96. >>> aniso8601.get_datetime_resolution('1977-06-10T12:00') == aniso8601.resolution.TimeResolution.Minutes
  97. True
  98. >>> aniso8601.get_datetime_resolution('1977-06-10T12') == aniso8601.resolution.TimeResolution.Hours
  99. True
  100. Note that datetime resolutions map to :code:`TimeResolution` as a valid datetime must have at least one time member so the resolution mapping is equivalent.
  101. Parsing dates
  102. -------------
  103. *Consider* `datetime.date.fromisoformat <https://docs.python.org/3/library/datetime.html#datetime.date.fromisoformat>`_ *for basic ISO 8601 date parsing*
  104. To parse a date represented in an ISO 8601 string::
  105. >>> import aniso8601
  106. >>> aniso8601.parse_date('1984-04-23')
  107. datetime.date(1984, 4, 23)
  108. Basic format is supported as well::
  109. >>> aniso8601.parse_date('19840423')
  110. datetime.date(1984, 4, 23)
  111. To parse a date using the ISO 8601 week date format::
  112. >>> aniso8601.parse_date('1986-W38-1')
  113. datetime.date(1986, 9, 15)
  114. To parse an ISO 8601 ordinal date::
  115. >>> aniso8601.parse_date('1988-132')
  116. datetime.date(1988, 5, 11)
  117. To get the resolution of an ISO 8601 date string::
  118. >>> aniso8601.get_date_resolution('1981-04-05') == aniso8601.resolution.DateResolution.Day
  119. True
  120. >>> aniso8601.get_date_resolution('1981-04') == aniso8601.resolution.DateResolution.Month
  121. True
  122. >>> aniso8601.get_date_resolution('1981') == aniso8601.resolution.DateResolution.Year
  123. True
  124. Parsing times
  125. -------------
  126. *Consider* `datetime.time.fromisoformat <https://docs.python.org/3/library/datetime.html#datetime.time.fromisoformat>`_ *for basic ISO 8601 time parsing*
  127. To parse a time formatted as an ISO 8601 string::
  128. >>> import aniso8601
  129. >>> aniso8601.parse_time('11:31:14')
  130. datetime.time(11, 31, 14)
  131. As with all of the above, basic format is supported::
  132. >>> aniso8601.parse_time('113114')
  133. datetime.time(11, 31, 14)
  134. A UTC offset can be specified for times::
  135. >>> aniso8601.parse_time('17:18:19-02:30')
  136. datetime.time(17, 18, 19, tzinfo=-2:30:00 UTC)
  137. >>> aniso8601.parse_time('171819Z')
  138. datetime.time(17, 18, 19, tzinfo=+0:00:00 UTC)
  139. Reduced accuracy is supported::
  140. >>> aniso8601.parse_time('21:42')
  141. datetime.time(21, 42)
  142. >>> aniso8601.parse_time('22')
  143. datetime.time(22, 0)
  144. A decimal fraction is always allowed on the lowest order element of an ISO 8601 formatted time::
  145. >>> aniso8601.parse_time('22:33.5')
  146. datetime.time(22, 33, 30)
  147. >>> aniso8601.parse_time('23.75')
  148. datetime.time(23, 45)
  149. The decimal fraction can be specified with a comma instead of a full-stop::
  150. >>> aniso8601.parse_time('22:33,5')
  151. datetime.time(22, 33, 30)
  152. >>> aniso8601.parse_time('23,75')
  153. datetime.time(23, 45)
  154. Leap seconds are currently not supported and attempting to parse one raises a :code:`LeapSecondError`::
  155. >>> aniso8601.parse_time('23:59:60')
  156. Traceback (most recent call last):
  157. File "<stdin>", line 1, in <module>
  158. File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/time.py", line 174, in parse_time
  159. return builder.build_time(hh=hourstr, mm=minutestr, ss=secondstr, tz=tz)
  160. File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/python.py", line 191, in build_time
  161. hh, mm, ss, tz = cls.range_check_time(hh, mm, ss, tz)
  162. File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/__init__.py", line 266, in range_check_time
  163. raise LeapSecondError('Leap seconds are not supported.')
  164. aniso8601.exceptions.LeapSecondError: Leap seconds are not supported.
  165. To get the resolution of an ISO 8601 time string::
  166. >>> aniso8601.get_time_resolution('11:31:14') == aniso8601.resolution.TimeResolution.Seconds
  167. True
  168. >>> aniso8601.get_time_resolution('11:31') == aniso8601.resolution.TimeResolution.Minutes
  169. True
  170. >>> aniso8601.get_time_resolution('11') == aniso8601.resolution.TimeResolution.Hours
  171. True
  172. Parsing durations
  173. -----------------
  174. To parse a duration formatted as an ISO 8601 string::
  175. >>> import aniso8601
  176. >>> aniso8601.parse_duration('P1Y2M3DT4H54M6S')
  177. datetime.timedelta(428, 17646)
  178. Reduced accuracy is supported::
  179. >>> aniso8601.parse_duration('P1Y')
  180. datetime.timedelta(365)
  181. A decimal fraction is allowed on the lowest order element::
  182. >>> aniso8601.parse_duration('P1YT3.5M')
  183. datetime.timedelta(365, 210)
  184. The decimal fraction can be specified with a comma instead of a full-stop::
  185. >>> aniso8601.parse_duration('P1YT3,5M')
  186. datetime.timedelta(365, 210)
  187. Parsing a duration from a combined date and time is supported as well::
  188. >>> aniso8601.parse_duration('P0001-01-02T01:30:05')
  189. datetime.timedelta(397, 5405)
  190. To get the resolution of an ISO 8601 duration string::
  191. >>> aniso8601.get_duration_resolution('P1Y2M3DT4H54M6S') == aniso8601.resolution.DurationResolution.Seconds
  192. True
  193. >>> aniso8601.get_duration_resolution('P1Y2M3DT4H54M') == aniso8601.resolution.DurationResolution.Minutes
  194. True
  195. >>> aniso8601.get_duration_resolution('P1Y2M3DT4H') == aniso8601.resolution.DurationResolution.Hours
  196. True
  197. >>> aniso8601.get_duration_resolution('P1Y2M3D') == aniso8601.resolution.DurationResolution.Days
  198. True
  199. >>> aniso8601.get_duration_resolution('P1Y2M') == aniso8601.resolution.DurationResolution.Months
  200. True
  201. >>> aniso8601.get_duration_resolution('P1Y') == aniso8601.resolution.DurationResolution.Years
  202. True
  203. The default :code:`PythonTimeBuilder` assumes years are 365 days, and months are 30 days. Where calendar level accuracy is required, a `RelativeTimeBuilder <https://bitbucket.org/nielsenb/relativetimebuilder>`_ can be used, see also `Builders`_.
  204. Parsing intervals
  205. -----------------
  206. To parse an interval specified by a start and end::
  207. >>> import aniso8601
  208. >>> aniso8601.parse_interval('2007-03-01T13:00:00/2008-05-11T15:30:00')
  209. (datetime.datetime(2007, 3, 1, 13, 0), datetime.datetime(2008, 5, 11, 15, 30))
  210. Intervals specified by a start time and a duration are supported::
  211. >>> aniso8601.parse_interval('2007-03-01T13:00:00Z/P1Y2M10DT2H30M')
  212. (datetime.datetime(2007, 3, 1, 13, 0, tzinfo=+0:00:00 UTC), datetime.datetime(2008, 5, 9, 15, 30, tzinfo=+0:00:00 UTC))
  213. A duration can also be specified by a duration and end time::
  214. >>> aniso8601.parse_interval('P1M/1981-04-05')
  215. (datetime.date(1981, 4, 5), datetime.date(1981, 3, 6))
  216. Notice that the result of the above parse is not in order from earliest to latest. If sorted intervals are required, simply use the :code:`sorted` keyword as shown below::
  217. >>> sorted(aniso8601.parse_interval('P1M/1981-04-05'))
  218. [datetime.date(1981, 3, 6), datetime.date(1981, 4, 5)]
  219. The end of an interval is returned as a datetime when required to maintain the resolution specified by a duration, even if the duration start is given as a date::
  220. >>> aniso8601.parse_interval('2014-11-12/PT4H54M6.5S')
  221. (datetime.date(2014, 11, 12), datetime.datetime(2014, 11, 12, 4, 54, 6, 500000))
  222. >>> aniso8601.parse_interval('2007-03-01/P1.5D')
  223. (datetime.date(2007, 3, 1), datetime.datetime(2007, 3, 2, 12, 0))
  224. Concise representations are supported::
  225. >>> aniso8601.parse_interval('2020-01-01/02')
  226. (datetime.date(2020, 1, 1), datetime.date(2020, 1, 2))
  227. >>> aniso8601.parse_interval('2007-12-14T13:30/15:30')
  228. (datetime.datetime(2007, 12, 14, 13, 30), datetime.datetime(2007, 12, 14, 15, 30))
  229. >>> aniso8601.parse_interval('2008-02-15/03-14')
  230. (datetime.date(2008, 2, 15), datetime.date(2008, 3, 14))
  231. >>> aniso8601.parse_interval('2007-11-13T09:00/15T17:00')
  232. (datetime.datetime(2007, 11, 13, 9, 0), datetime.datetime(2007, 11, 15, 17, 0))
  233. Repeating intervals are supported as well, and return a `generator <https://wiki.python.org/moin/Generators>`_::
  234. >>> aniso8601.parse_repeating_interval('R3/1981-04-05/P1D')
  235. <generator object _date_generator at 0x7fd800d3b320>
  236. >>> list(aniso8601.parse_repeating_interval('R3/1981-04-05/P1D'))
  237. [datetime.date(1981, 4, 5), datetime.date(1981, 4, 6), datetime.date(1981, 4, 7)]
  238. Repeating intervals are allowed to go in the reverse direction::
  239. >>> list(aniso8601.parse_repeating_interval('R2/PT1H2M/1980-03-05T01:01:00'))
  240. [datetime.datetime(1980, 3, 5, 1, 1), datetime.datetime(1980, 3, 4, 23, 59)]
  241. Unbounded intervals are also allowed (Python 2)::
  242. >>> result = aniso8601.parse_repeating_interval('R/PT1H2M/1980-03-05T01:01:00')
  243. >>> result.next()
  244. datetime.datetime(1980, 3, 5, 1, 1)
  245. >>> result.next()
  246. datetime.datetime(1980, 3, 4, 23, 59)
  247. or for Python 3::
  248. >>> result = aniso8601.parse_repeating_interval('R/PT1H2M/1980-03-05T01:01:00')
  249. >>> next(result)
  250. datetime.datetime(1980, 3, 5, 1, 1)
  251. >>> next(result)
  252. datetime.datetime(1980, 3, 4, 23, 59)
  253. Note that you should never try to convert a generator produced by an unbounded interval to a list::
  254. >>> list(aniso8601.parse_repeating_interval('R/PT1H2M/1980-03-05T01:01:00'))
  255. Traceback (most recent call last):
  256. File "<stdin>", line 1, in <module>
  257. File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/python.py", line 560, in _date_generator_unbounded
  258. currentdate += timedelta
  259. OverflowError: date value out of range
  260. To get the resolution of an ISO 8601 interval string::
  261. >>> aniso8601.get_interval_resolution('2007-03-01T13:00:00/2008-05-11T15:30:00') == aniso8601.resolution.IntervalResolution.Seconds
  262. True
  263. >>> aniso8601.get_interval_resolution('2007-03-01T13:00/2008-05-11T15:30') == aniso8601.resolution.IntervalResolution.Minutes
  264. True
  265. >>> aniso8601.get_interval_resolution('2007-03-01T13/2008-05-11T15') == aniso8601.resolution.IntervalResolution.Hours
  266. True
  267. >>> aniso8601.get_interval_resolution('2007-03-01/2008-05-11') == aniso8601.resolution.IntervalResolution.Day
  268. True
  269. >>> aniso8601.get_interval_resolution('2007-03/P1Y') == aniso8601.resolution.IntervalResolution.Month
  270. True
  271. >>> aniso8601.get_interval_resolution('2007/P1Y') == aniso8601.resolution.IntervalResolution.Year
  272. True
  273. And for repeating ISO 8601 interval strings::
  274. >>> aniso8601.get_repeating_interval_resolution('R3/1981-04-05/P1D') == aniso8601.resolution.IntervalResolution.Day
  275. True
  276. >>> aniso8601.get_repeating_interval_resolution('R/PT1H2M/1980-03-05T01:01:00') == aniso8601.resolution.IntervalResolution.Seconds
  277. True
  278. Builders
  279. ========
  280. Builders can be used to change the output format of a parse operation. All parse functions have a :code:`builder` keyword argument which accepts a builder class.
  281. Two builders are included. The :code:`PythonTimeBuilder` (the default) in the :code:`aniso8601.builders.python` module, and the :code:`TupleBuilder` which returns the parse result as a corresponding named tuple and is located in the :code:`aniso8601.builders` module.
  282. Information on writing a builder can be found in `BUILDERS </BUILDERS.rst>`_.
  283. The following builders are available as separate projects:
  284. * `RelativeTimeBuilder <https://bitbucket.org/nielsenb/relativetimebuilder>`_ supports parsing to `datetutil relativedelta types <https://dateutil.readthedocs.io/en/stable/relativedelta.html>`_ for calendar level accuracy
  285. * `AttoTimeBuilder <https://bitbucket.org/nielsenb/attotimebuilder>`_ supports parsing directly to `attotime attodatetime and attotimedelta types <https://bitbucket.org/nielsenb/attotime>`_ which support sub-nanosecond precision
  286. * `NumPyTimeBuilder <https://bitbucket.org/nielsenb/numpytimebuilder>`_ supports parsing directly to `NumPy datetime64 and timedelta64 types <https://docs.scipy.org/doc/numpy/reference/arrays.datetime.html>`_
  287. TupleBuilder
  288. ------------
  289. The :code:`TupleBuilder` returns parse results as `named tuples <https://docs.python.org/3/library/collections.html#collections.namedtuple>`_. It is located in the :code:`aniso8601.builders` module.
  290. Datetimes
  291. ^^^^^^^^^
  292. Parsing a datetime returns a :code:`DatetimeTuple` containing :code:`Date` and :code:`Time` tuples . The date tuple contains the following parse components: :code:`YYYY`, :code:`MM`, :code:`DD`, :code:`Www`, :code:`D`, :code:`DDD`. The time tuple contains the following parse components :code:`hh`, :code:`mm`, :code:`ss`, :code:`tz`, where :code:`tz` itself is a tuple with the following components :code:`negative`, :code:`Z`, :code:`hh`, :code:`mm`, :code:`name` with :code:`negative` and :code:`Z` being booleans::
  293. >>> import aniso8601
  294. >>> from aniso8601.builders import TupleBuilder
  295. >>> aniso8601.parse_datetime('1977-06-10T12:00:00', builder=TupleBuilder)
  296. Datetime(date=Date(YYYY='1977', MM='06', DD='10', Www=None, D=None, DDD=None), time=Time(hh='12', mm='00', ss='00', tz=None))
  297. >>> aniso8601.parse_datetime('1979-06-05T08:00:00-08:00', builder=TupleBuilder)
  298. Datetime(date=Date(YYYY='1979', MM='06', DD='05', Www=None, D=None, DDD=None), time=Time(hh='08', mm='00', ss='00', tz=Timezone(negative=True, Z=None, hh='08', mm='00', name='-08:00')))
  299. Dates
  300. ^^^^^
  301. Parsing a date returns a :code:`DateTuple` containing the following parse components: :code:`YYYY`, :code:`MM`, :code:`DD`, :code:`Www`, :code:`D`, :code:`DDD`::
  302. >>> import aniso8601
  303. >>> from aniso8601.builders import TupleBuilder
  304. >>> aniso8601.parse_date('1984-04-23', builder=TupleBuilder)
  305. Date(YYYY='1984', MM='04', DD='23', Www=None, D=None, DDD=None)
  306. >>> aniso8601.parse_date('1986-W38-1', builder=TupleBuilder)
  307. Date(YYYY='1986', MM=None, DD=None, Www='38', D='1', DDD=None)
  308. >>> aniso8601.parse_date('1988-132', builder=TupleBuilder)
  309. Date(YYYY='1988', MM=None, DD=None, Www=None, D=None, DDD='132')
  310. Times
  311. ^^^^^
  312. Parsing a time returns a :code:`TimeTuple` containing following parse components: :code:`hh`, :code:`mm`, :code:`ss`, :code:`tz`, where :code:`tz` is a :code:`TimezoneTuple` with the following components :code:`negative`, :code:`Z`, :code:`hh`, :code:`mm`, :code:`name`, with :code:`negative` and :code:`Z` being booleans::
  313. >>> import aniso8601
  314. >>> from aniso8601.builders import TupleBuilder
  315. >>> aniso8601.parse_time('11:31:14', builder=TupleBuilder)
  316. Time(hh='11', mm='31', ss='14', tz=None)
  317. >>> aniso8601.parse_time('171819Z', builder=TupleBuilder)
  318. Time(hh='17', mm='18', ss='19', tz=Timezone(negative=False, Z=True, hh=None, mm=None, name='Z'))
  319. >>> aniso8601.parse_time('17:18:19-02:30', builder=TupleBuilder)
  320. Time(hh='17', mm='18', ss='19', tz=Timezone(negative=True, Z=None, hh='02', mm='30', name='-02:30'))
  321. Durations
  322. ^^^^^^^^^
  323. Parsing a duration returns a :code:`DurationTuple` containing the following parse components: :code:`PnY`, :code:`PnM`, :code:`PnW`, :code:`PnD`, :code:`TnH`, :code:`TnM`, :code:`TnS`::
  324. >>> import aniso8601
  325. >>> from aniso8601.builders import TupleBuilder
  326. >>> aniso8601.parse_duration('P1Y2M3DT4H54M6S', builder=TupleBuilder)
  327. Duration(PnY='1', PnM='2', PnW=None, PnD='3', TnH='4', TnM='54', TnS='6')
  328. >>> aniso8601.parse_duration('P7W', builder=TupleBuilder)
  329. Duration(PnY=None, PnM=None, PnW='7', PnD=None, TnH=None, TnM=None, TnS=None)
  330. Intervals
  331. ^^^^^^^^^
  332. Parsing an interval returns an :code:`IntervalTuple` containing the following parse components: :code:`start`, :code:`end`, :code:`duration`, :code:`start` and :code:`end` may both be datetime or date tuples, :code:`duration` is a duration tuple::
  333. >>> import aniso8601
  334. >>> from aniso8601.builders import TupleBuilder
  335. >>> aniso8601.parse_interval('2007-03-01T13:00:00/2008-05-11T15:30:00', builder=TupleBuilder)
  336. Interval(start=Datetime(date=Date(YYYY='2007', MM='03', DD='01', Www=None, D=None, DDD=None), time=Time(hh='13', mm='00', ss='00', tz=None)), end=Datetime(date=Date(YYYY='2008', MM='05', DD='11', Www=None, D=None, DDD=None), time=Time(hh='15', mm='30', ss='00', tz=None)), duration=None)
  337. >>> aniso8601.parse_interval('2007-03-01T13:00:00Z/P1Y2M10DT2H30M', builder=TupleBuilder)
  338. Interval(start=Datetime(date=Date(YYYY='2007', MM='03', DD='01', Www=None, D=None, DDD=None), time=Time(hh='13', mm='00', ss='00', tz=Timezone(negative=False, Z=True, hh=None, mm=None, name='Z'))), end=None, duration=Duration(PnY='1', PnM='2', PnW=None, PnD='10', TnH='2', TnM='30', TnS=None))
  339. >>> aniso8601.parse_interval('P1M/1981-04-05', builder=TupleBuilder)
  340. Interval(start=None, end=Date(YYYY='1981', MM='04', DD='05', Www=None, D=None, DDD=None), duration=Duration(PnY=None, PnM='1', PnW=None, PnD=None, TnH=None, TnM=None, TnS=None))
  341. A repeating interval returns a :code:`RepeatingIntervalTuple` containing the following parse components: :code:`R`, :code:`Rnn`, :code:`interval`, where :code:`R` is a boolean, :code:`True` for an unbounded interval, :code:`False` otherwise.::
  342. >>> aniso8601.parse_repeating_interval('R3/1981-04-05/P1D', builder=TupleBuilder)
  343. RepeatingInterval(R=False, Rnn='3', interval=Interval(start=Date(YYYY='1981', MM='04', DD='05', Www=None, D=None, DDD=None), end=None, duration=Duration(PnY=None, PnM=None, PnW=None, PnD='1', TnH=None, TnM=None, TnS=None)))
  344. >>> aniso8601.parse_repeating_interval('R/PT1H2M/1980-03-05T01:01:00', builder=TupleBuilder)
  345. RepeatingInterval(R=True, Rnn=None, interval=Interval(start=None, end=Datetime(date=Date(YYYY='1980', MM='03', DD='05', Www=None, D=None, DDD=None), time=Time(hh='01', mm='01', ss='00', tz=None)), duration=Duration(PnY=None, PnM=None, PnW=None, PnD=None, TnH='1', TnM='2', TnS=None)))
  346. Development
  347. ===========
  348. Setup
  349. -----
  350. It is recommended to develop using a `virtualenv <https://virtualenv.pypa.io/en/stable/>`_.
  351. Inside a virtualenv, development dependencies can be installed automatically::
  352. $ pip install -e .[dev]
  353. `pre-commit <https://pre-commit.com/>`_ is used for managing pre-commit hooks::
  354. $ pre-commit install
  355. To run the pre-commit hooks manually::
  356. $ pre-commit run --all-files
  357. Tests
  358. -----
  359. Tests can be run using the `unittest testing framework <https://docs.python.org/3/library/unittest.html>`_::
  360. $ python -m unittest discover aniso8601
  361. Contributing
  362. ============
  363. aniso8601 is an open source project hosted on `Bitbucket <https://bitbucket.org/nielsenb/aniso8601>`_.
  364. Any and all bugs are welcome on our `issue tracker <https://bitbucket.org/nielsenb/aniso8601/issues>`_.
  365. Of particular interest are valid ISO 8601 strings that don't parse, or invalid ones that do. At a minimum,
  366. bug reports should include an example of the misbehaving string, as well as the expected result. Of course
  367. patches containing unit tests (or fixed bugs) are welcome!
  368. References
  369. ==========
  370. * `ISO 8601:2004(E) <http://dotat.at/tmp/ISO_8601-2004_E.pdf>`_ (Caution, PDF link)
  371. * `Wikipedia article on ISO 8601 <http://en.wikipedia.org/wiki/Iso8601>`_
  372. * `Discussion on alternative ISO 8601 parsers for Python <https://groups.google.com/forum/#!topic/comp.lang.python/Q2w4R89Nq1w>`_