fix: make sure that intervals with days and monts have the same PostgreSQL epoch
While fixing #1071 I noticed that Postgres returns an approximation of
leap years in intervals with specified months and years. More precisely:
- Postgres internal representation keeps separate (micros, days, months)
(as can be seen in the binary adapter).
- Years are converted to months. When pressed for an equivalence with
days, this shows with:
=# select '1 year'::interval = '360 days'::interval;
?column?
----------
t
- When converting the interval to seconds, Postgres adds 1/4 of a day
every 12 months (rounding to an integer number of years towards 0).
=# select extract('epoch' from '23 months'::interval) / 60. / 60 / 24 - (365 + 11 * 30);
?column?
--------------------
0.
2500000000000000
(1 row)
=# select extract('epoch' from '24 months'::interval) / 60. / 60 / 24 - (2 * 365);
?column?
--------------------
0.
5000000000000000
(1 row)
This MR implements a conversion from Postgres interval to Python
following the same rule. As a consequence, the `extract('epoch' from
interval)` function now returns the same number of seconds returned by
the `datetime.timedelta.total_seconds()` of the value returned. The
difference though is that the hours shows in the seconds:
>>> conn.execute("select '1 year'::interval").fetchone()[0]
datetime.timedelta(days=365, seconds=21600)
>>> conn.execute("select '4 year'::interval").fetchone()[0].days, 365 * 4
(1461, 1460)
This changeset only changes the Python implementation, not the C one.