age
se vypočítá podle timestamptz_age
funkce v src/backend/utils/adt/timestamp.c
. Komentář říká:
/* 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.
*/
Kód nejprve převede argumenty na struct pg_tm
proměnné tm1
a tm2
(struct pg_tm
je podobný struct tm
knihovny C , ale má další pole časového pásma) a poté vypočítá rozdíl tm
na pole.
V případě age('2018-07-01','2018-05-20')
, budou příslušná pole tohoto rozdílu vypadat takto:
tm_mday = -19
tm_mon = 2
tm_year = 0
Nyní jsou záporná pole upravena. pro tm_mday
, kód vypadá takto:
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--;
}
}
Protože dt1 > dt2
, else
větev se vezme a kód přidá počet dní v květnu (31) a zkrátí měsíc o 1, což skončí s
tm_mday = 12
tm_mon = 1
tm_year = 0
To je výsledek, který dostanete.
Nyní se na první pohled zdá, že tm2->tm_mon
není správný měsíc na výběr a bylo by lepší vzít předchozí měsíc argumentu vlevo:
day_tab[isleap(tm1->tm_year)][(tm1->tm_mon + 10) % 12]
Nemohu však říci, zda by tato volba byla ve všech případech lepší, a komentář v každém případě funkci odškodní, takže bych váhal označit to za chybu.
Možná budete chtít pokračovat s mailing listem hackerů.