Prior art#
The packages that already store partial dates in Django, why none of them is used, and what this package must not repeat. The storage decision itself is ADR 0001.
Existing packages#
Package |
Last release |
Storage |
Why not use it |
|---|---|---|---|
January 2022 |
A |
Unmaintained: four open issues have had no reply for years. Carries the defects listed below. |
|
February 2020 |
The same as django-partial-date, of which it is a fork |
Unmaintained. |
|
September 2026 |
The EDTF string, plus four float columns the model must declare for filtering and sorting |
Healthy and complete, but its Django field needs four extra columns on every model, and its documentation warns that the float conversions can be inaccurate. It is the reference if uncertain or approximate dates are ever in scope. |
What overlaps with python-edtf, and why this package exists anyway#
python-edtf covers every form this package stores, and far more. The overlap is real. This package exists because its users need three forms, not the whole of EDTF, and because they need them in a single database column with no companion fields to declare. A field that adds hidden columns, or asks every model to declare four more, is more machinery than the problem needs.
Defects in django-partial-date#
Every one of these is a defect this package must not repeat.
Comparisons across precisions are wrong.
__ge__isself.date >= other.date and self.precision >= other.precision, so1990-06is not “greater than or equal to”1991. There is no__lt__or__le__.Values are unhashable. The class defines
__eq__without__hash__, so a value cannot go in a set or be a dictionary key.The precision setter does nothing. It calls
date.replace(day=1)and discards the result, so a value built from 17 May 1990 at year precision still holds 17 May.Serialisation breaks on empty values. The field has no
value_to_string, sodumpdataand django-reversion cannot handle a blank one.It depends on
six, a Python 2 compatibility library.It invents a day.
.dateon a year-precision value returns 1 January, which callers cannot tell from a recorded 1 January.Its database lookups depend on the time zone. The column is a timestamp. With
USE_TZ, the__year,__monthand__datelookups convert to the current time zone first, so on a site west of UTC a value stored as 1990 matches__year=1989.
Storage options considered#
Option |
Outcome |
|---|---|
A timestamp with the precision in its seconds, as django-partial-date does |
Rejected. It stores a day and a month nobody recorded, and brings the time zone into date lookups. |
A date column and a precision column |
Rejected. Django has no field spanning two columns, so it needs a hidden companion field. |
A start date and an end date, or a PostgreSQL |
Rejected. It presents an uncertain date as a certain interval, and a |
The ISO 8601 string in one text column |
Chosen. ADR 0001 records why. |