Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 67 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,37 @@ portions of EDTF (Extended Date Time Format), and parsing and conversion for dat

Read [Contributors](CONTRIBUTORS.md) for detailed contribution information.

## Installation

*Recommended*: use pip to install the latest published version from PyPI:

```console
pip install undate
```

To install a development version or specific tag or branch, you can install from GitHub.
Use the `@name` notation to specify the branch or tag; e.g., to install development version:

```console
pip install git+https://github.com/dh-tech/undate-python@develop#egg=undate
```

## 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.
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.
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.

```python
from undate.undate import Undate
from undate import Undate

november7 = Undate(2000, 11, 7)
november = Undate(2000, 11)
Expand All @@ -46,12 +69,14 @@ easter1916 = Undate(1916, 4, 23, label="Easter 1916")
```

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

```python
>>> [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:

```python
>>> december = Undate(2000, 12)
>>> feb_leapyear = Undate(2024, 2)
Expand All @@ -68,7 +93,9 @@ If enough information is known, an `Undate` object can report on its duration:
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:
If enough of the date is known and the precision supports it, you can
check if one date falls within another date:

```python
>>> november7 = Undate(2000, 11, 7)
>>> november2000 = Undate(2000, 11)
Expand All @@ -86,7 +113,10 @@ False
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.
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.

```python
>>> november7_2020 = Undate(2020, 11, 7)
Expand All @@ -104,7 +134,8 @@ False
False
```

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

```python
>>> november_2020 = Undate(2020, 11)
Expand All @@ -118,17 +149,22 @@ Traceback (most recent call last):
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
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. `UndateIntervals`
are inclusive (i.e., a closed interval), and include both the earliest
and latest date as part of the range.

```python
>>> from undate.undate import UndateInterval
>>> from 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(Undate(1801), Undate(1900), label="19th century")
>>> UndateInterval(Undate(1801), Undate(1900), label="19th century").duration().days
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at these examples, my first question is are beginning and end values inclusive or exclusive? Looking up the date range for 19th century (which apparently I didn't know 😅), I realize it's inclusive but maybe worth pointing out?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Done!

36524
<UndateInterval '19th century' (1801/1900)>
>>> UndateInterval(Undate(1901), Undate(2000), label="20th century")
<UndateInterval '20th century' (1901/2000)>
>>> UndateInterval(latest=Undate(2000)) # before 2000
<UndateInterval ../2000>
>>> UndateInterval(Undate(1900)) # after 1900
Expand All @@ -139,8 +175,10 @@ An `UndateInterval` is a date range between two `Undate` objects. Intervals can
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.
Currently available converters are "ISO8601" and "EDTF" and supported calendars.
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. Currently available converters
are "ISO8601" and "EDTF" and supported calendars.

```python
>>> from undate import Undate
Expand All @@ -158,9 +196,17 @@ Currently available converters are "ISO8601" and "EDTF" and supported calendars.

### Calendars

All `Undate` objects are calendar aware, and date converters include support for parsing and working with dates from other calendars. The Gregorian calendar is used by default; currently `undate` supports the Islamic Hijri calendar and the Hebrew Anno Mundi calendar based on calendar conversion logic implemented in the [convertdate](https://convertdate.readthedocs.io/en/latest/) package.
All `Undate` objects are calendar aware, and date converters include
support for parsing and working with dates from other calendars. The
Gregorian calendar is used by default; currently `undate` supports the
Islamic Hijri calendar and the Hebrew Anno Mundi calendar based on
calendar conversion logic implemented in the
[convertdate](https://convertdate.readthedocs.io/en/latest/) package.

Dates are stored with the year, month, day and appropriate precision for the original calendar; internally, earliest and latest dates are calculated in Gregorian / Proleptic Gregorian calendar for standardized comparison across dates from different calendars.
Dates are stored with the year, month, day and appropriate precision for
the original calendar; internally, earliest and latest dates are
calculated in Gregorian / Proleptic Gregorian calendar for standardized
comparison across dates from different calendars.

```python
>>> from undate import Undate
Expand All @@ -183,7 +229,9 @@ Dates are stored with the year, month, day and appropriate precision for the ori

* * *

For more examples, refer to the code notebooks included in the [examples](https://github.com/dh-tech/undate-python/tree/main/examples/) in this repository.
For more examples, refer to the code notebooks included in the[examples]
(https://github.com/dh-tech/undate-python/tree/main/examples/) in this
repository.

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion src/undate/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.4.0"
__version__ = "0.5.0.dev0"

from undate.date import DatePrecision
from undate.undate import Undate, Calendar
Expand Down