Skip to main content

library for working with uncertain, fuzzy, or partially unknown dates and date intervals

Project description

undate overview

undate

undate is a python library for working with uncertain or partially known dates.

[!WARNING] This is pre-alpha software and is NOT feature complete! Use with caution. Currently it only supports parsing and formatting dates in ISO8601 format and some portions of EDTF (Extended Date Time Format).

Undate was initially created as part of a DH-Tech hackathon in November 2022.


DOI License Documentation Status unit tests codecov Ruff

All Contributors

Read Contributors for detailed contribution information.

Example Usage

Often humanities and cultural data include imprecise or uncertain temporal information. We want to store that information but also work with it in a structured way, not just treat it as text for display. Different projects may need to work with or convert between different date formats or even different calendars.

An undate.Undate is analogous to python’s builtin datetime.date object, but with support for varying degrees of precision and unknown information. You can initialize an undate with either strings or numbers for whichever parts of the date are known or partially known. An Undate can take an optional label.

from undate.undate import Undate

november7 = Undate(2000, 11, 7)
november = Undate(2000, 11)
year2k = Undate(2000)
november7_some_year = Undate(month=11, day=7)

partially_known_year = Undate("19XX")
partially_known_month = Undate(2022, "1X")

easter1916 = Undate(1916, 4, 23, label="Easter 1916")

You can convert an Undate to string using a date formatter (current default is ISO8601):

>>> [str(d) for d in [november7, november, year2k, november7_some_year]]
['2000-11-07', '2000-11', '2000', '--11-07']

If enough information is known, an Undate object can report on its duration:

>>> december = Undate(2000, 12)
>>> feb_leapyear = Undate(2024, 2)
>>> feb_regularyear = Undate(2023, 2)
>>> for d in [november7, november, december, year2k, november7_some_year, feb_regularyear, feb_leapyear]:
...    print(f"{d}  - duration in days: {d.duration().days}")
...
2000-11-07  - duration in days: 1
2000-11  - duration in days: 30
2000-12  - duration in days: 31
2000  - duration in days: 366
--11-07  - duration in days: 1
2023-02  - duration in days: 28
2024-02  - duration in days: 29

If enough of the date is known and the precision supports it, you can check if one date falls within another date:

>>> november7 = Undate(2000, 11, 7)
>>> november2000 = Undate(2000, 11)
>>> year2k = Undate(2000)
>>> ad100 = Undate(100)
>>> november7 in november
True
>>> november2000 in year2k
True
>>> november7 in year2k
True
>>> november2000 in ad100
False
>>> november7 in ad100
False

For dates that are imprecise or partially known, undate calculates earliest and latest possible dates for comparison purposes so you can sort dates and compare with equals, greater than, and less than. You can also compare with python datetime.date objects.

>>> november7_2020 = Undate(2020, 11, 7)
>>> november_2001 = Undate(2001, 11)
>>> year2k = Undate(2000)
>>> ad100 = Undate(100)
>>> sorted([november7_2020, november_2001, year2k, ad100])
[<Undate 0100>, <Undate 2000>, <Undate 2001-11>, <Undate 2020-11-07>]
>>> november7_2020 > november_2001
True
>>> year2k < ad100
False
>>> from datetime import date
>>> year2k > date(2001, 1, 1)
False

When dates cannot be compared due to ambiguity or precision, comparison methods raise a NotImplementedError.

>>> november_2020 = Undate(2020, 11)
>>> november7_2020 > november_2020
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/rkoeser/workarea/github/undate-python/src/undate/undate.py", line 262, in __gt__
    return not (self < other or self == other)
  File "/Users/rkoeser/workarea/github/undate-python/src/undate/undate.py", line 245, in __lt__
    raise NotImplementedError(
NotImplementedError: Can't compare when one date falls within the other

An UndateInterval is a date range between two Undate objects. Intervals can be open-ended, allow for optional labels, and can calculate duration if enough information is known

>>> from undate.undate import UndateInterval
>>> UndateInterval(Undate(1900), Undate(2000))
<UndateInterval 1900/2000>
>>> UndateInterval(Undate(1900), Undate(2000), label="19th century")
>>> UndateInterval(Undate(1900), Undate(2000), label="19th century").duration().days
36890
<UndateInterval '19th century' (1900/2000)>
>>> UndateInterval(Undate(1900), Undate(2000), label="20th century")
<UndateInterval '20th century' (1900/2000)>
>>> UndateInterval(latest=Undate(2000))  # before 2000
<UndateInterval ../2000>
>>> UndateInterval(Undate(1900))  # after 1900
<UndateInterval 1900/>
>>> UndateInterval(Undate(1900), Undate(2000), label="19th century").duration().days
36890
>>> UndateInterval(Undate(2000, 1, 1), Undate(2000, 1,31)).duration().days
31

You can initialize Undate or UndateInterval objects by parsing a date string with a specific converter, and you can also output an Undate object in those formats. Available converters are "ISO8601" and "EDTF" (but only)

>>> from undate import Undate
>>> Undate.parse("2002", "ISO8601")
<Undate 2002>
>>> Undate.parse("2002-05", "EDTF")
<Undate 2002-05>
>>> Undate.parse("--05-03", "ISO8601")
<Undate --05-03>
>>> Undate.parse("--05-03", "ISO8601").format("EDTF")
'XXXX-05-03'
>>> Undate.parse("1800/1900")
<UndateInterval 1800/1900>

For more examples, refer to the example notebooks included in this repository.

Documentation

Project documentation is available on ReadTheDocs.

For instructions on setting up for local development, see Developer Notes.

License

This software is licensed under the Apache 2.0 License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

undate-0.3.0.tar.gz (27.6 kB view details)

Uploaded Source

Built Distribution

undate-0.3.0-py3-none-any.whl (24.5 kB view details)

Uploaded Python 3

File details

Details for the file undate-0.3.0.tar.gz.

File metadata

  • Download URL: undate-0.3.0.tar.gz
  • Upload date:
  • Size: 27.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for undate-0.3.0.tar.gz
Algorithm Hash digest
SHA256 8e328c7c93f0f0f85c38e76503f27315e44908b5fa9f96239e049c1b38f67b96
MD5 1ca64475588b3840297587df877caa8b
BLAKE2b-256 eaa20b89c80acff3ca21a7ba3fba00bee7b16bd33b9ff0cc6cbf2858d8286c35

See more details on using hashes here.

File details

Details for the file undate-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: undate-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 24.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for undate-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5a4d26f4e24d51e37953f09e6929d3948121b63ad5e48679e25e35a503c26e2c
MD5 c124f0df70a4df1834c85951019d567d
BLAKE2b-256 3977ff1446a50e1ffee95447ee9dfc287f6199e7cd77813f5500b332d095432a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page