How can I store date and time values with reduced precision in a PostgreSQL type, and have them behave as date and/or time values?
ISO 8601 allows date values with reduced precision. ‘1964’, ‘1964-05’, ‘1964-05-02’ are all valid representations of a value, in increasing precision. The Python ‘datetime’ types also allow values with reduced precision in this way.
PostgreSQL native time types doesn't allow reduced precision
In the native date type, every element of a date must be present or the value is rejected. Setting the elements below the desired precision level to ‘00’ also fails.
=> SELECT CAST('1964-05-02' AS DATE);
date
------------
1964-05-02
(1 row)
=> SELECT CAST('1964-05' AS DATE);
ERROR: invalid input syntax for type date: "1964-05"
LINE 1: SELECT CAST('1964-05' AS DATE);
^
=> SELECT CAST('1964' AS DATE);
ERROR: invalid input syntax for type date: "1964"
LINE 1: SELECT CAST('1964' AS DATE);
^
=> SELECT CAST('1964-00-00' AS DATE);
ERROR: date/time field value out of range: "1964-00-00"
LINE 1: SELECT CAST('1964-00-00' AS DATE);
^
HINT: Perhaps you need a different "datestyle" setting.
Expected behaviour for a reduced-precision date and/or time type
Is there a simple, standard way to support entry of ISO 8601 date values with reduced precision into a PostgreSQL date and/or time type?
Creating a type for this is possible, but I don't know how. Of course, I need the values to be range checked and deal with timezones and compare sensibly with other time values all the other useful things the built-in types do.
What I expect is that, just as the value ‘1964-05-02’ refers to the entire interval between 00:00:00 on that day until 00:00:00 the next day, a reduced-precision value would simply represent a larger interval: ‘1962-05’ refers to the entire interval between 00:00:00 at the beginning of May 1962 until 00:00:00 on the first day of June of 1962.
An example of what I'd like to see:
=> SELECT CAST('1964-05-02 00:00' AS TIMESTAMP) = CAST('1964-05-02 00:00:00' AS TIMESTAMP);
?column?
----------
t
(1 row)
=> SELECT CAST('1964-05' AS TIMESTAMP) = CAST('1964-05-02' AS TIMESTAMP);
?column?
----------
t
(1 row)
Currently the former behaves as above; the latter complains about “invalid input syntax for type timestamp”. To my eye, they're both cases of reduced-precision values behaving sensibly when compared to finer-precision values.
The meaning of 1964-05
in ISO 8601 includes the more-precise values 1964-05-02
and 1964-05-02 18:27
and 1964-05-23
. So those should all compare equal.
true
when the timestamps 'might' be equal (allowing for precision)?1964-05
in ISO 8601 includes the more-precise values1964-05-02
and1964-05-02 18:27
and1964-05-23
. So those should all compare equal.