age
è calcolato dal timestamptz_age
funzione in src/backend/utils/adt/timestamp.c
. Il commento dice:
/* 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.
*/
Il codice prima converte gli argomenti in struct pg_tm
variabili tm1
e tm2
(struct pg_tm
è simile a struct tm
della libreria C , ma ha campi di fuso orario aggiuntivi) e quindi calcola la differenza tm
per campo.
Nel caso di age('2018-07-01','2018-05-20')
, i campi pertinenti di tale differenza sarebbero simili a questo:
tm_mday = -19
tm_mon = 2
tm_year = 0
Ora i campi negativi vengono modificati. per tm_mday
, il codice è simile a questo:
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--;
}
}
Dal momento che dt1 > dt2
, il else
viene preso il ramo e il codice aggiunge il numero di giorni di maggio (31) e riduce il mese di 1, finendo con
tm_mday = 12
tm_mon = 1
tm_year = 0
Questo è il risultato che ottieni.
Ora a prima vista sembra che tm2->tm_mon
non è il mese giusto per scegliere, e sarebbe stato meglio prendere il mese precedente dell'argomento sinistro:
day_tab[isleap(tm1->tm_year)][(tm1->tm_mon + 10) % 12]
Ma non posso dire se quella scelta sarebbe sempre migliore, e comunque il commento indennizza la funzione, quindi esiterei a chiamarlo bug.
Potresti voler occuparti della mailing list degli hacker.