age
wird durch das timestamptz_age
berechnet Funktion in src/backend/utils/adt/timestamp.c
. Der Kommentar sagt:
/* timestamptz_age()
* Calculate time difference while retaining year/month fields.
* Note that this does not result in an accurate absolute time span
* since year and month are out of context once the arithmetic
* is done.
*/
Der Code wandelt zuerst die Argumente in struct pg_tm
um Variablen tm1
und tm2
(struct pg_tm
ähnelt dem struct tm
der C-Bibliothek , hat aber zusätzliche Zeitzonenfelder) und berechnet dann die Differenz tm
pro Feld.
Im Fall von age('2018-07-01','2018-05-20')
, würden die relevanten Felder dieses Unterschieds wie folgt aussehen:
tm_mday = -19
tm_mon = 2
tm_year = 0
Jetzt werden negative Felder angepasst. für tm_mday
, sieht der Code so aus:
while (tm->tm_mday < 0)
{
if (dt1 < dt2)
{
tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
tm->tm_mon--;
}
else
{
tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
tm->tm_mon--;
}
}
Seit dt1 > dt2
, das else
Verzweigung wird genommen, und der Code addiert die Anzahl der Tage im Mai (31) und reduziert den Monat um 1 und endet mit
tm_mday = 12
tm_mon = 1
tm_year = 0
Das ist das Ergebnis, das Sie erhalten.
Nun scheint es auf den ersten Blick, dass tm2->tm_mon
ist nicht der richtige Monat zu wählen, und es wäre besser gewesen, den vorherigen Monat des linken Arguments zu nehmen:
day_tab[isleap(tm1->tm_year)][(tm1->tm_mon + 10) % 12]
Aber ich kann nicht sagen, ob diese Wahl in allen Fällen besser wäre, und in jedem Fall entschädigt der Kommentar die Funktion, also würde ich zögern, es einen Fehler zu nennen.
Vielleicht möchten Sie es mit der Hacker-Mailingliste aufnehmen.