A small Python package for date handling including support for BC dates and uncertainty.
$ pip install historicaldate
PyPI: https://pypi.org/project/historicaldate/
Documentation: https://historicaldate.readthedocs.io/en/stable/
The package provides a parser for date formats that are often used to indicate uncertain dates, such as
- circa 1989
- between 1920 and 1934
- 2003
- circa 1483 earliest 1483
These string are converted to a HDate() object, which stores the earliest, latest possible and an approximate midpoint date corresponding to the original string. These dates are stored as:
- Ordinals. These correspond to Python datetime ordinals for AD dates, extended backwards to non-positive values for BC dates.
- Python datetime.date, for AD dates only.
The package is intended for dealing with historical events. It does not support time of day, and at present takes a naive approach to the difference between Julian and Gregorian calendars since this is usually what is needed for the expected application areas.
- 25 Dec 1066 (or variants such as 25th Dec 1066 or 25 December 1066 etc.)
- 1066-12-25
Specifying dateformat="dmy" (as a parameter to the HDate constructor ) also allows...
- 25/12/1066
Specifying dateformat="mdy" allows...
- 12/25/1066
- Dec 25, 1066
- 1066-12-25
But does not allow...
- 25/12/1066
- 25 Dec 1066
These are all allowed:
- Dec 1066
- 1066
- 1066-12
- circa 1066
- c. 1066
- between 1066 and 1068
- circa 1483 earliest 1483
A date value of 'ongoing' leads to the earliest and midpoint dates taking values datetime.date.today(), the late date being a few years in the future, with flags set for 'ongoing'
Python dates are used for AD (CE) timeline displays, and 25 Dec 1066 converts to the Python date 1066-12-25.
This gets us into the tricky question of the few days difference between the Julian and Gregorian calendars. The approach here is (at least for the moment) to observe that this difference doesn't have any significant impact on most expected application areas, and so can be ignored.
In effect this package naively assumes that any AD date string passed to HDate is (proleptic) Gregorian, the same assumption that is made by Python's datetime.date. This is 'naive' because the usual convention when quoting historical dates is to use the calendar in operation at the relevant place at the time. So when we say that the coronation of William I of England took place on 25 Dec 1066, that is a Julian date, not a proleptic Gregorian date (which I believe would be 31 Dec 1066).
It's expected this approach will continue to be the default, since to do anything else would make things unnecessarily more complex for most applications. It's possible however that Julian / Gregorian conversion functionality may be added to future versions
(Proleptic Gregorian Calendar: A Gregorian calendar extended backwards in time before the dates, starting in the 16th century AD, that the Gregorian calendar was actually introduced)
Objects of this class have a property pdates, a dictionary encoding the date information.
>>>from historicaldate import hdate
>>>hd1 = hdate.HDate('Dec 1066')
>>>print(hd1.pdates)
{'mid': datetime.date(1066, 12, 15), 'ordinal_mid': 389332, 'slmid': 'm',
'late': datetime.date(1066, 12, 31), 'ordinal_late': 389348, 'sllate': 'm',
'early': datetime.date(1066, 12, 1), 'ordinal_early': 389318, 'slearly': 'm'}
>>>
>>>hd2 = hdate.HDate('Dec 20, 1066', dateformat="mdy")
>>>print(hd2.pdates)
{'mid': datetime.date(1066, 12, 20), 'ordinal_mid': 389337, 'slmid': 'd',
'late': datetime.date(1066, 12, 20), 'ordinal_late': 389337, 'sllate': 'd',
'early': datetime.date(1066, 12, 20), 'ordinal_early': 389337, 'slearly': 'd'}
>>>
>>>hd3 = hdate.HDate('385 BC')
>>> print(hd3.pdates)
{'mid': None, 'ordinal_mid': -140455, 'slmid': 'y',
'late': None, 'ordinal_late': -140256, 'sllate': 'y',
'early': None, 'ordinal_early': -140621, 'slearly': 'y'}
All dates (AD and BC) are given values of ordinal_early, ordinal_mid and ordinal_late. These represent the earliest possible, midpoint and latest possible ordinals (int) corresponding to the date specified.
These are usual Python date ordinals (int) for AD dates as created by datetime.date.toordinal(), extended backwards in time to non-positive numbers for BC dates assuming that 1BC, 5BC etc. are leap years. See above for how the few days difference between the Julian and Gregorian calendars is treated.
AD dates are also given values of early, mid and late, which are the equivalent Python dates (datetime.date objects).
The dictionary members slearly, slmid and sllate indicate the 'specification level' of the corresponding date, and take the following values:
Value | Meaning |
---|---|
'd' | day |
'm' | month |
'y' | year |
'c' | Derived from a 'circa' calculation |
'o' | Derived from an 'ongoing' calculation |
Cleaned up for PyPI release
The package has been trimmed down to date treatment only. The Plotly utilities included in older versions are now at https://github.com/dh3968mlq/hdtimelines
- BC dates are now supported
- Ordinal dates implemented
- dateformat implemented, allowing dates to be formatted as 25/12/1066 or 12/25/1066 or Dec 25, 1066