ISO 8601 date/time parser

Overview

ISO 8601 date/time parser

Travis-CI Coveralls Latest Version License

This module implements ISO 8601 date, time and duration parsing. The implementation follows ISO8601:2004 standard, and implements only date/time representations mentioned in the standard. If something is not mentioned there, then it is treated as non existent, and not as an allowed option.

For instance, ISO8601:2004 never mentions 2 digit years. So, it is not intended by this module to support 2 digit years. (while it may still be valid as ISO date, because it is not explicitly forbidden.) Another example is, when no time zone information is given for a time, then it should be interpreted as local time, and not UTC.

As this module maps ISO 8601 dates/times to standard Python data types, like date, time, datetime and timedelta, it is not possible to convert all possible ISO 8601 dates/times. For instance, dates before 0001-01-01 are not allowed by the Python date and datetime classes. Additionally fractional seconds are limited to microseconds. That means if the parser finds for instance nanoseconds it will round it to microseconds.

Documentation

Currently there are four parsing methods available.
  • parse_time:
    parses an ISO 8601 time string into a time object
  • parse_date:
    parses an ISO 8601 date string into a date object
  • parse_datetime:
    parses an ISO 8601 date-time string into a datetime object
  • parse_duration:
    parses an ISO 8601 duration string into a timedelta or Duration object.
  • parse_tzinfo:
    parses the time zone info part of an ISO 8601 string into a tzinfo object.

As ISO 8601 allows to define durations in years and months, and timedelta does not handle years and months, this module provides a Duration class, which can be used almost like a timedelta object (with some limitations). However, a Duration object can be converted into a timedelta object.

There are also ISO formatting methods for all supported data types. Each xxx_isoformat method accepts a format parameter. The default format is always the ISO 8601 expanded format. This is the same format used by datetime.isoformat:

  • time_isoformat:
    Intended to create ISO time strings with default format hh:mm:ssZ.
  • date_isoformat:
    Intended to create ISO date strings with default format yyyy-mm-dd.
  • datetime_isoformat:
    Intended to create ISO date-time strings with default format yyyy-mm-ddThh:mm:ssZ.
  • duration_isoformat:
    Intended to create ISO duration strings with default format PnnYnnMnnDTnnHnnMnnS.
  • tz_isoformat:
    Intended to create ISO time zone strings with default format hh:mm.
  • strftime:
    A re-implementation mostly compatible with Python's strftime, but supports only those format strings, which can also be used for dates prior 1900. This method also understands how to format datetime and Duration instances.

Installation:

This module can easily be installed with Python standard installation methods.

Either use python setup.py install or in case you have setuptools or distribute available, you can also use easy_install.

Limitations:

  • The parser accepts several date/time representation which should be invalid according to ISO 8601 standard.
    1. for date and time together, this parser accepts a mixture of basic and extended format. e.g. the date could be in basic format, while the time is accepted in extended format. It also allows short dates and times in date-time strings.
    2. For incomplete dates, the first day is chosen. e.g. 19th century results in a date of 1901-01-01.
    3. negative Duration and timedelta value are not fully supported yet.

Further information:

The doc strings and unit tests should provide rather detailed information about the methods and their limitations.

The source release provides a setup.py script, which can be used to run the unit tests included.

Source code is available at http://github.com/gweis/isodate.

Comments
  • isodate.parse_datetime incorrectly handles Years, Months and Weeks

    isodate.parse_datetime incorrectly handles Years, Months and Weeks

    https://en.wikipedia.org/wiki/ISO_8601#Durations

    See the following snippet:

    >>> s = "P12YT0H0M"
    >>> str(isodate.parse_duration(s))
    '12 years, 0:00:00'
    >>> isodate.parse_duration(s).total_seconds()
    0.0
    

    The library incorrectly places the larger increments in the object, as can be seen here:

    >>> isodate.parse_duration(s)
    isodate.duration.Duration(0, 0, 0, years=12, months=0)
    

    While in code here: https://github.com/gweis/isodate/blob/master/src/isodate/isoduration.py#L92 it is actually clear that the author chose to output another other format when a year or months is sent, but I argue this behaviour is wrong.

    • When the input (you never know!) changes the output format suddenly changes; Surprise!! ;-(
    • This change of output format is hidden, because .total_seconds() still works fine, but the conversion is wrong!!
    • There is no apparent benefit of keeping the Duration type. You could always convert a timedelta object back to something pretty if you want.

    TL;DR I suggest always converting to timedelta.

    opened by dhrp 9
  • Drop support for EOL Python <= 3.6

    Drop support for EOL Python <= 3.6

    Also move testing from Travis CI to GitHub Actions

    • also allows testing on macOS and Windows
    • 20 parallel jobs instead of 4
    • Travis CI has an uncertain OSS future
    • For example: https://github.com/hugovk/isodate/actions/runs/775454949

    Move coverage from Coveralls to Codecov

    • For example: https://app.codecov.io/gh/hugovk/isodate/

    Run Flake8 via pre-commit

    • Pins versions
    • Makes it easy to run on CI and as optional pre-commit hook
    • Add some other handy pre-commit fixers/linters too

    Here's the pip installs for isodate from PyPI for March 2021, showing low numbers for EOL versions:

    | category | percent | downloads | |----------|--------:|-----------:| | 3.7 | 51.39% | 16,518,933 | | 3.6 | 25.40% | 8,165,006 | | 3.8 | 10.28% | 3,305,128 | | 3.5 | 4.76% | 1,529,899 | | 2.7 | 3.16% | 1,016,819 | | null | 3.06% | 982,390 | | 3.9 | 1.92% | 617,791 | | 3.4 | 0.03% | 10,536 | | 3.10 | 0.00% | 540 | | 3.3 | 0.00% | 15 | | 2.6 | 0.00% | 13 | | Total | | 32,147,070 |

    Date range: 2021-03-01 - 2021-03-31

    Source: pip install -U pypistats && pypistats python_minor isodate --last-month

    opened by hugovk 7
  • Add type hints and pre-commit hooks (black+isort+mypy)

    Add type hints and pre-commit hooks (black+isort+mypy)

    Closes: #71, Ref: https://github.com/gweis/isodate/pull/66#issuecomment-992006703


    $ pre-commit run --all
    pyupgrade................................................................Passed
    flake8...................................................................Passed
    check blanket noqa.......................................................Passed
    Check for merge conflicts................................................Passed
    Check Yaml...............................................................Passed
    Fix End of Files.........................................................Passed
    Trim Trailing Whitespace.................................................Passed
    black....................................................................Passed
    isort....................................................................Passed
    mypy.....................................................................Passed
    
    opened by eggplants 6
  • 0.6.0: pytest warnings

    0.6.0: pytest warnings

    + PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-isodate-0.6.0-8.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-isodate-0.6.0-8.fc35.x86_64/usr/lib/python3.8/site-packages
    + /usr/bin/python3 -Bm pytest -ra
    =========================================================================== test session starts ============================================================================
    platform linux -- Python 3.8.9, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
    rootdir: /home/tkloczko/rpmbuild/BUILD/isodate-0.6.0
    plugins: forked-1.3.0, shutil-1.7.0, virtualenv-1.7.0, asyncio-0.14.0, expect-1.1.0, cov-2.11.1, mock-3.5.1, httpbin-1.0.0, xdist-2.2.1, flake8-1.0.7, timeout-1.4.2, betamax-0.8.1, pyfakefs-4.4.0, freezegun-0.4.2, flaky-3.7.0, cases-3.4.6, hypothesis-6.10.0
    collected 18 items
    
    src/isodate/tests/test_date.py .                                                                                                                                     [  5%]
    src/isodate/tests/test_datetime.py .                                                                                                                                 [ 11%]
    src/isodate/tests/test_duration.py ..........                                                                                                                        [ 66%]
    src/isodate/tests/test_pickle.py ....                                                                                                                                [ 88%]
    src/isodate/tests/test_strf.py .                                                                                                                                     [ 94%]
    src/isodate/tests/test_time.py .                                                                                                                                     [100%]
    
    ============================================================================= warnings summary =============================================================================
    src/isodate/tests/test_duration.py: 18 warnings
      /home/tkloczko/rpmbuild/BUILD/isodate-0.6.0/src/isodate/duration.py:183: DeprecationWarning: an integer is required (got type decimal.Decimal).  Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
        newdt = other.replace(year=newyear, month=newmonth, day=newday)
    
    -- Docs: https://docs.pytest.org/en/stable/warnings.html
    ===================================================================== 18 passed, 18 warnings in 0.12s ======================================================================
    
    opened by kloczek 6
  • Fix for Python 3.10 (released 2021-10-04)

    Fix for Python 3.10 (released 2021-10-04)

    Fixes https://github.com/gweis/isodate/issues/58. Fixes https://github.com/gweis/isodate/issues/67.

    Python 3.10 is due out on 2021-10-04, three weeks from now.

    https://discuss.python.org/t/python-3-10-0rc2-is-now-available/10496?u=hugovk

    This deprecation warning was added in Python 3.8:

    DeprecationWarning: an integer is required (got type decimal.Decimal). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.

    For example:

    Python 3.8.6 (v3.8.6:db455296be, Sep 23 2020, 13:31:39)
    [Clang 6.0 (clang-600.0.57)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import datetime as dt
    >>> from isodate import Duration
    >>> dt.date(2000, 3, 30) + Duration(days=1)
    /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/isodate/duration.py:183: DeprecationWarning: an integer is required (got type decimal.Decimal).  Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
      newdt = other.replace(year=newyear, month=newmonth, day=newday)
    /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/isodate/duration.py:183: DeprecationWarning: an integer is required (got type decimal.Decimal).  Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
      newdt = other.replace(year=newyear, month=newmonth, day=newday)
    datetime.date(2000, 3, 31)
    >>>
    

    https://bugs.python.org/issue36048

    In Python 3.10 it is now an error:

    TypeError: 'decimal.Decimal' object cannot be interpreted as an integer

    For example:

    Python 3.10.0rc2+ (heads/3.10:a272ffe, Sep  8 2021, 11:20:24) [Clang 10.0.1 (clang-1001.0.46.4)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import datetime as dt
    >>> from isodate import Duration
    >>> dt.date(2000, 3, 30) + Duration(days=1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Users/hugo/.pyenv/versions/3.10-dev/lib/python3.10/site-packages/isodate/duration.py", line 183, in __add__
        newdt = other.replace(year=newyear, month=newmonth, day=newday)
    TypeError: 'decimal.Decimal' object cannot be interpreted as an integer
    >>>
    

    https://bugs.python.org/issue37999

    Failing build without fix:

    • https://github.com/hugovk/isodate/runs/3584919810?check_suite_focus=true

    Passing build with fix:

    • https://github.com/hugovk/isodate/runs/3585342875?check_suite_focus=true

    isodate is downloaded from PyPI 33 million times a month, the 52nd most popular package (https://hugovk.github.io/top-pypi-packages/), therefore I recommend making a release before 2021-10-04.


    This PR also switches from Travis CI to GitHub Actions and Coveralls to Codecov, taken from https://github.com/gweis/isodate/pull/66, because testing on Travis CI is more difficult now. It only adds testing for supported Python versions. Let me know if this commit should be dropped, but I'd recommend merging #66 as well.

    opened by hugovk 5
  • Duration: support addition and subtraction with arrow objects

    Duration: support addition and subtraction with arrow objects

    This will allow isodate to support addition and substraction with arrow objects.

    Currently, the __radd__ and __rsub__ methods are pending on crsmithdev/arrow#344, as arrow currently raises TypeError instead of returning NotImplemented (which results into python not looking at isodate's methods for that).

    isodate suffers from the same issue (rasing TypeError instead of returning NotImplemented). This however won't affect the behaviour with arrow objects, so I'll address this in another PR.

    opened by flokli 5
  • Rounding of seconds resulting in 60 breaks parse_time.  (...:59.9999999)

    Rounding of seconds resulting in 60 breaks parse_time. (...:59.9999999)

    Rounding of fractional seconds breaks when it rounds to 60. (Presumably true for other fractions)

    isodate.parse('9999-12-31T23.59.59.9999999') <- DateTime.Max from MS .NET

    Example: Python 3.7.3 (default, Jan 22 2021, 20:04:44)

    >>> import isodate
    >>> isodate.parse_datetime('2021-11-12T13:48:59.9999999')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "python3.7/site-packages/isodate/isodatetime.py", line 56, in parse_datetime
        tmptime = parse_time(timestring)
      File "python3.7/site-packages/isodate/isotime.py", line 134, in parse_time
        tzinfo)
    ValueError: second must be in 0..59
    

    Verison:

    $ pip show isodate
    Name: isodate
    Version: 0.6.0
    <snip>
    
    opened by olekang 4
  • Make parse_datetime raise ISO8601Error if no 'T'

    Make parse_datetime raise ISO8601Error if no 'T'

    • Make parse_datetime raise ISO8601Error if time designator 'T' is missing as before it would raise a ValueError that was hard to interpret.
    • Alter test_parse for test_datetime to check that bad inputs raise an ISO8601 error. The other tests did this, but test_datetime didn't.
    • Add test case where the 'T' time designator is missing from input datetime strings.
    opened by tofu-rocketry 4
  • Python 3.8 compatibility

    Python 3.8 compatibility

    Using python3.8, with -Werror

    >>> import datetime
    >>> import isodate
    >>> datetime.datetime.now() + isodate.parse_duration("P5Y")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "[...]/.tox/py38-std-sha256/lib/python3.8/site-packages/isodate/duration.py", line 183, in __add__
        newdt = other.replace(year=newyear, month=newmonth, day=newday)
    DeprecationWarning: an integer is required (got type decimal.Decimal).  Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
    

    It looks like casting to int explicitly would solve the warning, something like:

    ewdt = other.replace(year=int(newyear), month=int(newmonth), day=newday)
    

    According to the release notes: https://docs.python.org/3.8/whatsnew/3.8.html

    Many builtin and extension functions that take integer arguments will now emit a deprecation warning for Decimals, Fractions and any other objects that can be converted to integers only with a loss (e.g. that have the __int__() method but do not have the __index__() method). In future version they will be errors. (Contributed by Serhiy Storchaka in bpo-36048.)

    opened by JoseKilo 3
  • License fix and move

    License fix and move

    Changes:

    1. move license to Project's root
    2. add a missing sentence from 2-clause license 3-clause license ("BSD License 2.0", "Revised BSD License", "New BSD License", or "Modified BSD License"): (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    Issues:

    1. https://github.com/gweis/isodate/issues/47
    opened by mangin 3
  • missing LICENSE file

    missing LICENSE file

    Please provide a proper LICENSE | COPYING | etc file, so it's clear under which license this project is.

    (e.g: it mentions it's BSD, but there are more than 1 BSD license: BSD-2-Clause, BSD-3-Clause, BSD-4-Clause, and many more as specified in SPDX).

    Adding a proper file, would allow packagers to integrate this project into linux-distros easier, so please do consider adding this and pushing a release with it.

    opened by mrkz 3
  • Missing support for time intervals

    Missing support for time intervals

    I'm working on my calendar-cli.

    A calendar event typically spans a time interval, and ISO 8601 does specify three standard ways of writing a time interval (according to wikipedia. I've sort of invented my own way of writing time intervals, but I thought it would be a good idea to support the standard as well. Actually doing the parsing of ISO time intervals is however out of the scope of calendar-cli, and I was expecting someone else had already written the code for it. Using a popular search engine, I found the isodate library - but apparently, it does not support parsing time intervals.

    Is it on the roadmap? Eventually, if I would do the work myself, would someone assist me with design review, code review and merging? (I can't give any commitments on time frame for this one, right now I have lots of available time by the computer, but it may be years until next time).

    opened by tobixen 0
  • Why are tests included in the distrubuted package?

    Why are tests included in the distrubuted package?

    Is that intentional or just a blunder? Tests should just be available to developers and run by the pipeline, I see no reason to distribute them to users. Other projects do not distribute them.

    opened by harvastum 0
  • Avoid formatting absolute durations as nominal durations

    Avoid formatting absolute durations as nominal durations

    From https://github.com/gweis/isodate/pull/64:

    A datetime.timedelta(days=1) is defined as exactly 24 hours, whereas ISO 8601 defines "P1D" as a calendar day, whose exact duration depends on its positioning in a calendar. For example, for the Europe/Amsterdam timezone (which happens to be my timezone), daylight saving time will start on March 28th 2021, which means March 28th in my calendar has 23 hours.

    from datetime import timedelta
    from isodate import duration_isoformat
    
    print(duration_isoformat(timedelta(hours=24)))  # Outcome: P1D Expected: PT24H
    

    If you'd like, I could try my hand at a PR, starting with introducing a new self.days attribute to express days as a nominal duration in the Duration class. I believe this issue also touches parse_duration.

    Please let me know if this makes sense.

    opened by Flix6x 0
  • parse_date do not raise Exception on incorrect string (GPS format)

    parse_date do not raise Exception on incorrect string (GPS format)

    Hello,

    I found that on some value of string , parse_date do not raise an Exception where it should. As i am using it in json hook it is problematique.

    Example:

    isodate.parse_date("16.263772,-61.2329") datetime.date(1601, 1, 1)

    isodate.parse_date("100.263772,-61.2329") datetime.date(1001, 1, 1)

    it does the same for any two (or more) digits number in before "."

    Whereas date.fromisoformat do raise an error on those values.

    I don't know if you will considere that as an issue.

    Regards.

    opened by maximeLeurent 1
Owner
null
Parse human-readable date/time strings

parsedatetime Parse human-readable date/time strings. Python 2.6 or greater is required for parsedatetime version 1.0 or greater. While we still test

Mike Taylor 651 Dec 23, 2022
python parser for human readable dates

Python parser for human readable dates Key Features • How To Use • Installation • Common use cases • You may also like... • License Key Features Suppo

Scrapinghub 2.2k Jan 8, 2023
A datetime parser in Python by Ari24-cb24 and NekoFantic

datetimeparser A datetime parser in Python by Ari24-cb24 and NekoFantic V 1.0 Erinnerung für den Parser Auf falsche Eingaben überprüfen Liste an Event

AriDevelopment 13 Dec 30, 2022
UNIX time from NTP or short UtfN is a simple CLI tool to set the time from an NTP-Server.

UNIX ⌚ from NTP UNIX time from NTP or short UtfN is a simple CLI tool to set the time from an NTP-Server. Sets time and date using the date command pr

Alexander 1 Jan 2, 2022
⌚️Internet Time reference and (eventually) converter site, for planning things with your internet friends who aren't (yet) obsessed with Internet Time 😉

Internet-Ti.me Internet Time reference and (eventually) converter site, for planning things with your internet friends who aren't (yet) obsessed with

Jessica Stokes 17 Nov 2, 2022
Delorean: Time Travel Made Easy

Delorean: Time Travel Made Easy Delorean is a library for clearing up the inconvenient truths that arise dealing with datetimes in Python. Understandi

Mahdi Yusuf 1.8k Dec 20, 2022
TimeTagger is a web-based time-tracking solution that can be run locally or on a server

TimeTagger is a web-based time-tracking solution that can be run locally or on a server. In the latter case, you'll want to add authentication, and also be aware of the license restrictions.

Almar Klein 626 Jan 6, 2023
darts is a Python library for easy manipulation and forecasting of time series.

A python library for easy manipulation and forecasting of time series.

Unit8 5.2k Jan 1, 2023
Cross Platform Application for Calculating Render Time

mdsanima-rt-go Cross Platform Application for Calculating Render Time. Testing This is a base application build on Windows Android and Linux. All buil

MDSANIMA DEV 2 Mar 29, 2022
Extract the windows major and minor build numbers from an ISO file, and automatically sort the iso files.

WindowsBuildFromISO Extract the windows major and minor build numbers from an ISO file, and automatically sort the iso files. Features Parse multiple

Podalirius 9 Nov 9, 2022
Scan the MRZ code of a passport and extract the firstname, lastname, passport number, nationality, date of birth, expiration date and personal numer.

PassportScanner Works with 2 and 3 line identity documents. What is this With PassportScanner you can use your camera to scan the MRZ code of a passpo

Edwin Vermeer 441 Dec 24, 2022
This application is the basic of automated online-class-joiner(for YıldızEdu) within the right time. Gets the ZOOM link by scheduled date and time.

This application is the basic of automated online-class-joiner(for YıldızEdu) within the right time. Gets the ZOOM link by scheduled date and time.

215355 1 Dec 16, 2021
Python bindings to the dutch NLP tool Frog (pos tagger, lemmatiser, NER tagger, morphological analysis, shallow parser, dependency parser)

Frog for Python This is a Python binding to the Natural Language Processing suite Frog. Frog is intended for Dutch and performs part-of-speech tagging

Maarten van Gompel 46 Dec 14, 2022
Py-Parser est un parser de code python en python encore en plien dévlopement.

PY - PARSER Py-Parser est un parser de code python en python encore en plien dévlopement. Une fois achevé, il servira a de nombreux projets comme glad

pf4 3 Feb 21, 2022
Lua-parser-lark - An out-of-box Lua parser written in Lark

An out-of-box Lua parser written in Lark Such parser handles a relaxed version o

Taine Zhao 2 Jul 19, 2022
Lol qq parser - A League of Legends parser for QQ data

lol_qq_parser A League of Legends parser for QQ data Sources This package relies

Tolki 3 Jul 13, 2022
Discord bot-CTFD-Thread-Parser - Discord bot CTFD-Thread-Parser

Discord bot CTFD-Thread-Parser Description: This tools is used to create automat

null 15 Mar 22, 2022
Code for Iso-Points: Optimizing Neural Implicit Surfaces with Hybrid Representations

Implementation for Iso-Points (CVPR 2021) Official code for paper Iso-Points: Optimizing Neural Implicit Surfaces with Hybrid Representations paper |

Yifan Wang 66 Nov 8, 2022
An Efficient Implementation of Analytic Mesh Algorithm for 3D Iso-surface Extraction from Neural Networks

AnalyticMesh Analytic Marching is an exact meshing solution from neural networks. Compared to standard methods, it completely avoids geometric and top

Karbo 45 Dec 21, 2022
A wrapper for DVD file structure and ISO files.

vs-parsedvd DVDs were an error. A wrapper for DVD file structure and ISO files. You can find me in the IEW Discord server

null 7 Nov 17, 2022